patch-2.4.8 linux/arch/cris/mm/tlb.c

Next file: linux/arch/i386/boot/Makefile
Previous file: linux/arch/cris/mm/init.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c
@@ -40,6 +40,10 @@
  *
  * The last page_id is never running - it is used as an invalid page_id
  * so we can make TLB entries that will never match.
+ *
+ * Notice that we need to make the flushes atomic, otherwise an interrupt
+ * handler that uses vmalloced memory might cause a TLB load in the middle
+ * of a flush causing.
  */
 
 struct mm_struct *page_id_map[NUM_PAGEID];
@@ -49,17 +53,18 @@
 /* invalidate all TLB entries */
 
 void
-flush_tlb_all()
+flush_tlb_all(void)
 {
 	int i;
+	unsigned long flags;
 
 	/* the vpn of i & 0xf is so we dont write similar TLB entries
 	 * in the same 4-way entry group. details.. 
 	 */
 
+	save_and_cli(flags); /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
-
 		*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
 			      IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
 		
@@ -69,6 +74,7 @@
 			      IO_STATE(R_TLB_LO, we,    no       ) |
 			      IO_FIELD(R_TLB_LO, pfn,   0        ) );
 	}
+	restore_flags(flags);
 	D(printk("tlb: flushed all\n"));
 }
 
@@ -79,6 +85,7 @@
 {
 	int i;
 	int page_id = mm->context;
+	unsigned long flags;
 
 	D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
 
@@ -90,6 +97,7 @@
 	 * global pages. is it worth the extra I/O ? 
 	 */
 
+	save_and_cli(flags);  /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
 		if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
@@ -103,6 +111,7 @@
 				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
 		}
 	}
+	restore_flags(flags);
 }
 
 /* invalidate a single page */
@@ -114,6 +123,7 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int page_id = mm->context;
 	int i;
+	unsigned long flags;
 
 	D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm));
 
@@ -126,6 +136,7 @@
 	 * and the virtual address requested 
 	 */
 
+	save_and_cli(flags);  /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		unsigned long tlb_hi;
 		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
@@ -142,6 +153,7 @@
 				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
 		}
 	}
+	restore_flags(flags);
 }
 
 /* invalidate a page range */
@@ -153,6 +165,7 @@
 {
 	int page_id = mm->context;
 	int i;
+	unsigned long flags;
 
 	D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
 		 start, end, page_id, mm));
@@ -167,6 +180,7 @@
 	 * and the virtual address range
 	 */
 
+	save_and_cli(flags);  /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		unsigned long tlb_hi, vpn;
 		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
@@ -184,8 +198,30 @@
 				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
 		}
 	}
+	restore_flags(flags);
 }
 
+/* dump the entire TLB for debug purposes */
+
+#if 0
+void
+dump_tlb_all(void)
+{
+	int i;
+	unsigned long flags;
+	
+	printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we  |\n");
+
+	save_and_cli(flags);
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+		printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
+		       i, *R_TLB_HI, *R_TLB_LO);
+	}
+	restore_flags(flags);
+}
+#endif
+
 /*
  * Initialize the context related info for a new mm_struct
  * instance.
@@ -228,8 +264,7 @@
 	map_replace_ptr++;
 
 	if(map_replace_ptr == INVALID_PAGEID)
-		map_replace_ptr = 0;         /* wrap around */
-	
+		map_replace_ptr = 0;         /* wrap around */	
 }
 
 /* 

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