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>
This commit is contained in:
Helge Deller
2009-06-16 20:51:48 +00:00
committed by Kyle McMartin
parent 84be31be37
commit e82a3b7512
3 changed files with 30 additions and 19 deletions

View File

@@ -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++;