[parisc-linux-cvs] linux-2.6 jejb

James Bottomley James.Bottomley at SteelEye.com
Wed Aug 18 14:44:14 MDT 2004


On Wed, 2004-08-18 at 16:21, James Bottomley wrote:
> CVSROOT:	/var/cvs
> Module name:	linux-2.6
> Changes by:	jejb	04/08/18 14:21:41
> 
> Modified files:
> 	.              : Makefile 
> 	arch/parisc/kernel: cache.c pacache.S pci-dma.c smp.c 
> 	include/asm-parisc: system.h tlbflush.h 
> 
> Log message:
> Fix N class SMP
> 
> I've been working on this with Randolph, so most of these fixes are
> actually his...
> 
> The main fixes are:
> 
> - memory barriers to our space and control register moves
> - fix for the N class merced bus problem which can't have more than
> one PxTLB broadcast outstanding at once
> - make smp_call_function() wait until the function completes
> 
> This now boots and runs on a 32MB N4000 in Fort Collins with 2 cpus
> and discontig mem support.

Index: arch/parisc/kernel/cache.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/cache.c,v
retrieving revision 1.19
diff -u -r1.19 cache.c
--- arch/parisc/kernel/cache.c	10 Jul 2004 07:51:15 -0000	1.19
+++ arch/parisc/kernel/cache.c	18 Aug 2004 19:39:23 -0000
@@ -33,6 +33,17 @@
 int icache_stride;
 EXPORT_SYMBOL(dcache_stride);
 
+
+#if defined(CONFIG_SMP)
+/* On some machines (e.g. ones with the Merced bus), there can be
+ * only a single PxTLB broadcast at a time; this must be guaranteed
+ * by software.  We put a spinlock around all TLB flushes  to
+ * ensure this.
+ */
+spinlock_t pa_tlb_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(pa_tlb_lock);
+#endif
+
 struct pdc_cache_info cache_info;
 #ifndef CONFIG_PA20
 static struct pdc_btlb_info btlb_info;
@@ -307,3 +318,13 @@
 EXPORT_SYMBOL(flush_kernel_dcache_page);
 EXPORT_SYMBOL(flush_data_cache_local);
 EXPORT_SYMBOL(flush_kernel_icache_range_asm);
+
+void clear_user_page_asm(void *page, unsigned long vaddr)
+{
+	/* This function is implemented in assembly in pacache.S */
+	extern void __clear_user_page_asm(void *page, unsigned long vaddr);
+
+	purge_tlb_start();
+	__clear_user_page_asm(page, vaddr);
+	purge_tlb_end();
+}
Index: arch/parisc/kernel/pacache.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/pacache.S,v
retrieving revision 1.8
diff -u -r1.8 pacache.S
--- arch/parisc/kernel/pacache.S	17 Aug 2004 19:01:57 -0000	1.8
+++ arch/parisc/kernel/pacache.S	18 Aug 2004 19:39:24 -0000
@@ -475,9 +475,9 @@
 	.procend
 #endif
 
-	.export clear_user_page_asm,code
+	.export __clear_user_page_asm,code
 
-clear_user_page_asm:
+__clear_user_page_asm:
 	.proc
 	.callinfo NO_CALLS
 	.entry
Index: arch/parisc/kernel/pci-dma.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/pci-dma.c,v
retrieving revision 1.5
diff -u -r1.5 pci-dma.c
--- arch/parisc/kernel/pci-dma.c	30 May 2004 18:57:23 -0000	1.5
+++ arch/parisc/kernel/pci-dma.c	18 Aug 2004 19:39:25 -0000
@@ -104,7 +104,9 @@
 		if (!pte_none(*pte))
 			printk(KERN_ERR "map_pte_uncached: page already exists\n");
 		set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
+		purge_tlb_start();
 		pdtlb_kernel(orig_vaddr);
+		purge_tlb_end();
 		vaddr += PAGE_SIZE;
 		orig_vaddr += PAGE_SIZE;
 		(*paddr_ptr) += PAGE_SIZE;
