diff options
author | Helge Deller <deller@gmx.de> | 2009-06-16 16:51:48 -0400 |
---|---|---|
committer | Kyle McMartin <kyle@mcmartin.ca> | 2009-07-02 23:34:09 -0400 |
commit | e82a3b75127188f20c7780bec580e148beb29da7 (patch) | |
tree | 8a11d55123c20b5341a95941c77eb3d35e4ef9d8 /arch/parisc/kernel/cache.c | |
parent | 84be31be3727d11b2a91781306b642e801c5a379 (diff) |
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/cache.c')
-rw-r--r-- | arch/parisc/kernel/cache.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index f34082da009a..b6ed34de14e1 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c | |||
@@ -397,12 +397,13 @@ EXPORT_SYMBOL(flush_kernel_icache_range_asm); | |||
397 | 397 | ||
398 | void clear_user_page_asm(void *page, unsigned long vaddr) | 398 | void clear_user_page_asm(void *page, unsigned long vaddr) |
399 | { | 399 | { |
400 | unsigned long flags; | ||
400 | /* This function is implemented in assembly in pacache.S */ | 401 | /* This function is implemented in assembly in pacache.S */ |
401 | extern void __clear_user_page_asm(void *page, unsigned long vaddr); | 402 | extern void __clear_user_page_asm(void *page, unsigned long vaddr); |
402 | 403 | ||
403 | purge_tlb_start(); | 404 | purge_tlb_start(flags); |
404 | __clear_user_page_asm(page, vaddr); | 405 | __clear_user_page_asm(page, vaddr); |
405 | purge_tlb_end(); | 406 | purge_tlb_end(flags); |
406 | } | 407 | } |
407 | 408 | ||
408 | #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ | 409 | #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ |
@@ -443,20 +444,24 @@ extern void clear_user_page_asm(void *page, unsigned long vaddr); | |||
443 | 444 | ||
444 | void clear_user_page(void *page, unsigned long vaddr, struct page *pg) | 445 | void clear_user_page(void *page, unsigned long vaddr, struct page *pg) |
445 | { | 446 | { |
447 | unsigned long flags; | ||
448 | |||
446 | purge_kernel_dcache_page((unsigned long)page); | 449 | purge_kernel_dcache_page((unsigned long)page); |
447 | purge_tlb_start(); | 450 | purge_tlb_start(flags); |
448 | pdtlb_kernel(page); | 451 | pdtlb_kernel(page); |
449 | purge_tlb_end(); | 452 | purge_tlb_end(flags); |
450 | clear_user_page_asm(page, vaddr); | 453 | clear_user_page_asm(page, vaddr); |
451 | } | 454 | } |
452 | EXPORT_SYMBOL(clear_user_page); | 455 | EXPORT_SYMBOL(clear_user_page); |
453 | 456 | ||
454 | void flush_kernel_dcache_page_addr(void *addr) | 457 | void flush_kernel_dcache_page_addr(void *addr) |
455 | { | 458 | { |
459 | unsigned long flags; | ||
460 | |||
456 | flush_kernel_dcache_page_asm(addr); | 461 | flush_kernel_dcache_page_asm(addr); |
457 | purge_tlb_start(); | 462 | purge_tlb_start(flags); |
458 | pdtlb_kernel(addr); | 463 | pdtlb_kernel(addr); |
459 | purge_tlb_end(); | 464 | purge_tlb_end(flags); |
460 | } | 465 | } |
461 | EXPORT_SYMBOL(flush_kernel_dcache_page_addr); | 466 | EXPORT_SYMBOL(flush_kernel_dcache_page_addr); |
462 | 467 | ||
@@ -489,8 +494,10 @@ void __flush_tlb_range(unsigned long sid, unsigned long start, | |||
489 | if (npages >= 512) /* 2MB of space: arbitrary, should be tuned */ | 494 | if (npages >= 512) /* 2MB of space: arbitrary, should be tuned */ |
490 | flush_tlb_all(); | 495 | flush_tlb_all(); |
491 | else { | 496 | else { |
497 | unsigned long flags; | ||
498 | |||
492 | mtsp(sid, 1); | 499 | mtsp(sid, 1); |
493 | purge_tlb_start(); | 500 | purge_tlb_start(flags); |
494 | if (split_tlb) { | 501 | if (split_tlb) { |
495 | while (npages--) { | 502 | while (npages--) { |
496 | pdtlb(start); | 503 | pdtlb(start); |
@@ -503,7 +510,7 @@ void __flush_tlb_range(unsigned long sid, unsigned long start, | |||
503 | start += PAGE_SIZE; | 510 | start += PAGE_SIZE; |
504 | } | 511 | } |
505 | } | 512 | } |
506 | purge_tlb_end(); | 513 | purge_tlb_end(flags); |
507 | } | 514 | } |
508 | } | 515 | } |
509 | 516 | ||