| From 24d0492b7d5d321a9c5846c8c974eba9823ffaa0 Mon Sep 17 00:00:00 2001 |
| From: Helge Deller <deller@gmx.de> |
| Date: Thu, 8 Dec 2016 21:00:46 +0100 |
| Subject: parisc: Fix TLB related boot crash on SMP machines |
| |
| From: Helge Deller <deller@gmx.de> |
| |
| commit 24d0492b7d5d321a9c5846c8c974eba9823ffaa0 upstream. |
| |
| At bootup we run measurements to calculate the best threshold for when we |
| should be using full TLB flushes instead of just flushing a specific amount of |
| TLB entries. This performance test is run over the kernel text segment. |
| |
| But running this TLB performance test on the kernel text segment turned out to |
| crash some SMP machines when the kernel text pages were mapped as huge pages. |
| |
| To avoid those crashes this patch simply skips this test on some SMP machines |
| and calculates an optimal threshold based on the maximum number of available |
| TLB entries and number of online CPUs. |
| |
| On a technical side, this seems to happen: |
| The TLB measurement code uses flush_tlb_kernel_range() to flush specific TLB |
| entries with a page size of 4k (pdtlb 0(sr1,addr)). On UP systems this purge |
| instruction seems to work without problems even if the pages were mapped as |
| huge pages. But on SMP systems the TLB purge instruction is broadcasted to |
| other CPUs. Those CPUs then crash the machine because the page size is not as |
| expected. C8000 machines with PA8800/PA8900 CPUs were not affected by this |
| problem, because the required cache coherency prohibits to use huge pages at |
| all. Sadly I didn't found any documentation about this behaviour, so this |
| finding is purely based on testing with phyiscal SMP machines (A500-44 and |
| J5000, both were 2-way boxes). |
| |
| Signed-off-by: Helge Deller <deller@gmx.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/parisc/kernel/cache.c | 11 +++++++++++ |
| 1 file changed, 11 insertions(+) |
| |
| --- a/arch/parisc/kernel/cache.c |
| +++ b/arch/parisc/kernel/cache.c |
| @@ -375,6 +375,15 @@ void __init parisc_setup_cache_timing(vo |
| |
| /* calculate TLB flush threshold */ |
| |
| + /* On SMP machines, skip the TLB measure of kernel text which |
| + * has been mapped as huge pages. */ |
| + if (num_online_cpus() > 1 && !parisc_requires_coherency()) { |
| + threshold = max(cache_info.it_size, cache_info.dt_size); |
| + threshold *= PAGE_SIZE; |
| + threshold /= num_online_cpus(); |
| + goto set_tlb_threshold; |
| + } |
| + |
| alltime = mfctl(16); |
| flush_tlb_all(); |
| alltime = mfctl(16) - alltime; |
| @@ -393,6 +402,8 @@ void __init parisc_setup_cache_timing(vo |
| alltime, size, rangetime); |
| |
| threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime); |
| + |
| +set_tlb_threshold: |
| if (threshold) |
| parisc_tlb_flush_threshold = threshold; |
| printk(KERN_INFO "TLB flush threshold set to %lu KiB\n", |