patch-2.2.14 linux/arch/sparc/mm/sun4c.c

Next file: linux/arch/sparc/mm/swift.S
Previous file: linux/arch/sparc/mm/srmmu.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.13/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.173.2.1 1999/09/08 00:32:02 davem Exp $
+/* $Id: sun4c.c,v 1.173.2.5 1999/10/11 08:24:44 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -27,42 +27,19 @@
 #include <asm/mmu_context.h>
 #include <asm/sun4paddr.h>
 
-/* TODO: Make it such that interrupt handlers cannot dick with
- *       the user segment lists, most of the cli/sti pairs can
- *       disappear once that is taken care of.
- */
-
-/* XXX Ok the real performance win, I figure, will be to use a combined hashing
- * XXX and bitmap scheme to keep track of what we have mapped where.  The whole
- * XXX incentive is to make it such that the range flushes can be serviced
- * XXX always in near constant time. --DaveM
+/* 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;
 
-/* Define this to get extremely anal debugging, undefine for performance. */
-/* #define DEBUG_SUN4C_MM */
-
-#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
-
-/* This is used in many routines below. */
-#define FUW_INLINE do {							\
-	register int ctr asm("g5");					\
-	ctr = 0;							\
-	__asm__ __volatile__("\n"					\
-	"1:	ld	[%%g6 + %2], %%g4	! flush user windows\n"	\
-	"	orcc	%%g0, %%g4, %%g0\n"				\
-	"	add	%0, 1, %0\n"					\
-	"	bne	1b\n"						\
-	"	 save	%%sp, -64, %%sp\n"				\
-	"2:	subcc	%0, 1, %0\n"					\
-	"	bne	2b\n"						\
-	"	 restore %%g0, %%g0, %%g0\n"				\
-	: "=&r" (ctr)							\
-	: "0" (ctr), "i" (UWINMASK_OFFSET)				\
-	: "g4", "cc");							\
-} while(0);
-
 #ifdef CONFIG_SUN4
 #define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
 #else
@@ -82,58 +59,21 @@
 #define MIN(a,b) ((a)<(b)?(a):(b))
 #endif
 
-
-#define KGPROF_PROFILING 0
-#if KGPROF_PROFILING
-#define KGPROF_DEPTH 3 /* this needs to match the code below */
-#define KGPROF_SIZE 100
-static struct {
-	unsigned addr[KGPROF_DEPTH];
-	unsigned count;
-} kgprof_counters[KGPROF_SIZE];
-
-/* just call this function from whatever function you think needs it then
-   look at /proc/cpuinfo to see where the function is being called from
-   and how often. This gives a type of "kernel gprof" */
-#define NEXT_PROF(prev,lvl) (prev>PAGE_OFFSET?__builtin_return_address(lvl):0)
-static inline void kgprof_profile(void)
-{
-	unsigned ret[KGPROF_DEPTH];
-	int i,j;
-	/* you can't use a variable argument to __builtin_return_address() */
-	ret[0] = (unsigned)__builtin_return_address(0);
-	ret[1] = (unsigned)NEXT_PROF(ret[0],1);
-	ret[2] = (unsigned)NEXT_PROF(ret[1],2);
-
-	for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-		for (j=0;j<KGPROF_DEPTH;j++) 
-			if (ret[j] != kgprof_counters[i].addr[j]) break;
-		if (j==KGPROF_DEPTH) break;
-	}
-	if (i<KGPROF_SIZE) {		
-		for (j=0;j<KGPROF_DEPTH;j++)
-			kgprof_counters[i].addr[j] = ret[j];
-		kgprof_counters[i].count++;
-	}
-}
-#endif
-
-
 /* Flushing the cache. */
 struct sun4c_vac_props sun4c_vacinfo;
-static int ctxflushes, segflushes, pageflushes;
 unsigned long sun4c_kernel_faults;
 
 /* convert a virtual address to a physical address and vice
-   versa. Easy on the 4c */
+ * versa. Easy on the 4c
+ */
 static unsigned long sun4c_v2p(unsigned long vaddr)
 {
-  return(vaddr - PAGE_OFFSET);
+	return (vaddr - PAGE_OFFSET);
 }
 
 static unsigned long sun4c_p2v(unsigned long vaddr)
 {
-  return(vaddr + PAGE_OFFSET);
+	return (vaddr + PAGE_OFFSET);
 }
 
 
@@ -142,44 +82,64 @@
 {
 	unsigned long begin, end;
 
-	if(sun4c_vacinfo.on)
+	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) {
+	while (begin < end) {
 		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 				     "r" (begin), "i" (ASI_CONTROL));
 		begin += sun4c_vacinfo.linesize;
 	}
 }
 
