patch-2.4.0-test9 linux/arch/sh/mm/cache.c

Next file: linux/arch/sh/mm/fault.c
Previous file: linux/arch/sh/lib/checksum.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
@@ -64,9 +64,9 @@
 #define CACHE_IC_WAY_SHIFT       13
 #define CACHE_OC_ENTRY_SHIFT      5
 #define CACHE_IC_ENTRY_SHIFT      5
-#define CACHE_OC_ENTRY_MASK  0x3fe0
-#define CACHE_OC_ENTRY_PHYS_MASK  0x0fe0
-#define CACHE_IC_ENTRY_MASK  0x1fe0
+#define CACHE_OC_ENTRY_MASK		0x3fe0
+#define CACHE_OC_ENTRY_PHYS_MASK	0x0fe0
+#define CACHE_IC_ENTRY_MASK		0x1fe0
 #define CACHE_IC_NUM_ENTRIES	256
 #define CACHE_OC_NUM_ENTRIES	512
 #define CACHE_OC_NUM_WAYS	  1
@@ -92,7 +92,8 @@
 			addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
 				(i<<CACHE_OC_ENTRY_SHIFT);
 			data = ctrl_inl(addr);
-			if (data & CACHE_UPDATED) {
+			if ((data & (CACHE_UPDATED|CACHE_VALID))
+			    == (CACHE_UPDATED|CACHE_VALID)) {
 				data &= ~CACHE_UPDATED;
 				ctrl_outl(data, addr);
 			}
@@ -114,17 +115,25 @@
 	 */
 	addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
 	addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
+
+	/* First, write back & invalidate */
 	data0  = ctrl_inl(addr0);
-	data0  ^= 0x00000001;
-	ctrl_outl(data0,addr0);
+	ctrl_outl(data0&~(CACHE_VALID|CACHE_UPDATED), addr0);
+	data1  = ctrl_inl(addr1);
+	ctrl_outl(data1&~(CACHE_VALID|CACHE_UPDATED), addr1);
+
+	/* Next, check if there's shadow or not */
+	data0 = ctrl_inl(addr0);
+	data0 ^= CACHE_VALID;
+	ctrl_outl(data0, addr0);
 	data1 = ctrl_inl(addr1);
-	data2 = data1 ^ 0x00000001;
-	ctrl_outl(data2,addr1);
+	data2 = data1 ^ CACHE_VALID;
+	ctrl_outl(data2, addr1);
 	data3 = ctrl_inl(addr0);
 
-	/* Invaliate them, in case the cache has been enabled already. */
-	ctrl_outl(data0&~0x00000001, addr0);
-	ctrl_outl(data2&~0x00000001, addr1);
+	/* Lastly, invaliate them. */
+	ctrl_outl(data0&~CACHE_VALID, addr0);
+	ctrl_outl(data2&~CACHE_VALID, addr1);
 	back_to_P1();
 
 	if (data0 == data1 && data2 == data3) {	/* Shadow */
@@ -150,8 +159,6 @@
 	detect_cpu_and_cache_system();
 
 	ccr = ctrl_inl(CCR);
-	if (ccr == CCR_CACHE_VAL)
-		return;
 	jump_to_P2();
 	if (ccr & CCR_CACHE_ENABLE)
 		/*
@@ -380,29 +387,114 @@
 }
 
 /*
+ * Write-back & invalidate the cache.
+ *
  * After accessing the memory from kernel space (P1-area), we need to 
- * write back the cache line to maintain DMA coherency.
+ * write back the cache line.
  *
  * We search the D-cache to see if we have the entries corresponding to
  * the page, and if found, write back them.
  */
+void __flush_page_to_ram(void *kaddr)
+{
+	unsigned long phys, addr, data, i;
+
+	/* Physical address of this page */
+	phys = PHYSADDR(kaddr);
+
+	jump_to_P2();
+	/* Loop all the D-cache */
+	for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
+		addr = CACHE_OC_ADDRESS_ARRAY| (i<<CACHE_OC_ENTRY_SHIFT);
+		data = ctrl_inl(addr);
+		if ((data & CACHE_VALID) && (data&PAGE_MASK) == phys) {
+			data &= ~(CACHE_UPDATED|CACHE_VALID);
+			ctrl_outl(data, addr);
+		}
+	}
+	back_to_P1();
+}
+
 void flush_page_to_ram(struct page *pg)
 {
+	unsigned long phys;
+
+	/* Physical address of this page */
+	phys = (pg - mem_map)*PAGE_SIZE + __MEMORY_START;
+	__flush_page_to_ram(phys_to_virt(phys));
+}
+
+/*
+ * Check entries of the I-cache & D-cache of the page.
+ * (To see "alias" issues)
+ */
+void check_cache_page(struct page *pg)
+{
 	unsigned long phys, addr, data, i;
+	unsigned long kaddr;
+	unsigned long cache_line_index;
+	int bingo = 0;
 
 	/* Physical address of this page */
 	phys = (pg - mem_map)*PAGE_SIZE + __MEMORY_START;
+	kaddr = phys + PAGE_OFFSET;
+	cache_line_index = (kaddr&CACHE_OC_ENTRY_MASK)>>CACHE_OC_ENTRY_SHIFT;
 
 	jump_to_P2();
 	/* Loop all the D-cache */
 	for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
 		addr = CACHE_OC_ADDRESS_ARRAY| (i<<CACHE_OC_ENTRY_SHIFT);
 		data = ctrl_inl(addr);
-		if ((data & CACHE_UPDATED) && (data&PAGE_MASK) == phys) {
-			data &= ~CACHE_UPDATED;
+		if ((data & (CACHE_UPDATED|CACHE_VALID))
+		    == (CACHE_UPDATED|CACHE_VALID)
+		    && (data&PAGE_MASK) == phys) {
+			data &= ~(CACHE_VALID|CACHE_UPDATED);
 			ctrl_outl(data, addr);
+			if ((i^cache_line_index)&0x180)
+				bingo = 1;
+		}
+	}
+
+	cache_line_index &= 0xff;
+	/* Loop all the I-cache */
+	for (i=0; i<CACHE_IC_NUM_ENTRIES; i++) {
+		addr = CACHE_IC_ADDRESS_ARRAY| (i<<CACHE_IC_ENTRY_SHIFT);
+		data = ctrl_inl(addr);
+		if ((data & CACHE_VALID) && (data&PAGE_MASK) == phys) {
+			data &= ~CACHE_VALID;
+			ctrl_outl(data, addr);
+			if (((i^cache_line_index)&0x80))
+				bingo = 2;
 		}
 	}
 	back_to_P1();
+
+	if (bingo) {
+		extern void dump_stack(void);
+
+		if (bingo ==1)
+			printk("BINGO!\n");
+		else
+			printk("Bingo!\n");
+		dump_stack();
+		printk("--------------------\n");
+	}
+}
+
+/* Page is 4K, OC size is 16K, there are four lines. */
+#define CACHE_ALIAS 0x00003000
+
+void clear_user_page(void *to, unsigned long address)
+{
+	clear_page(to);
+	if (((address ^ (unsigned long)to) & CACHE_ALIAS))
+		__flush_page_to_ram(to);
+}
+
+void copy_user_page(void *to, void *from, unsigned long address)
+{
+	copy_page(to, from);
+	if (((address ^ (unsigned long)to) & CACHE_ALIAS))
+		__flush_page_to_ram(to);
 }
 #endif

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