[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