@@ -179,7 +181,9 @@
 	do {
 		pte_t page = *pte;
 		pte_clear(pte);
+		purge_tlb_start();
 		pdtlb_kernel(orig_vaddr);
+		purge_tlb_end();
 		vaddr += PAGE_SIZE;
 		orig_vaddr += PAGE_SIZE;
 		pte++;
Index: arch/parisc/kernel/smp.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/smp.c,v
retrieving revision 1.12
diff -u -r1.12 smp.c
--- arch/parisc/kernel/smp.c	30 Jul 2004 21:53:39 -0000	1.12
+++ arch/parisc/kernel/smp.c	18 Aug 2004 19:39:25 -0000
@@ -333,6 +333,7 @@
 	struct smp_call_struct data;
 	unsigned long timeout;
 	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	int retries = 0;
 
 	if (num_online_cpus() < 2)
 		return 0;
@@ -365,21 +366,22 @@
 	/*  Send a message to all other CPUs and wait for them to respond  */
 	send_IPI_allbutself(IPI_CALL_FUNC);
 
+ retry:
 	/*  Wait for response  */
 	timeout = jiffies + HZ;
 	while ( (atomic_read (&data.unstarted_count) > 0) &&
 		time_before (jiffies, timeout) )
 		barrier ();
 
+	if (atomic_read (&data.unstarted_count) > 0) {
+		printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d), try %d\n",
+		      smp_processor_id(), ++retries);
+		goto retry;
+	}
 	/* We either got one or timed out. Release the lock */
 
 	mb();
 	smp_call_function_data = NULL;
-	if (atomic_read (&data.unstarted_count) > 0) {
-		printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d)\n",
-		      smp_processor_id());
-		return -ETIMEDOUT;
-	}
 
 	while (wait && atomic_read (&data.unfinished_count) > 0)
 			barrier ();
Index: include/asm-parisc/system.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/system.h,v
retrieving revision 1.6
diff -u -r1.6 system.h
--- include/asm-parisc/system.h	17 Aug 2004 01:14:44 -0000	1.6
+++ include/asm-parisc/system.h	18 Aug 2004 19:39:44 -0000
@@ -80,7 +80,7 @@
 #define mtctl(gr, cr) \
 	__asm__ __volatile__("mtctl %0,%1" \
 		: /* no outputs */ \
-		: "r" (gr), "i" (cr))
+		: "r" (gr), "i" (cr) : "memory")
 
 /* these are here to de-mystefy the calling code, and to provide hooks */
 /* which I needed for debugging EIEM problems -PB */
@@ -102,7 +102,7 @@
 #define mtsp(gr, cr) \
 	__asm__ __volatile__("mtsp %0,%1" \
 		: /* no outputs */ \
-		: "r" (gr), "i" (cr))
+		: "r" (gr), "i" (cr) : "memory")
 

 /*
@@ -183,5 +183,23 @@
 #endif
 
 #define KERNEL_START (0x10100000 - 0x1000)
+
+/* This is for the serialisation of PxTLB broadcasts.  At least on the
+ * N class systems, only one PxTLB inter processor broadcast can be
+ * active at any one time on the Merced bus.  This tlb purge
+ * synchronisation is fairly lightweight and harmless so we activate
+ * it on all SMP systems not just the N class. */
+#ifdef CONFIG_SMP
+extern spinlock_t pa_tlb_lock;
+
+#define purge_tlb_start(x) spin_lock(&pa_tlb_lock)
+#define purge_tlb_end(x) spin_unlock(&pa_tlb_lock)
+
+#else
+
+#define purge_tlb_start(x) do { } while(0)
+#define purge_tlb_end(x) do { } while (0)
+
+#endif
 
 #endif
Index: include/asm-parisc/tlbflush.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/tlbflush.h,v
retrieving revision 1.3
diff -u -r1.3 tlbflush.h
--- include/asm-parisc/tlbflush.h	27 Jan 2004 18:46:14 -0000	1.3
+++ include/asm-parisc/tlbflush.h	18 Aug 2004 19:39:44 -0000
@@ -51,9 +51,12 @@
 {
 	/* For one page, it's not worth testing the split_tlb variable */
 
+	mb();
 	mtsp(vma->vm_mm->context,1);
+	purge_tlb_start();
 	pdtlb(addr);
 	pitlb(addr);
+	purge_tlb_end();
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
@@ -61,6 +64,7 @@
 {
 	unsigned long npages;
 
+	
 	npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 	if (npages >= 512)  /* XXX arbitrary, should be tuned */
 		flush_tlb_all();
@@ -68,16 +72,20 @@
 
 		mtsp(vma->vm_mm->context,1);
 		if (split_tlb) {
+			purge_tlb_start();
 			while (npages--) {
 				pdtlb(start);
 				pitlb(start);
 				start += PAGE_SIZE;
 			}
+			purge_tlb_end();
 		} else {
+			purge_tlb_start();
 			while (npages--) {
 				pdtlb(start);
 				start += PAGE_SIZE;
 			}
+			purge_tlb_end();
 		}
 	}
 }



More information about the parisc-linux-cvs mailing list