-/* Context level flush. */
-static inline void sun4c_flush_context_hw(void)
+static __inline__ void sun4c_flush_context_hw(void)
 {
 	unsigned long end = SUN4C_VAC_SIZE;
-	unsigned pgsz = PAGE_SIZE;
 
-	ctxflushes++;
-	__asm__ __volatile__("
-1:	subcc	%0, %2, %0
-	bg	1b
-	 sta	%%g0, [%0] %3
-	nop; nop; nop;		! Weitek hwbug
-"	: "=&r" (end)
-	: "0" (end), "r" (pgsz), "i" (ASI_HWFLUSHCONTEXT)
+	__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;
 
-	ctxflushes++;
 	__asm__ __volatile__("
 	add	%2, %2, %%g1
 	add	%2, %%g1, %%g2
@@ -203,72 +163,13 @@
 	: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
 }
 
-/* Scrape the segment starting at ADDR from the virtual cache. */
-static inline void sun4c_flush_segment(unsigned long addr)
-{
-	if(sun4c_get_segmap(addr) == invalid_segment)
-		return;
-
-	segflushes++;
-	if(sun4c_vacinfo.do_hwflushes) {
-		unsigned long end = (addr + SUN4C_VAC_SIZE);
-
-		for( ; addr < end; addr += PAGE_SIZE)
-			__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
-					     "r" (addr), "i" (ASI_HWFLUSHSEG));
-	} else {
-		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\t"
-				     : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
-				     : "0" (addr), "1" (nbytes), "2" (lsize),
-				       "i" (ASI_FLUSHSEG)
-				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
-	}
-}
-
-/* Call this version when you know hardware flushes are available. */
-static inline void sun4c_flush_segment_hw(unsigned long addr)
-{
-	if(sun4c_get_segmap(addr) != invalid_segment) {
-		unsigned long end;
-
-		segflushes++;
-		for(end = addr + SUN4C_VAC_SIZE; addr < end; addr += PAGE_SIZE)
-			__asm__ __volatile__("sta %%g0, [%0] %1"
-					     : : "r" (addr), "i" (ASI_HWFLUSHSEG));
-		/* Weitek POWER-UP hwbug workaround. */
-		__asm__ __volatile__("nop;nop;nop;	! Weitek hwbug");
-	}
-}
-
 /* 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) {
+	if (sun4c_get_segmap(addr) != invalid_segment) {
 		unsigned long nbytes = SUN4C_VAC_SIZE;
 		unsigned long lsize = sun4c_vacinfo.linesize;
 
-		segflushes++;
 		__asm__ __volatile__("
 		add	%2, %2, %%g1
 		add	%2, %%g1, %%g2
@@ -300,12 +201,11 @@
 {
 	addr &= PAGE_MASK;
 
-	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
-	   _SUN4C_PAGE_VALID)
+	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
+	    _SUN4C_PAGE_VALID)
 		return;
 
-	pageflushes++;
-	if(sun4c_vacinfo.do_hwflushes) {
+	if (sun4c_vacinfo.do_hwflushes) {
 		__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
 				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
 	} else {
@@ -338,30 +238,15 @@
 	}
 }
 
-/* Again, hw-only and sw-only cache page-level flush variants. */
-static inline void sun4c_flush_page_hw(unsigned long addr)
-{
-	addr &= PAGE_MASK;
-	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
-	   _SUN4C_PAGE_VALID) {
-		pageflushes++;
-		__asm__ __volatile__("sta %%g0, [%0] %1"
-				     : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
-		/* Weitek POWER-UP hwbug workaround. */
-		__asm__ __volatile__("nop;nop;nop;	! Weitek hwbug");
-	}
-}
-
 /* 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) {
+	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;
 
-		pageflushes++;
 		__asm__ __volatile__("
 		add	%2, %2, %%g1
 		add	%2, %%g1, %%g2
@@ -411,7 +296,7 @@
 	unsigned long vaddr;
 
 	sun4c_put_segmap(0, pseg);
-	for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
+	for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE)
 		sun4c_put_pte(vaddr, 0);
 	sun4c_put_segmap(0, invalid_segment);
 }
@@ -423,15 +308,15 @@
 
 	savectx = sun4c_get_context();
 	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
-	for(ctx = 0; ctx < num_contexts; ctx++) {
+	for (ctx = 0; ctx < num_contexts; ctx++) {
 		sun4c_set_context(ctx);
-		for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
+		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)
+		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)
+		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)
+		for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
 			sun4c_put_segmap(vaddr, invalid_segment);
 	}
 	sun4c_set_context(savectx);
@@ -442,7 +327,7 @@
 	sun4c_disable_vac();
 
 	if (ARCH_SUN4) {
-		switch(idprom->id_machtype) {
+		switch (idprom->id_machtype) {
 
 		case (SM_SUN4|SM_4_110):
 			sun4c_vacinfo.type = NONE;
@@ -477,12 +362,12 @@
 		default:
 			prom_printf("Cannot initialize VAC - wierd 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))) {
+		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.
 			 */
@@ -497,7 +382,7 @@
 		sun4c_vacinfo.do_hwflushes =
 		 prom_getintdefault(prom_root_node, "vac-hwflush", 0);
 
-		if(sun4c_vacinfo.do_hwflushes == 0)
+		if (sun4c_vacinfo.do_hwflushes == 0)
 			sun4c_vacinfo.do_hwflushes =
 			 prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
@@ -509,7 +394,7 @@
 
 	sun4c_vacinfo.num_lines =
 		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
-	switch(sun4c_vacinfo.linesize) {
+	switch (sun4c_vacinfo.linesize) {
 	case 16:
 		sun4c_vacinfo.log2lsize = 4;
 		break;
@@ -566,7 +451,7 @@
 			prom_printf("Unhandled number of segmaps: %d\n",
 				    num_segmaps);
 			prom_halt();
-	}
+	};
 	switch (num_contexts) {
 		case 8:
 			/* Default, nothing to do. */
@@ -574,19 +459,22 @@
 		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) {
+	};
+
+	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) {
+		switch (sun4c_vacinfo.linesize) {
 		case 16:
 			/* Default, nothing to do. */
 			break;
@@ -604,7 +492,7 @@
 __initfunc(static void sun4c_probe_mmu(void))
 {
 	if (ARCH_SUN4) {
-		switch(idprom->id_machtype) {
+		switch (idprom->id_machtype) {
 		case (SM_SUN4|SM_4_110):
 			prom_printf("No support for 4100 yet\n");
 			prom_halt();
@@ -631,10 +519,10 @@
 		default:
 			prom_printf("Invalid SUN4 model\n");
 			prom_halt();
-		}
+		};
 	} else {
-		if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-	   	(idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
 			/* Hardcode these just to be safe, PROM on SS1 does
 		 	* not have this info available in the root node.
 		 	*/
@@ -679,10 +567,10 @@
 {
 	extern unsigned long start;
 
-	if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
-	   (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
-	   (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
-	   (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
+	if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
+	    (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
 		/* Whee.. */
 		printk("SS2 cache bug detected, uncaching trap table page\n");
 		sun4c_flush_page((unsigned int) &start);
@@ -697,9 +585,9 @@
 	unsigned long page, end;
 
 	end = PAGE_ALIGN((addr + len));
-	while(addr < end) {
+	while (addr < end) {
 		page = get_free_page(GFP_KERNEL);
-		if(!page) {
+		if (!page) {
 			prom_printf("alloc_dvma: Cannot get a dvma page\n");
 			prom_halt();
 		}
@@ -726,6 +614,13 @@
 	unsigned long vaddr;
 	unsigned char pseg;
 	unsigned char locked;
+
+	/* For user mappings only, and completely hidden from kernel
+	 * TLB miss code.
+	 */
+	unsigned char ctx;
+	struct sun4c_mmu_entry *lru_next;
+	struct sun4c_mmu_entry *lru_prev;
 };
 
 static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS];
@@ -734,12 +629,15 @@
 {
 	int i;
 
-	for(i=0; i < SUN4C_MAX_SEGMAPS; i++) {
+	for (i = 0; i < SUN4C_MAX_SEGMAPS; i++) {
 		mmu_entry_pool[i].pseg = i;
 		mmu_entry_pool[i].next = 0;
 		mmu_entry_pool[i].prev = 0;
 		mmu_entry_pool[i].vaddr = 0;
 		mmu_entry_pool[i].locked = 0;
+		mmu_entry_pool[i].ctx = 0;
+		mmu_entry_pool[i].lru_next = 0;
+		mmu_entry_pool[i].lru_prev = 0;
 	}
 	mmu_entry_pool[invalid_segment].locked = 1;
 }
@@ -750,8 +648,8 @@
 	unsigned long start, end;
 
 	end = vaddr + SUN4C_REAL_PGDIR_SIZE;
-	for(start = vaddr; start < end; start += PAGE_SIZE)
-		if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
+	for (start = vaddr; start < end; start += PAGE_SIZE)
+		if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
 			sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
 				      ~bits_off);
 }
@@ -762,16 +660,16 @@
 	unsigned char pseg, ctx;
 #ifdef CONFIG_SUN4
 	/* sun4/110 and 260 have no kadb. */
-	if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
-	   (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
+	if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
+	    (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
 #endif
-	for(vaddr = KADB_DEBUGGER_BEGVM;
-	    vaddr < LINUX_OPPROM_ENDVM;
-	    vaddr += SUN4C_REAL_PGDIR_SIZE) {
+	for (vaddr = KADB_DEBUGGER_BEGVM;
+	     vaddr < LINUX_OPPROM_ENDVM;
+	     vaddr += SUN4C_REAL_PGDIR_SIZE) {
 		pseg = sun4c_get_segmap(vaddr);
-		if(pseg != invalid_segment) {
+		if (pseg != invalid_segment) {
 			mmu_entry_pool[pseg].locked = 1;
-			for(ctx = 0; ctx < num_contexts; ctx++)
+			for (ctx = 0; ctx < num_contexts; ctx++)
 				prom_putsegment(ctx, vaddr, pseg);
 			fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
 		}
@@ -779,10 +677,10 @@
 #ifdef CONFIG_SUN4
 	}
 #endif
-	for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
+	for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
 		pseg = sun4c_get_segmap(vaddr);
 		mmu_entry_pool[pseg].locked = 1;
-		for(ctx = 0; ctx < num_contexts; ctx++)
+		for (ctx = 0; ctx < num_contexts; ctx++)
 			prom_putsegment(ctx, vaddr, pseg);
 		fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
 	}
@@ -792,13 +690,13 @@
 {
 	int i, ctx;
 
-	while(start < end) {
-		for(i=0; i < invalid_segment; i++)
-			if(!mmu_entry_pool[i].locked)
+	while (start < end) {
+		for (i = 0; i < invalid_segment; i++)
+			if (!mmu_entry_pool[i].locked)
 				break;
 		mmu_entry_pool[i].locked = 1;
 		sun4c_init_clean_segmap(i);
-		for(ctx = 0; ctx < num_contexts; ctx++)
+		for (ctx = 0; ctx < num_contexts; ctx++)
 			prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
 		start += SUN4C_REAL_PGDIR_SIZE;
 	}
@@ -815,13 +713,15 @@
 
 static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */
 static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
+static struct sun4c_mmu_ring sun4c_ulru_ring;	     /* LRU user entries */
 struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
 struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
 
 static inline void sun4c_init_rings(unsigned long *mempool)
 {
 	int i;
-	for(i=0; i<SUN4C_MAX_CONTEXTS; i++) {
+
+	for (i = 0; i<SUN4C_MAX_CONTEXTS; i++) {
 		sun4c_context_ring[i].ringhd.next =
 			sun4c_context_ring[i].ringhd.prev =
 			&sun4c_context_ring[i].ringhd;
@@ -830,6 +730,9 @@
 	sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
 		&sun4c_ufree_ring.ringhd;
 	sun4c_ufree_ring.num_entries = 0;
+	sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev =
+		&sun4c_ulru_ring.ringhd;
+	sun4c_ulru_ring.num_entries = 0;
 	sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
 		&sun4c_kernel_ring.ringhd;
 	sun4c_kernel_ring.num_entries = 0;
@@ -838,8 +741,8 @@
 	sun4c_kfree_ring.num_entries = 0;
 }
 
-static inline void add_ring(struct sun4c_mmu_ring *ring,
-			    struct sun4c_mmu_entry *entry)
+static void add_ring(struct sun4c_mmu_ring *ring,
+		     struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *head = &ring->ringhd;
 
@@ -849,49 +752,58 @@
 	ring->num_entries++;
 }
 
-static inline void add_ring_ordered(struct sun4c_mmu_ring *ring,
-				    struct sun4c_mmu_entry *entry)
+static __inline__ void add_lru(struct sun4c_mmu_entry *entry)
+{
+	struct sun4c_mmu_ring *ring = &sun4c_ulru_ring;
+	struct sun4c_mmu_entry *head = &ring->ringhd;
+
+	entry->lru_next = head;
+	(entry->lru_prev = head->lru_prev)->lru_next = entry;
+	head->lru_prev = entry;
+}
+
+static void add_ring_ordered(struct sun4c_mmu_ring *ring,
+			     struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *head = &ring->ringhd;
 	unsigned long addr = entry->vaddr;
 
-	if(head->next != &ring->ringhd) {
-		while((head->next != &ring->ringhd) && (head->next->vaddr < addr))
-			head = head->next;
-	}
+	while ((head->next != &ring->ringhd) && (head->next->vaddr < addr))
+		head = head->next;
+
 	entry->prev = head;
 	(entry->next = head->next)->prev = entry;
 	head->next = entry;
 	ring->num_entries++;
+
+	add_lru(entry);
 }
 
-static inline void remove_ring(struct sun4c_mmu_ring *ring,
-			       struct sun4c_mmu_entry *entry)
+static __inline__ void remove_ring(struct sun4c_mmu_ring *ring,
+				   struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *next = entry->next;
 
 	(next->prev = entry->prev)->next = next;
 	ring->num_entries--;
-#ifdef DEBUG_SUN4C_MM
-	if(ring->num_entries < 0)
-		panic("sun4c: Ring num_entries < 0!");
-#endif
 }
 
-static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+static void remove_lru(struct sun4c_mmu_entry *entry)
 {
-        remove_ring(sun4c_context_ring+ctx, entry);
-        add_ring(&sun4c_ufree_ring, entry);
+	struct sun4c_mmu_entry *next = entry->lru_next;
+
+	(next->lru_prev = entry->lru_prev)->lru_next = next;
 }
 
-static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) 
+static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
 {
-        remove_ring(&sun4c_ufree_ring, entry);
-        add_ring_ordered(sun4c_context_ring+ctx, entry);
+        remove_ring(sun4c_context_ring+ctx, entry);
+	remove_lru(entry);
+        add_ring(&sun4c_ufree_ring, entry);
 }
 
-static inline void free_kernel_entry(struct sun4c_mmu_entry *entry,
-				     struct sun4c_mmu_ring *ring)
+static void free_kernel_entry(struct sun4c_mmu_entry *entry,
+			      struct sun4c_mmu_ring *ring)
 {
         remove_ring(ring, entry);
         add_ring(&sun4c_kfree_ring, entry);
@@ -901,9 +813,9 @@
 {
 	int i;
 
-	while(howmany) {
-		for(i=0; i < invalid_segment; i++)
-			if(!mmu_entry_pool[i].locked)
+	while (howmany) {
+		for (i = 0; i < invalid_segment; i++)
+			if (!mmu_entry_pool[i].locked)
 				break;
 		mmu_entry_pool[i].locked = 1;
 		sun4c_init_clean_segmap(i);
@@ -916,54 +828,40 @@
 {
 	int i;
 
-	for(i=0; i < invalid_segment; i++) {
-		if(mmu_entry_pool[i].locked)
+	for (i = 0; i < invalid_segment; i++) {
+		if (mmu_entry_pool[i].locked)
 			continue;
 		sun4c_init_clean_segmap(i);
 		add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
 	}
 }
 
-static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
 {
 	int savectx, ctx;
 
 	savectx = sun4c_get_context();
-	for(ctx = 0; ctx < num_contexts; ctx++) {
+	for (ctx = 0; ctx < num_contexts; ctx++) {
 		sun4c_set_context(ctx);
 		sun4c_put_segmap(kentry->vaddr, invalid_segment);
 	}
 	sun4c_set_context(savectx);
 }
 
-static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
 {
 	int savectx, ctx;
 
 	savectx = sun4c_get_context();
-	for(ctx = 0; ctx < num_contexts; ctx++) {
+	for (ctx = 0; ctx < num_contexts; ctx++) {
 		sun4c_set_context(ctx);
 		sun4c_put_segmap(kentry->vaddr, kentry->pseg);
 	}
 	sun4c_set_context(savectx);
 }
 
-static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
-{
-	sun4c_put_segmap(uentry->vaddr, invalid_segment);
-}
-
-static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
-{
-	unsigned long start = uentry->vaddr;
-	unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
-
-	sun4c_put_segmap(uentry->vaddr, uentry->pseg);
-	while(start < end) {
-		sun4c_put_pte(start, 0);
-		start += PAGE_SIZE;
-	}
-}
+#define sun4c_user_unmap(__entry) \
+	sun4c_put_segmap((__entry)->vaddr, invalid_segment)
 
 static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
@@ -971,11 +869,11 @@
 	unsigned long flags;
 
 	save_and_cli(flags);
-	if(head->next != head) {
+	if (head->next != head) {
 		struct sun4c_mmu_entry *entry = head->next;
 		int savectx = sun4c_get_context();
 
-		FUW_INLINE
+		flush_user_windows();
 		sun4c_set_context(ctx);
 		sun4c_flush_context_hw();
 		do {
@@ -985,7 +883,7 @@
 			free_user_entry(ctx, entry);
 
 			entry = next;
-		} while(entry != head);
+		} while (entry != head);
 		sun4c_set_context(savectx);
 	}
 	restore_flags(flags);
@@ -997,11 +895,11 @@
 	unsigned long flags;
 
 	save_and_cli(flags);
-	if(head->next != head) {
+	if (head->next != head) {
 		struct sun4c_mmu_entry *entry = head->next;
 		int savectx = sun4c_get_context();
 
-		FUW_INLINE
+		flush_user_windows();
 		sun4c_set_context(ctx);
 		sun4c_flush_context_sw();
 		do {
@@ -1011,49 +909,31 @@
 			free_user_entry(ctx, entry);
 
 			entry = next;
-		} while(entry != head);
+		} while (entry != head);
 		sun4c_set_context(savectx);
 	}
 	restore_flags(flags);
 }
 
-static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
-	/* by using .prev we get a kind of "lru" algorithm */
-	struct sun4c_mmu_entry *entry = crp->ringhd.prev;
-	unsigned long flags;
-	int savectx = sun4c_get_context();
-
-#ifdef DEBUG_SUN4C_MM
-	if(entry == &crp->ringhd)
-		panic("sun4c_demap_one: Freeing from empty ctx ring.");
-#endif
-	FUW_INLINE
-	save_and_cli(flags);
-	sun4c_set_context(ctx);
-	sun4c_flush_segment(entry->vaddr);
-	sun4c_user_unmap(entry);
-	free_user_entry(ctx, entry);
-	sun4c_set_context(savectx);
-	restore_flags(flags);
-}
-
 static int sun4c_user_taken_entries = 0;  /* This is how much we have.             */
 static int max_user_taken_entries = 0;    /* This limits us and prevents deadlock. */
 
-static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
+static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
 {
 	struct sun4c_mmu_entry *this_entry;
 
 	/* If some are free, return first one. */
-	if(sun4c_kfree_ring.num_entries) {
+	if (sun4c_kfree_ring.num_entries) {
 		this_entry = sun4c_kfree_ring.ringhd.next;
 		return this_entry;
 	}
 
 	/* Else free one up. */
 	this_entry = sun4c_kernel_ring.ringhd.prev;
-	sun4c_flush_segment(this_entry->vaddr);
+	if (sun4c_vacinfo.do_hwflushes)
+		sun4c_flush_segment_hw(this_entry->vaddr);
+	else
+		sun4c_flush_segment_sw(this_entry->vaddr);
 	sun4c_kernel_unmap(this_entry);
 	free_kernel_entry(this_entry, &sun4c_kernel_ring);
 	this_entry = sun4c_kfree_ring.ringhd.next;
@@ -1061,141 +941,73 @@
 	return this_entry;
 }
 
-void sun4c_shrink_kernel_ring(void)
-{
-	struct sun4c_mmu_entry *entry;
-	unsigned long flags;
-
-	/* If an interrupt comes in here, we die... */
-	save_and_cli(flags);
-
-	if (sun4c_user_taken_entries) {
-		entry = sun4c_kernel_strategy();
-        	remove_ring(&sun4c_kfree_ring, entry);
-		add_ring(&sun4c_ufree_ring, entry);
-		sun4c_user_taken_entries--;
-#if 0
-		printk("shrink: ufree= %d, kfree= %d, kernel= %d\n",
-			sun4c_ufree_ring.num_entries,
-			sun4c_kfree_ring.num_entries,
-			sun4c_kernel_ring.num_entries);
-#endif
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_user_taken_entries < 0)
-			panic("sun4c_shrink_kernel_ring: taken < 0.");
-#endif
-	}
-	restore_flags(flags);
-}
-
 /* Using this method to free up mmu entries eliminates a lot of
  * potential races since we have a kernel that incurs tlb
  * replacement faults.  There may be performance penalties.
+ *
+ * NOTE: Must be called with interrupts disabled.
  */
-static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
+static struct sun4c_mmu_entry *sun4c_user_strategy(void)
 {
-	struct ctx_list *next_one;
-	struct sun4c_mmu_ring *rp = 0;
+	struct sun4c_mmu_entry *entry;
 	unsigned char ctx;
-#ifdef DEBUG_SUN4C_MM
-	int lim = num_contexts;
-#endif
+	int savectx;
 
 	/* If some are free, return first one. */
-	if(sun4c_ufree_ring.num_entries) {
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-			panic("sun4c_user_strategy: num_entries!=0 but ring empty.");
-#endif
-		return sun4c_ufree_ring.ringhd.next;
+	if (sun4c_ufree_ring.num_entries) {
+		entry = sun4c_ufree_ring.ringhd.next;
+		goto unlink_out;
 	}
 
 	if (sun4c_user_taken_entries) {
-		sun4c_shrink_kernel_ring();
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-			panic("sun4c_user_strategy: kernel shrunk but ufree empty.");
-#endif
-		return sun4c_ufree_ring.ringhd.next;
+		entry = sun4c_kernel_strategy();
+		sun4c_user_taken_entries--;
+		goto kunlink_out;
 	}
 
-	/* Grab one from the LRU context. */
-	next_one = ctx_used.next;
-	while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0)
-#ifdef DEBUG_SUN4C_MM
-	       && (--lim >= 0)
-#endif
-	       )
-		next_one = next_one->next;
+	/* Grab from the beginning of the LRU list. */
+	entry = sun4c_ulru_ring.ringhd.lru_next;
+	ctx = entry->ctx;
 
-#ifdef DEBUG_SUN4C_MM
-	if(lim < 0)
-		panic("No user segmaps!");
-#endif
+	savectx = sun4c_get_context();
+	flush_user_windows();
+	sun4c_set_context(ctx);
+	if (sun4c_vacinfo.do_hwflushes)
+		sun4c_flush_segment_hw(entry->vaddr);
+	else
+		sun4c_flush_segment_sw(entry->vaddr);
+	sun4c_user_unmap(entry);
+	remove_ring(sun4c_context_ring + ctx, entry);
+	remove_lru(entry);
+	sun4c_set_context(savectx);
 
-	ctx = next_one->ctx_number;
-	rp = &sun4c_context_ring[ctx];
+	return entry;
 
-	sun4c_demap_one(rp, ctx);
-#ifdef DEBUG_SUN4C_MM
-	if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-		panic("sun4c_user_strategy: demapped one but ufree empty.");
-#endif
-	return sun4c_ufree_ring.ringhd.next;
+unlink_out:
+	remove_ring(&sun4c_ufree_ring, entry);
+	return entry;
+kunlink_out:
+	remove_ring(&sun4c_kfree_ring, entry);
+	return entry;
 }
 
+/* NOTE: Must be called with interrupts disabled. */
 void sun4c_grow_kernel_ring(void)
 {
 	struct sun4c_mmu_entry *entry;
 
-#if 0
-	printk("grow: ");
-#endif
-
 	/* Prevent deadlock condition. */
-	if(sun4c_user_taken_entries >= max_user_taken_entries) {
-#if 0
-		printk("deadlock avoidance, taken= %d max= %d\n",
-		       sun4c_user_taken_entries, max_user_taken_entries);
-#endif
+	if (sun4c_user_taken_entries >= max_user_taken_entries)
 		return;
-	}
 
 	if (sun4c_ufree_ring.num_entries) {
 		entry = sun4c_ufree_ring.ringhd.next;
-#ifdef DEBUG_SUN4C_MM
-		if(entry == &sun4c_ufree_ring.ringhd)
-			panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty.");
-#endif
         	remove_ring(&sun4c_ufree_ring, entry);
 		add_ring(&sun4c_kfree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_user_taken_entries < 0)
-			panic("\nsun4c_grow_kernel_ring: taken < 0.");
-#endif
 		sun4c_user_taken_entries++;
-#if 0
-		printk("ufree= %d, kfree= %d, kernel= %d\n",
-			sun4c_ufree_ring.num_entries,
-			sun4c_kfree_ring.num_entries,
-			sun4c_kernel_ring.num_entries);
-#endif
 	}
 }
 
-static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
-{
-	struct sun4c_mmu_entry *entry;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	entry = sun4c_user_strategy();
-	entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK);
-	assign_user_entry(ctx, entry);
-	sun4c_user_map(entry);
-	restore_flags(flags);
-}
-
 /* This is now a fast in-window trap handler to avoid any and all races. */
 static void sun4c_quick_kernel_fault(unsigned long address)
 {
@@ -1234,7 +1046,7 @@
 #define BUCKET_PTE_PAGE(pte)   \
         (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT))
 
-static inline void get_locked_segment(unsigned long addr)
+static void get_locked_segment(unsigned long addr)
 {
 	struct sun4c_mmu_entry *stolen;
 	unsigned long flags;
@@ -1242,19 +1054,14 @@
 	save_and_cli(flags);
 	addr &= SUN4C_REAL_PGDIR_MASK;
 	stolen = sun4c_user_strategy();
-	remove_ring(&sun4c_ufree_ring, stolen);
 	max_user_taken_entries--;
-#ifdef DEBUG_SUN4C_MM
-	if(max_user_taken_entries < 0)
-		panic("get_locked_segment: max_user_taken < 0.");
-#endif
 	stolen->vaddr = addr;
-	FUW_INLINE
+	flush_user_windows();
 	sun4c_kernel_map(stolen);
 	restore_flags(flags);
 }
 
-static inline void free_locked_segment(unsigned long addr)
+static void free_locked_segment(unsigned long addr)
 {
 	struct sun4c_mmu_entry *entry;
 	unsigned long flags;
@@ -1265,14 +1072,13 @@
 	pseg = sun4c_get_segmap(addr);
 	entry = &mmu_entry_pool[pseg];
 
-	FUW_INLINE
-	sun4c_flush_segment(addr);
+	flush_user_windows();
+	if (sun4c_vacinfo.do_hwflushes)
+		sun4c_flush_segment_hw(addr);
+	else
+		sun4c_flush_segment_sw(addr);
 	sun4c_kernel_unmap(entry);
 	add_ring(&sun4c_ufree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
-	if(max_user_taken_entries < 0)
-		panic("free_locked_segment: max_user_taken < 0.");
-#endif
 	max_user_taken_entries++;
 	restore_flags(flags);
 }
@@ -1284,8 +1090,8 @@
 	/* 32 buckets per segment... */
 	entry &= ~31;
 	start = entry;
-	for(end = (start + 32); start < end; start++)
-		if(sun4c_bucket[start] != BUCKET_EMPTY)
+	for (end = (start + 32); start < end; start++)
+		if (sun4c_bucket[start] != BUCKET_EMPTY)
 			return;
 
 	/* Entire segment empty, release it. */
@@ -1304,23 +1110,39 @@
 	int entry;
 
 	pages = __get_free_pages(GFP_KERNEL, TASK_STRUCT_ORDER);
-	if(!pages)
+	if (!pages)
 		return (struct task_struct *) 0;
 
-	for(entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
-		if(sun4c_bucket[entry] == BUCKET_EMPTY)
+	for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
+		if (sun4c_bucket[entry] == BUCKET_EMPTY)
 			break;
-	if(entry == NR_TASK_BUCKETS) {
+	if (entry == NR_TASK_BUCKETS) {
 		free_pages(pages, TASK_STRUCT_ORDER);
 		return (struct task_struct *) 0;
 	}
-	if(entry >= sun4c_lowbucket_avail)
+	if (entry >= sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry + 1;
 
 	addr = BUCKET_ADDR(entry);
 	sun4c_bucket[entry] = (union task_union *) addr;
-	if(sun4c_get_segmap(addr) == invalid_segment)
+	if (sun4c_get_segmap(addr) == invalid_segment)
 		get_locked_segment(addr);
+
+	/* We are changing the virtual color of the page(s)
+	 * so we must flush the cache to guarentee consistancy.
+	 */
+	if (sun4c_vacinfo.do_hwflushes) {
+		sun4c_flush_page_hw(pages);
+#ifndef CONFIG_SUN4	
+		sun4c_flush_page_hw(pages + PAGE_SIZE);
+#endif
+	} else {
+		sun4c_flush_page_sw(pages);
+#ifndef CONFIG_SUN4	
+		sun4c_flush_page_sw(pages + PAGE_SIZE);
+#endif
+	}
+
 	sun4c_put_pte(addr, BUCKET_PTE(pages));
 #ifndef CONFIG_SUN4	
 	sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
@@ -1344,7 +1166,7 @@
 	sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 #endif
 	sun4c_bucket[entry] = BUCKET_EMPTY;
-	if(entry < sun4c_lowbucket_avail)
+	if (entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
 
 	free_pages(pages, TASK_STRUCT_ORDER);
@@ -1367,7 +1189,7 @@
 	sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 #endif
 	sun4c_bucket[entry] = BUCKET_EMPTY;
-	if(entry < sun4c_lowbucket_avail)
+	if (entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
 
 	free_pages(pages, TASK_STRUCT_ORDER);
@@ -1378,10 +1200,10 @@
 {
 	int entry;
 
-	if(sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
+	if (sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
 		prom_printf("task union not %d page(s)!\n", 1 << TASK_STRUCT_ORDER);
 	}
-	for(entry = 0; entry < NR_TASK_BUCKETS; entry++)
+	for (entry = 0; entry < NR_TASK_BUCKETS; entry++)
 		sun4c_bucket[entry] = BUCKET_EMPTY;
 	sun4c_lowbucket_avail = 0;
 }
@@ -1501,7 +1323,7 @@
 	unsigned long page;
 
 	page = ((unsigned long)bufptr) & PAGE_MASK;
-	if(MAP_NR(page) > max_mapnr) {
+	if (MAP_NR(page) > max_mapnr) {
 		sun4c_flush_page(page);
 		return (__u32)bufptr; /* already locked */
 	}
@@ -1510,7 +1332,7 @@
 
 static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-	while(sz >= 0) {
+	while (sz >= 0) {
 		sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len);
 		sz--;
 	}
@@ -1518,14 +1340,14 @@
 
 static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus)
 {
-	if(bufptr < sun4c_iobuffer_start)
+	if (bufptr < sun4c_iobuffer_start)
 		return; /* On kernel stack or similar, see above */
 	sun4c_unlockarea((char *)bufptr, len);
 }
 
 static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-	while(sz >= 0) {
+	while (sz >= 0) {
 		sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len);
 		sz--;
 	}
@@ -1546,7 +1368,7 @@
 	sun4c_taskstack_start = SUN4C_LOCK_VADDR;
 	sun4c_taskstack_end = (sun4c_taskstack_start +
 			       (TASK_ENTRY_SIZE * NR_TASK_BUCKETS));
-	if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
+	if (sun4c_taskstack_end >= SUN4C_LOCK_END) {
 		prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n");
 		prom_halt();
 	}
@@ -1576,12 +1398,12 @@
 {
 	unsigned long begin, end;
 
-	FUW_INLINE
+	flush_user_windows();
 	begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE);
 	end = (begin + SUN4C_VAC_SIZE);
 
-	if(sun4c_vacinfo.linesize == 32) {
-		while(begin < end) {
+	if (sun4c_vacinfo.linesize == 32) {
+		while (begin < end) {
 			__asm__ __volatile__("
 			ld	[%0 + 0x00], %%g0
 			ld	[%0 + 0x20], %%g0
@@ -1603,7 +1425,7 @@
 			begin += 512;
 		}
 	} else {
-		while(begin < end) {
+		while (begin < end) {
 			__asm__ __volatile__("
 			ld	[%0 + 0x00], %%g0
 			ld	[%0 + 0x10], %%g0
@@ -1631,29 +1453,31 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		unsigned long flags;
+	if (new_ctx != NO_CONTEXT) {
+		flush_user_windows();
+		if (sun4c_context_ring[new_ctx].num_entries) {
+			struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+			unsigned long flags;
+
+			save_and_cli(flags);
+			if (head->next != head) {
+				struct sun4c_mmu_entry *entry = head->next;
+				int savectx = sun4c_get_context();
+
+				sun4c_set_context(new_ctx);
+				sun4c_flush_context_hw();
+				do {
+					struct sun4c_mmu_entry *next = entry->next;
 
-		save_and_cli(flags);
-		if(head->next != head) {
-			struct sun4c_mmu_entry *entry = head->next;
-			int savectx = sun4c_get_context();
-
-			FUW_INLINE
-			sun4c_set_context(new_ctx);
-			sun4c_flush_context_hw();
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
+					sun4c_user_unmap(entry);
+					free_user_entry(new_ctx, entry);
 
-				entry = next;
-			} while(entry != head);
-			sun4c_set_context(savectx);
+					entry = next;
+				} while (entry != head);
+				sun4c_set_context(savectx);
+			}
+			restore_flags(flags);
 		}
-		restore_flags(flags);
 	}
 }
 
@@ -1661,29 +1485,28 @@
 {
 	int new_ctx = mm->context;
 	
-#if KGPROF_PROFILING
-	kgprof_profile();
-#endif
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+
 		save_and_cli(flags);
 
 		/* All user segmap chains are ordered on entry->vaddr. */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
 		/* Tracing various job mixtures showed that this conditional
 		 * only passes ~35% of the time for most worse case situations,
 		 * therefore we avoid all of this gross overhead ~65% of the time.
 		 */
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
+
 			sun4c_set_context(new_ctx);
 
 			/* At this point, always, (start >= entry->vaddr) and
@@ -1698,11 +1521,11 @@
 
 				/* "realstart" is always >= entry->vaddr */
 				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-				if(end < realend)
+				if (end < realend)
 					realend = end;
-				if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
 					unsigned long page = entry->vaddr;
-					while(page < realend) {
+					while (page < realend) {
 						sun4c_flush_page_hw(page);
 						page += PAGE_SIZE;
 					}
@@ -1712,14 +1535,13 @@
 					free_user_entry(new_ctx, entry);
 				}
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
 	}
 }
 
-/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */
 static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
@@ -1728,76 +1550,84 @@
 	/* Sun4c has no separate I/D caches so cannot optimize for non
 	 * text page flushes.
 	 */
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int octx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		sun4c_flush_page_hw(page);
 		sun4c_set_context(octx);
+		restore_flags(flags);
 	}
 }
 
 static void sun4c_flush_page_to_ram_hw(unsigned long page)
 {
+	unsigned long flags;
+
+	save_and_cli(flags);
 	sun4c_flush_page_hw(page);
+	restore_flags(flags);
 }
 
 static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		unsigned long flags;
+	if (new_ctx != NO_CONTEXT) {
+		flush_user_windows();
 
-		save_and_cli(flags);
-		if(head->next != head) {
-			struct sun4c_mmu_entry *entry = head->next;
-			int savectx = sun4c_get_context();
-
-			FUW_INLINE
-			sun4c_set_context(new_ctx);
-			sun4c_flush_context_sw();
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
+		if (sun4c_context_ring[new_ctx].num_entries) {
+			struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+			unsigned long flags;
+
+			save_and_cli(flags);
+			if (head->next != head) {
+				struct sun4c_mmu_entry *entry = head->next;
+				int savectx = sun4c_get_context();
+
+				sun4c_set_context(new_ctx);
+				sun4c_flush_context_sw();
+				do {
+					struct sun4c_mmu_entry *next = entry->next;
 
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
+					sun4c_user_unmap(entry);
+					free_user_entry(new_ctx, entry);
 
-				entry = next;
-			} while(entry != head);
-			sun4c_set_context(savectx);
+					entry = next;
+				} while (entry != head);
+				sun4c_set_context(savectx);
+			}
+			restore_flags(flags);
 		}
-		restore_flags(flags);
 	}
 }
 
 static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
 	int new_ctx = mm->context;
-	
-#if KGPROF_PROFILING
-	kgprof_profile();
-#endif
-	if(new_ctx != NO_CONTEXT) {
+
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+
 		save_and_cli(flags);
 		/* All user segmap chains are ordered on entry->vaddr. */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
 		/* Tracing various job mixtures showed that this conditional
 		 * only passes ~35% of the time for most worse case situations,
 		 * therefore we avoid all of this gross overhead ~65% of the time.
 		 */
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
 			sun4c_set_context(new_ctx);
 
@@ -1813,11 +1643,11 @@
 
 				/* "realstart" is always >= entry->vaddr */
 				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-				if(end < realend)
+				if (end < realend)
 					realend = end;
-				if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
 					unsigned long page = entry->vaddr;
-					while(page < realend) {
+					while (page < realend) {
 						sun4c_flush_page_sw(page);
 						page += PAGE_SIZE;
 					}
@@ -1827,7 +1657,7 @@
 					free_user_entry(new_ctx, entry);
 				}
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
@@ -1842,19 +1672,26 @@
 	/* Sun4c has no separate I/D caches so cannot optimize for non
 	 * text page flushes.
 	 */
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int octx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		sun4c_flush_page_sw(page);
 		sun4c_set_context(octx);
+		restore_flags(flags);
 	}
 }
 
 static void sun4c_flush_page_to_ram_sw(unsigned long page)
 {
+	unsigned long flags;
+
+	save_and_cli(flags);
 	sun4c_flush_page_sw(page);
+	restore_flags(flags);
 }
 
 /* Sun4c cache is unified, both instructions and data live there, so
@@ -1881,8 +1718,11 @@
 	flush_user_windows();
 	while (sun4c_kernel_ring.num_entries) {
 		next_entry = this_entry->next;
-		sun4c_flush_segment(this_entry->vaddr);
-		for(ctx = 0; ctx < num_contexts; ctx++) {
+		if (sun4c_vacinfo.do_hwflushes)
+			sun4c_flush_segment_hw(this_entry->vaddr);
+		else
+			sun4c_flush_segment_sw(this_entry->vaddr);
+		for (ctx = 0; ctx < num_contexts; ctx++) {
 			sun4c_set_context(ctx);
 			sun4c_put_segmap(this_entry->vaddr, invalid_segment);
 		}
@@ -1897,16 +1737,15 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		unsigned long flags;
 
 		save_and_cli(flags);
-		if(head->next != head) {
+		if (head->next != head) {
 			struct sun4c_mmu_entry *entry = head->next;
 			int savectx = sun4c_get_context();
 
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			sun4c_flush_context_hw();
 			do {
@@ -1916,7 +1755,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while(entry != head);
+			} while (entry != head);
 			sun4c_set_context(savectx);
 		}
 		restore_flags(flags);
@@ -1927,26 +1766,21 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
-#if KGPROF_PROFILING
-		kgprof_profile();
-#endif
 
 		save_and_cli(flags);
 		/* See commentary in sun4c_flush_cache_range_*(). */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
 
-			/* This window flush is paranoid I think... -DaveM */
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
@@ -1956,7 +1790,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
@@ -1968,15 +1802,17 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int savectx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
 		sun4c_flush_page_hw(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
+		restore_flags(flags);
 	}
 }
 
@@ -1984,16 +1820,15 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		unsigned long flags;
 
 		save_and_cli(flags);
-		if(head->next != head) {
+		if (head->next != head) {
 			struct sun4c_mmu_entry *entry = head->next;
 			int savectx = sun4c_get_context();
 
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			sun4c_flush_context_sw();
 			do {
@@ -2003,7 +1838,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while(entry != head);
+			} while (entry != head);
 			sun4c_set_context(savectx);
 		}
 		restore_flags(flags);
@@ -2014,27 +1849,21 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
 
-#if KGPROF_PROFILING
-		kgprof_profile();
-#endif
-
 		save_and_cli(flags);
 		/* See commentary in sun4c_flush_cache_range_*(). */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
 
-			/* This window flush is paranoid I think... -DaveM */
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
@@ -2044,7 +1873,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
@@ -2056,15 +1885,17 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int savectx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
 		sun4c_flush_page_sw(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
+		restore_flags(flags);
 	}
 }
 
@@ -2077,7 +1908,6 @@
 {
 }
 
-
 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
 		     int bus_type, int rdonly)
 {
@@ -2085,7 +1915,7 @@
 
 	page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
 	page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
-	if(rdonly)
+	if (rdonly)
 		page_entry &= ~_SUN4C_WRITEABLE;
 	sun4c_put_pte(virt_addr, page_entry);
 }
@@ -2100,7 +1930,7 @@
 	struct ctx_list *ctxp;
 
 	ctxp = ctx_free.next;
-	if(ctxp != &ctx_free) {
+	if (ctxp != &ctx_free) {
 		remove_from_ctx_list(ctxp);
 		add_to_used_ctxlist(ctxp);
 		mm->context = ctxp->ctx_number;
@@ -2108,26 +1938,22 @@
 		return;
 	}
 	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == current->mm)
+	if (ctxp->ctx_mm == current->mm)
 		ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
-	if(ctxp == &ctx_used)
-		panic("out of mmu contexts");
-#endif
 	remove_from_ctx_list(ctxp);
 	add_to_used_ctxlist(ctxp);
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
 	sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
-			    ctxp->ctx_number);
+			       ctxp->ctx_number);
 }
 
 static void sun4c_switch_to_context_hw(struct task_struct *tsk)
 {
 	struct ctx_list *ctx;
 
-	if(tsk->mm->context == NO_CONTEXT) {
+	if (tsk->mm->context == NO_CONTEXT) {
 		sun4c_alloc_context_hw(tsk->mm);
 	} else {
 		/* Update the LRU ring of contexts. */
@@ -2141,7 +1967,7 @@
 static void sun4c_init_new_context_hw(struct mm_struct *mm)
 {
 	sun4c_alloc_context_hw(mm);
-	if(mm == current->mm)
+	if (mm == current->mm)
 		sun4c_set_context(mm->context);
 }
 
@@ -2149,7 +1975,7 @@
 {
 	struct ctx_list *ctx_old;
 
-	if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+	if (mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
 		sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
@@ -2163,7 +1989,7 @@
 	struct ctx_list *ctxp;
 
 	ctxp = ctx_free.next;
-	if(ctxp != &ctx_free) {
+	if (ctxp != &ctx_free) {
 		remove_from_ctx_list(ctxp);
 		add_to_used_ctxlist(ctxp);
 		mm->context = ctxp->ctx_number;
@@ -2171,26 +1997,22 @@
 		return;
 	}
 	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == current->mm)
+	if (ctxp->ctx_mm == current->mm)
 		ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
-	if(ctxp == &ctx_used)
-		panic("out of mmu contexts");
-#endif
 	remove_from_ctx_list(ctxp);
 	add_to_used_ctxlist(ctxp);
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
 	sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
-			    ctxp->ctx_number);
+			       ctxp->ctx_number);
 }
 
 static void sun4c_switch_to_context_sw(struct task_struct *tsk)
 {
 	struct ctx_list *ctx;
 
-	if(tsk->mm->context == NO_CONTEXT) {
+	if (tsk->mm->context == NO_CONTEXT) {
 		sun4c_alloc_context_sw(tsk->mm);
 	} else {
 		/* Update the LRU ring of contexts. */
@@ -2204,7 +2026,7 @@
 static void sun4c_init_new_context_sw(struct mm_struct *mm)
 {
 	sun4c_alloc_context_sw(mm);
-	if(mm == current->mm)
+	if (mm == current->mm)
 		sun4c_set_context(mm->context);
 }
 
@@ -2212,7 +2034,7 @@
 {
 	struct ctx_list *ctx_old;
 
-	if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+	if (mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
 		sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
@@ -2227,7 +2049,7 @@
 	int len;
 
 	used_user_entries = 0;
-	for(i=0; i < num_contexts; i++)
+	for (i = 0; i < num_contexts; i++)
 		used_user_entries += sun4c_context_ring[i].num_entries;
 
 	len = sprintf(buf, 
@@ -2241,10 +2063,7 @@
 		"usedpsegs\t: %d\n"
 		"ufreepsegs\t: %d\n"
 		"user_taken\t: %d\n"
-		"max_taken\t: %d\n"
-		"context\t\t: %d flushes\n"
-		"segment\t\t: %d flushes\n"
-		"page\t\t: %d flushes\n",
+		"max_taken\t: %d\n",
 		sun4c_vacinfo.num_bytes,
 		(sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
 		sun4c_vacinfo.linesize,
@@ -2255,22 +2074,7 @@
 		used_user_entries,
 		sun4c_ufree_ring.num_entries,
 		sun4c_user_taken_entries,
-		max_user_taken_entries,
-		ctxflushes, segflushes, pageflushes);
-
-#if KGPROF_PROFILING
-	{
-		int i,j;
-		len += sprintf(buf + len,"kgprof profiling:\n");
-		for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-			len += sprintf(buf + len,"%5d  ",kgprof_counters[i].count);
-			for (j=0;j<KGPROF_DEPTH;j++) {
-				len += sprintf(buf + len,"%08x ",kgprof_counters[i].addr[j]);
-			}
-			len += sprintf(buf + len,"\n");
-		}
-	}
-#endif
+		max_user_taken_entries);
 
 	return len;
 }
@@ -2279,13 +2083,6 @@
  * data structures.
  */
 
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
-#endif
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
-#endif
-
 /* First the functions which the mid-level code uses to directly
  * manipulate the software page tables.  Some defines since we are
  * emulating the i386 page directory layout.
@@ -2297,17 +2094,6 @@
 #define PGD_DIRTY    0x040
 #define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
 
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned long sun4c_vmalloc_start(void)
-{
-	return SUN4C_VMALLOC_START;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_none(pte_t pte)		{ return !pte_val(pte); }
-#endif
-
 static int sun4c_pte_present(pte_t pte)
 {
 	return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
@@ -2336,48 +2122,6 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_write(pte_t pte)
-{
-	return pte_val(pte) & _SUN4C_PAGE_WRITE;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_dirty(pte_t pte)
-{
-	return pte_val(pte) & _SUN4C_PAGE_MODIFIED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_young(pte_t pte)
-{
-	return pte_val(pte) & _SUN4C_PAGE_ACCESSED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_wrprotect(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~(_SUN4C_PAGE_WRITE | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkclean(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~(_SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkold(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~(_SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_SILENT_READ));
-}
-#endif
-
 static pte_t sun4c_pte_mkwrite(pte_t pte)
 {
 	pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE);
@@ -2421,14 +2165,6 @@
 	return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
-{
-	return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) |
-		     pgprot_val(newprot));
-}
-#endif
-
 static unsigned long sun4c_pte_page(pte_t pte)
 {
 	return (PAGE_OFFSET + ((pte_val(pte) & SUN4C_PFN_MASK) << (PAGE_SHIFT)));
@@ -2489,7 +2225,7 @@
 
 static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
-	if(address >= SUN4C_LOCK_VADDR)
+	if (address >= SUN4C_LOCK_VADDR)
 		return NULL;
 	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 	if (sun4c_pmd_none(*pmd))
@@ -2529,7 +2265,7 @@
 {
 	unsigned long *ret;
 
-	if((ret = pgd_quicklist) != NULL) {
+	if ((ret = pgd_quicklist) != NULL) {
 		pgd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
 		pgtable_cache_size--;
@@ -2548,15 +2284,15 @@
 static int sun4c_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
-	if(pgtable_cache_size > high) {
+	if (pgtable_cache_size > high) {
 		do {
-			if(pgd_quicklist)
+			if (pgd_quicklist)
 				free_pgd_slow(get_pgd_fast()), freed++;
-			if(pmd_quicklist)
+			if (pmd_quicklist)
 				free_pmd_slow(get_pmd_fast()), freed++;
-			if(pte_quicklist)
+			if (pte_quicklist)
 				free_pte_slow(get_pte_fast()), freed++;
-		} while(pgtable_cache_size > low);
+		} while (pgtable_cache_size > low);
 	}
 	return freed;
 }
@@ -2577,7 +2313,7 @@
 {
 	unsigned long *ret;
 
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
 		pgtable_cache_size--;
@@ -2680,9 +2416,9 @@
 
 	if (vma->vm_file)
 		dentry = vma->vm_file->f_dentry;
-	if(dentry)
+	if (dentry)
 		inode = dentry->d_inode;
-	if(inode) {
+	if (inode) {
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
 		struct vm_area_struct *vmaring = inode->i_mmap; 
 		int alias_found = 0;
@@ -2691,19 +2427,21 @@
 			unsigned long start;
 
 			/* Do not mistake ourselves as another mapping. */
-			if(vmaring == vma)
+			if (vmaring == vma)
 				continue;
 
 			if (S4CVAC_BADALIAS(vaddr, address)) {
 				alias_found++;
 				start = vmaring->vm_start;
-				while(start < vmaring->vm_end) {
+				while (start < vmaring->vm_end) {
 					pgdp = sun4c_pgd_offset(vmaring->vm_mm, start);
-					if(!pgdp) goto next;
+					if (!pgdp)
+						goto next;
 					ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
-					if(!ptep) goto next;
+					if (!ptep)
+						goto next;
 
-					if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
+					if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
 						flush_cache_page(vmaring, start);
 						*ptep = __pte(pte_val(*ptep) |
 							      _SUN4C_PAGE_NOCACHE);
@@ -2715,7 +2453,7 @@
 			}
 		} while ((vmaring = vmaring->vm_next_share) != NULL);
 
-		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
+		if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = sun4c_pgd_offset(vma->vm_mm, address);
 			ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
 			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
@@ -2724,16 +2462,62 @@
 	}
 }
 
+/* An experiment, turn off by default for now... -DaveM */
+#define SUN4C_PRELOAD_PSEG
+
 void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 	unsigned long flags;
+	int pseg;
 
 	save_and_cli(flags);
 	address &= PAGE_MASK;
-	if(sun4c_get_segmap(address) == invalid_segment)
-		alloc_user_segment(address, sun4c_get_context());
+	if ((pseg = sun4c_get_segmap(address)) == invalid_segment) {
+		struct sun4c_mmu_entry *entry = sun4c_user_strategy();
+		struct mm_struct *mm = vma->vm_mm;
+		unsigned long start, end;
+
+		entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK);
+		entry->ctx = mm->context;
+		add_ring_ordered(sun4c_context_ring + mm->context, entry);
+		sun4c_put_segmap(entry->vaddr, entry->pseg);
+		end = start + SUN4C_REAL_PGDIR_SIZE;
+		while (start < end) {
+#ifdef SUN4C_PRELOAD_PSEG
+			pgd_t *pgdp = sun4c_pgd_offset(mm, start);
+			pte_t *ptep;
+
+			if (!pgdp)
+				goto no_mapping;
+			ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
+			if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT))
+				goto no_mapping;
+			sun4c_put_pte(start, pte_val(*ptep));
+			goto next;
+
+		no_mapping:
+#endif
+			sun4c_put_pte(start, 0);
+#ifdef SUN4C_PRELOAD_PSEG
+		next:
+#endif
+			start += PAGE_SIZE;
+		}
+		if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+			sun4c_vac_alias_fixup(vma, address, pte);
+#ifndef SUN4C_PRELOAD_PSEG
+		sun4c_put_pte(address, pte_val(pte));
+#endif
+		restore_flags(flags);
+		return;
+	} else {
+		struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg];
+
+		remove_lru(entry);
+		add_lru(entry);
+	}
 
-	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+	if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
 		sun4c_vac_alias_fixup(vma, address, pte);
 
 	sun4c_put_pte(address, pte_val(pte));
@@ -2786,8 +2570,8 @@
 	start_mem = sparc_context_init(start_mem, num_contexts);
 	start_mem = free_area_init(start_mem, end_mem);
 	cnt = 0;
-	for(i = 0; i < num_segmaps; i++)
-		if(mmu_entry_pool[i].locked)
+	for (i = 0; i < num_segmaps; i++)
+		if (mmu_entry_pool[i].locked)
 			cnt++;
 
 	max_user_taken_entries = num_segmaps - cnt - 40 - 1;
@@ -2839,7 +2623,7 @@
 
 	BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
 
-	if(sun4c_vacinfo.do_hwflushes) {
+	if (sun4c_vacinfo.do_hwflushes) {
 		BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
 		BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
 		BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)