summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2009-07-29 23:17:20 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2009-08-16 14:26:56 -0700
commit2614443191474e4c8619bf59665f9ef820e5276c (patch)
tree2420f887cc21cde58b8e18c897808990c226cf45 /include
parent04101e4e4ef4ff5035ce5ad4510db02eb54c4985 (diff)
parisc: ensure broadcast tlb purge runs single threaded
commit e82a3b75127188f20c7780bec580e148beb29da7 upstream parisc: ensure broadcast tlb purge runs single threaded The TLB flushing functions on hppa, which causes PxTLB broadcasts on the system bus, needs to be protected by irq-safe spinlocks to avoid irq handlers to deadlock the kernel. The deadlocks only happened during I/O intensive loads and triggered pretty seldom, which is why this bug went so long unnoticed. Signed-off-by: Helge Deller <deller@gmx.de> [edited to use spin_lock_irqsave on UP as well since we'd been locking there all this time anyway, --kyle] Signed-off-by: Kyle McMartin <kyle@mcmartin.ca> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'include')
-rw-r--r--include/asm-parisc/tlbflush.h13
1 files changed, 6 insertions, 7 deletions
diff --git a/include/asm-parisc/tlbflush.h b/include/asm-parisc/tlbflush.h
index 1f6fd4fc05b9..9c5d646eb3fe 100644
--- a/include/asm-parisc/tlbflush.h
+++ b/include/asm-parisc/tlbflush.h
@@ -12,14 +12,12 @@
* 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. We also need to have
- * preemption disabled on uniprocessor machines, and spin_lock does that
- * nicely.
+ * it on all systems not just the N class.
*/
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)
+#define purge_tlb_start(flags) spin_lock_irqsave(&pa_tlb_lock, flags)
+#define purge_tlb_end(flags) spin_unlock_irqrestore(&pa_tlb_lock, flags)
extern void flush_tlb_all(void);
extern void flush_tlb_all_local(void *);
@@ -63,14 +61,15 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr)
{
+ unsigned long flags;
/* For one page, it's not worth testing the split_tlb variable */
mb();
mtsp(vma->vm_mm->context,1);
- purge_tlb_start();
+ purge_tlb_start(flags);
pdtlb(addr);
pitlb(addr);
- purge_tlb_end();
+ purge_tlb_end(flags);
}
void __flush_tlb_range(unsigned long sid,