Skip to content

Commit 24d0492

Browse files
committed
parisc: Fix TLB related boot crash on SMP machines
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). Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Helge Deller <deller@gmx.de>
1 parent febe429 commit 24d0492

1 file changed

Lines changed: 11 additions & 0 deletions

File tree

arch/parisc/kernel/cache.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,15 @@ void __init parisc_setup_cache_timing(void)
393393

394394
/* calculate TLB flush threshold */
395395

396+
/* On SMP machines, skip the TLB measure of kernel text which
397+
* has been mapped as huge pages. */
398+
if (num_online_cpus() > 1 && !parisc_requires_coherency()) {
399+
threshold = max(cache_info.it_size, cache_info.dt_size);
400+
threshold *= PAGE_SIZE;
401+
threshold /= num_online_cpus();
402+
goto set_tlb_threshold;
403+
}
404+
396405
alltime = mfctl(16);
397406
flush_tlb_all();
398407
alltime = mfctl(16) - alltime;
@@ -411,6 +420,8 @@ void __init parisc_setup_cache_timing(void)
411420
alltime, size, rangetime);
412421

413422
threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime);
423+
424+
set_tlb_threshold:
414425
if (threshold)
415426
parisc_tlb_flush_threshold = threshold;
416427
printk(KERN_INFO "TLB flush threshold set to %lu KiB\n",

0 commit comments

Comments
 (0)