⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sun4c.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: sun4c.c,v 1.210 2001/11/13 03:27:47 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */#define NR_TASK_BUCKETS 512#include <linux/config.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/bootmem.h>#include <linux/highmem.h>#include <linux/fs.h>#include <linux/seq_file.h>#include <asm/scatterlist.h>#include <asm/page.h>#include <asm/pgalloc.h>#include <asm/pgtable.h>#include <asm/vaddrs.h>#include <asm/idprom.h>#include <asm/machines.h>#include <asm/memreg.h>#include <asm/processor.h>#include <asm/auxio.h>#include <asm/io.h>#include <asm/oplib.h>#include <asm/openprom.h>#include <asm/mmu_context.h>#include <asm/sun4paddr.h>#include <asm/highmem.h>/* Because of our dynamic kernel TLB miss strategy, and how * our DVMA mapping allocation works, you _MUST_: * * 1) Disable interrupts _and_ not touch any dynamic kernel *    memory while messing with kernel MMU state.  By *    dynamic memory I mean any object which is not in *    the kernel image itself or a task_struct (both of *    which are locked into the MMU). * 2) Disable interrupts while messing with user MMU state. */extern int num_segmaps, num_contexts;extern unsigned long page_kernel;#ifdef CONFIG_SUN4#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes#else/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536. * So let's save some cycles and just use that everywhere except for that bootup * sanity check. */#define SUN4C_VAC_SIZE 65536#endif#define SUN4C_KERNEL_BUCKETS 32#ifndef MAX#define MAX(a,b) ((a)<(b)?(b):(a))#endif#ifndef MIN#define MIN(a,b) ((a)<(b)?(a):(b))#endif/* Flushing the cache. */struct sun4c_vac_props sun4c_vacinfo;unsigned long sun4c_kernel_faults;/* Invalidate every sun4c cache line tag. */void sun4c_flush_all(void){	unsigned long begin, end;	if (sun4c_vacinfo.on)		panic("SUN4C: AIEEE, trying to invalidate vac while"                      " it is on.");	/* Clear 'valid' bit in all cache line tags */	begin = AC_CACHETAGS;	end = (AC_CACHETAGS + SUN4C_VAC_SIZE);	while (begin < end) {		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :				     "r" (begin), "i" (ASI_CONTROL));		begin += sun4c_vacinfo.linesize;	}}static __inline__ void sun4c_flush_context_hw(void){	unsigned long end = SUN4C_VAC_SIZE;	__asm__ __volatile__(		"1:	addcc	%0, -4096, %0\n\t"		"	bne	1b\n\t"		"	 sta	%%g0, [%0] %2"	: "=&r" (end)	: "0" (end), "i" (ASI_HWFLUSHCONTEXT)	: "cc");}/* Must be called minimally with IRQs disabled. */static void sun4c_flush_segment_hw(unsigned long addr){	if (sun4c_get_segmap(addr) != invalid_segment) {		unsigned long vac_size = SUN4C_VAC_SIZE;		__asm__ __volatile__(			"1:	addcc	%0, -4096, %0\n\t"			"	bne	1b\n\t"			"	 sta	%%g0, [%2 + %0] %3"			: "=&r" (vac_size)			: "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG)			: "cc");	}}/* Must be called minimally with interrupts disabled. */static __inline__ void sun4c_flush_page_hw(unsigned long addr){	addr &= PAGE_MASK;	if ((int)sun4c_get_pte(addr) < 0)		__asm__ __volatile__("sta %%g0, [%0] %1"				     : : "r" (addr), "i" (ASI_HWFLUSHPAGE));}/* Don't inline the software version as it eats too many cache lines if expanded. */static void sun4c_flush_context_sw(void){	unsigned long nbytes = SUN4C_VAC_SIZE;	unsigned long lsize = sun4c_vacinfo.linesize;	__asm__ __volatile__(	"add	%2, %2, %%g1\n\t"	"add	%2, %%g1, %%g2\n\t"	"add	%2, %%g2, %%g3\n\t"	"add	%2, %%g3, %%g4\n\t"	"add	%2, %%g4, %%g5\n\t"	"add	%2, %%g5, %%o4\n\t"	"add	%2, %%o4, %%o5\n"	"1:\n\t"	"subcc	%0, %%o5, %0\n\t"	"sta	%%g0, [%0] %3\n\t"	"sta	%%g0, [%0 + %2] %3\n\t"	"sta	%%g0, [%0 + %%g1] %3\n\t"	"sta	%%g0, [%0 + %%g2] %3\n\t"	"sta	%%g0, [%0 + %%g3] %3\n\t"	"sta	%%g0, [%0 + %%g4] %3\n\t"	"sta	%%g0, [%0 + %%g5] %3\n\t"	"bg	1b\n\t"	" sta	%%g0, [%1 + %%o4] %3\n"	: "=&r" (nbytes)	: "0" (nbytes), "r" (lsize), "i" (ASI_FLUSHCTX)	: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");}/* Don't inline the software version as it eats too many cache lines if expanded. */static void sun4c_flush_segment_sw(unsigned long addr){	if (sun4c_get_segmap(addr) != invalid_segment) {		unsigned long nbytes = SUN4C_VAC_SIZE;		unsigned long lsize = sun4c_vacinfo.linesize;		__asm__ __volatile__(		"add	%2, %2, %%g1\n\t"		"add	%2, %%g1, %%g2\n\t"		"add	%2, %%g2, %%g3\n\t"		"add	%2, %%g3, %%g4\n\t"		"add	%2, %%g4, %%g5\n\t"		"add	%2, %%g5, %%o4\n\t"		"add	%2, %%o4, %%o5\n"		"1:\n\t"		"subcc	%1, %%o5, %1\n\t"		"sta	%%g0, [%0] %6\n\t"		"sta	%%g0, [%0 + %2] %6\n\t"		"sta	%%g0, [%0 + %%g1] %6\n\t"		"sta	%%g0, [%0 + %%g2] %6\n\t"		"sta	%%g0, [%0 + %%g3] %6\n\t"		"sta	%%g0, [%0 + %%g4] %6\n\t"		"sta	%%g0, [%0 + %%g5] %6\n\t"		"sta	%%g0, [%0 + %%o4] %6\n\t"		"bg	1b\n\t"		" add	%0, %%o5, %0\n"		: "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)		: "0" (addr), "1" (nbytes), "2" (lsize),		  "i" (ASI_FLUSHSEG)		: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");	}}/* Bolix one page from the virtual cache. */static void sun4c_flush_page(unsigned long addr){	addr &= PAGE_MASK;	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=	    _SUN4C_PAGE_VALID)		return;	if (sun4c_vacinfo.do_hwflushes) {		__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :				     "r" (addr), "i" (ASI_HWFLUSHPAGE));	} else {		unsigned long left = PAGE_SIZE;		unsigned long lsize = sun4c_vacinfo.linesize;		__asm__ __volatile__("add	%2, %2, %%g1\n\t"				     "add	%2, %%g1, %%g2\n\t"				     "add	%2, %%g2, %%g3\n\t"				     "add	%2, %%g3, %%g4\n\t"				     "add	%2, %%g4, %%g5\n\t"				     "add	%2, %%g5, %%o4\n\t"				     "add	%2, %%o4, %%o5\n"				     "1:\n\t"				     "subcc	%1, %%o5, %1\n\t"				     "sta	%%g0, [%0] %6\n\t"				     "sta	%%g0, [%0 + %2] %6\n\t"				     "sta	%%g0, [%0 + %%g1] %6\n\t"				     "sta	%%g0, [%0 + %%g2] %6\n\t"				     "sta	%%g0, [%0 + %%g3] %6\n\t"				     "sta	%%g0, [%0 + %%g4] %6\n\t"				     "sta	%%g0, [%0 + %%g5] %6\n\t"				     "sta	%%g0, [%0 + %%o4] %6\n\t"				     "bg	1b\n\t"				     " add	%0, %%o5, %0\n\t"				     : "=&r" (addr), "=&r" (left), "=&r" (lsize)				     : "0" (addr), "1" (left), "2" (lsize),				       "i" (ASI_FLUSHPG)				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");	}}/* Don't inline the software version as it eats too many cache lines if expanded. */static void sun4c_flush_page_sw(unsigned long addr){	addr &= PAGE_MASK;	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==	    _SUN4C_PAGE_VALID) {		unsigned long left = PAGE_SIZE;		unsigned long lsize = sun4c_vacinfo.linesize;		__asm__ __volatile__(		"add	%2, %2, %%g1\n\t"		"add	%2, %%g1, %%g2\n\t"		"add	%2, %%g2, %%g3\n\t"		"add	%2, %%g3, %%g4\n\t"		"add	%2, %%g4, %%g5\n\t"		"add	%2, %%g5, %%o4\n\t"		"add	%2, %%o4, %%o5\n"		"1:\n\t"		"subcc	%1, %%o5, %1\n\t"		"sta	%%g0, [%0] %6\n\t"		"sta	%%g0, [%0 + %2] %6\n\t"		"sta	%%g0, [%0 + %%g1] %6\n\t"		"sta	%%g0, [%0 + %%g2] %6\n\t"		"sta	%%g0, [%0 + %%g3] %6\n\t"		"sta	%%g0, [%0 + %%g4] %6\n\t"		"sta	%%g0, [%0 + %%g5] %6\n\t"		"sta	%%g0, [%0 + %%o4] %6\n\t"		"bg	1b\n\t"		" add	%0, %%o5, %0\n"		: "=&r" (addr), "=&r" (left), "=&r" (lsize)		: "0" (addr), "1" (left), "2" (lsize),		  "i" (ASI_FLUSHPG)		: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");	}}/* The sun4c's do have an on chip store buffer.  And the way you * clear them out isn't so obvious.  The only way I can think of * to accomplish this is to read the current context register, * store the same value there, then read an external hardware * register. */void sun4c_complete_all_stores(void){	volatile int _unused;	_unused = sun4c_get_context();	sun4c_set_context(_unused);#ifdef CONFIG_SUN_AUXIO	_unused = *AUXREG;#endif}/* Bootup utility functions. */static inline void sun4c_init_clean_segmap(unsigned char pseg){	unsigned long vaddr;	sun4c_put_segmap(0, pseg);	for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE)		sun4c_put_pte(vaddr, 0);	sun4c_put_segmap(0, invalid_segment);}static inline void sun4c_init_clean_mmu(unsigned long kernel_end){	unsigned long vaddr;	unsigned char savectx, ctx;	savectx = sun4c_get_context();	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);	for (ctx = 0; ctx < num_contexts; ctx++) {		sun4c_set_context(ctx);		for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)			sun4c_put_segmap(vaddr, invalid_segment);		for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)			sun4c_put_segmap(vaddr, invalid_segment);		for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)			sun4c_put_segmap(vaddr, invalid_segment);		for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)			sun4c_put_segmap(vaddr, invalid_segment);	}	sun4c_set_context(savectx);}void __init sun4c_probe_vac(void){	sun4c_disable_vac();	if (ARCH_SUN4) {		switch (idprom->id_machtype) {		case (SM_SUN4|SM_4_110):			sun4c_vacinfo.type = NONE;			sun4c_vacinfo.num_bytes = 0;			sun4c_vacinfo.linesize = 0;			sun4c_vacinfo.do_hwflushes = 0;			prom_printf("No VAC. Get some bucks and buy a real computer.");			prom_halt();			break;		case (SM_SUN4|SM_4_260):			sun4c_vacinfo.type = WRITE_BACK;			sun4c_vacinfo.num_bytes = 128 * 1024;			sun4c_vacinfo.linesize = 16;			sun4c_vacinfo.do_hwflushes = 0;			break;		case (SM_SUN4|SM_4_330):			sun4c_vacinfo.type = WRITE_THROUGH;			sun4c_vacinfo.num_bytes = 128 * 1024;			sun4c_vacinfo.linesize = 16;			sun4c_vacinfo.do_hwflushes = 0;			break;		case (SM_SUN4|SM_4_470):			sun4c_vacinfo.type = WRITE_BACK;			sun4c_vacinfo.num_bytes = 128 * 1024;			sun4c_vacinfo.linesize = 32;			sun4c_vacinfo.do_hwflushes = 0;			break;		default:			prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);			prom_halt();		};	} else {		sun4c_vacinfo.type = WRITE_THROUGH;		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {			/* PROM on SS1 lacks this info, to be super safe we			 * hard code it here since this arch is cast in stone.			 */			sun4c_vacinfo.num_bytes = 65536;			sun4c_vacinfo.linesize = 16;		} else {			sun4c_vacinfo.num_bytes =			 prom_getintdefault(prom_root_node, "vac-size", 65536);			sun4c_vacinfo.linesize =			 prom_getintdefault(prom_root_node, "vac-linesize", 16);		}		sun4c_vacinfo.do_hwflushes =		 prom_getintdefault(prom_root_node, "vac-hwflush", 0);		if (sun4c_vacinfo.do_hwflushes == 0)			sun4c_vacinfo.do_hwflushes =			 prom_getintdefault(prom_root_node, "vac_hwflush", 0);		if (sun4c_vacinfo.num_bytes != 65536) {			prom_printf("WEIRD Sun4C VAC cache size, tell davem");			prom_halt();		}	}	sun4c_vacinfo.num_lines =		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);	switch (sun4c_vacinfo.linesize) {	case 16:		sun4c_vacinfo.log2lsize = 4;		break;	case 32:		sun4c_vacinfo.log2lsize = 5;		break;	default:		prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",			    sun4c_vacinfo.linesize);		prom_halt();	};	sun4c_flush_all();	sun4c_enable_vac();}/* Patch instructions for the low level kernel fault handler. */extern unsigned long invalid_segment_patch1, invalid_segment_patch1_ff;extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff;extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff;extern unsigned long num_context_patch1, num_context_patch1_16;extern unsigned long num_context_patch2, num_context_patch2_16;extern unsigned long vac_linesize_patch, vac_linesize_patch_32;extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on;extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on;#define PATCH_INSN(src, dst) do {	\		daddr = &(dst);		\		iaddr = &(src);		\		*daddr = *iaddr;	\	} while (0);static void patch_kernel_fault_handler(void){	unsigned long *iaddr, *daddr;	switch (num_segmaps) {		case 128:			/* Default, nothing to do. */			break;		case 256:			PATCH_INSN(invalid_segment_patch1_ff,				   invalid_segment_patch1);			PATCH_INSN(invalid_segment_patch2_ff,				   invalid_segment_patch2);			break;		case 512:			PATCH_INSN(invalid_segment_patch1_1ff,				   invalid_segment_patch1);			PATCH_INSN(invalid_segment_patch2_1ff,				   invalid_segment_patch2);			break;		default:			prom_printf("Unhandled number of segmaps: %d\n",				    num_segmaps);			prom_halt();	};	switch (num_contexts) {		case 8:			/* Default, nothing to do. */			break;		case 16:			PATCH_INSN(num_context_patch1_16,				   num_context_patch1);#if 0			PATCH_INSN(num_context_patch2_16,				   num_context_patch2);#endif			break;		default:			prom_printf("Unhandled number of contexts: %d\n",				    num_contexts);			prom_halt();	};	if (sun4c_vacinfo.do_hwflushes != 0) {		PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1);		PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2);	} else {		switch (sun4c_vacinfo.linesize) {		case 16:			/* Default, nothing to do. */			break;		case 32:			PATCH_INSN(vac_linesize_patch_32, vac_linesize_patch);			break;		default:			prom_printf("Impossible VAC linesize %d, halting...\n",				    sun4c_vacinfo.linesize);			prom_halt();		};	}}static void __init sun4c_probe_mmu(void)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -