summaryrefslogtreecommitdiffstats
path: root/arch/parisc/kernel/pci-dma.c
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2009-06-16 22:51:48 +0200
committerKyle McMartin <kyle@mcmartin.ca>2009-07-03 05:34:09 +0200
commite82a3b75127188f20c7780bec580e148beb29da7 (patch)
tree8a11d55123c20b5341a95941c77eb3d35e4ef9d8 /arch/parisc/kernel/pci-dma.c
parentparisc: fix "delay!" timer handling (diff)
downloadlinux-e82a3b75127188f20c7780bec580e148beb29da7.tar.xz
linux-e82a3b75127188f20c7780bec580e148beb29da7.zip
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>
Diffstat (limited to 'arch/parisc/kernel/pci-dma.c')
-rw-r--r--arch/parisc/kernel/pci-dma.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index 7d927eac932b..c07f618ff7da 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -90,12 +90,14 @@ static inline int map_pte_uncached(pte_t * pte,
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
+ unsigned long flags;
+
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();
+ purge_tlb_start(flags);
pdtlb_kernel(orig_vaddr);
- purge_tlb_end();
+ purge_tlb_end(flags);
vaddr += PAGE_SIZE;
orig_vaddr += PAGE_SIZE;
(*paddr_ptr) += PAGE_SIZE;
@@ -168,11 +170,13 @@ static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr,
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
+ unsigned long flags;
pte_t page = *pte;
+
pte_clear(&init_mm, vaddr, pte);
- purge_tlb_start();
+ purge_tlb_start(flags);
pdtlb_kernel(orig_vaddr);
- purge_tlb_end();
+ purge_tlb_end(flags);
vaddr += PAGE_SIZE;
orig_vaddr += PAGE_SIZE;
pte++;