aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn David Anglin <dave.anglin@bell.net>2016-11-20 21:12:36 -0500
committerHelge Deller <deller@gmx.de>2016-11-25 06:31:57 -0500
commit741dc7bf1c7c7d93b853bb55efe77baa27e1b0a9 (patch)
treeb74342741f7114047a05a35d4ae3ad9ae58905cf
parent4345a64ac931a8dc499f1fc69880952412f36c3e (diff)
parisc: Fix races in parisc_setup_cache_timing()
Helge reported to me the following startup crash: [ 0.000000] Linux version 4.8.0-1-parisc64-smp (debian-kernel@lists.debian.org) (gcc version 5.4.1 20161019 (GCC) ) #1 SMP Debian 4.8.7-1 (2016-11-13) [ 0.000000] The 64-bit Kernel has started... [ 0.000000] Kernel default page size is 4 KB. Huge pages enabled with 1 MB physical and 2 MB virtual size. [ 0.000000] Determining PDC firmware type: System Map. [ 0.000000] model 9000/785/J5000 [ 0.000000] Total Memory: 2048 MB [ 0.000000] Memory: 2018528K/2097152K available (9272K kernel code, 3053K rwdata, 1319K rodata, 1024K init, 840K bss, 78624K reserved, 0K cma-reserved) [ 0.000000] virtual kernel memory layout: [ 0.000000] vmalloc : 0x0000000000008000 - 0x000000003f000000 (1007 MB) [ 0.000000] memory : 0x0000000040000000 - 0x00000000c0000000 (2048 MB) [ 0.000000] .init : 0x0000000040100000 - 0x0000000040200000 (1024 kB) [ 0.000000] .data : 0x0000000040b0e000 - 0x0000000040f533e0 (4372 kB) [ 0.000000] .text : 0x0000000040200000 - 0x0000000040b0e000 (9272 kB) [ 0.768910] Brought up 1 CPUs [ 0.992465] NET: Registered protocol family 16 [ 2.429981] Releasing cpu 1 now, hpa=fffffffffffa2000 [ 2.635751] CPU(s): 2 out of 2 PA8500 (PCX-W) at 440.000000 MHz online [ 2.726692] Setting cache flush threshold to 1024 kB [ 2.729932] Not-handled unaligned insn 0x43ffff80 [ 2.798114] Setting TLB flush threshold to 140 kB [ 2.928039] Unaligned handler failed, ret = -1 [ 3.000419] _______________________________ [ 3.000419] < Your System ate a SPARC! Gah! > [ 3.000419] ------------------------------- [ 3.000419] \ ^__^ [ 3.000419] (__)\ )\/\ [ 3.000419] U ||----w | [ 3.000419] || || [ 9.340055] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0-1-parisc64-smp #1 Debian 4.8.7-1 [ 9.448082] task: 00000000bfd48060 task.stack: 00000000bfd50000 [ 9.528040] [ 10.760029] IASQ: 0000000000000000 0000000000000000 IAOQ: 000000004025d154 000000004025d158 [ 10.868052] IIR: 43ffff80 ISR: 0000000000340000 IOR: 000001ff54150960 [ 10.960029] CPU: 1 CR30: 00000000bfd50000 CR31: 0000000011111111 [ 11.052057] ORIG_R28: 000000004021e3b4 [ 11.100045] IAOQ[0]: irq_exit+0x94/0x120 [ 11.152062] IAOQ[1]: irq_exit+0x98/0x120 [ 11.208031] RP(r2): irq_exit+0xb8/0x120 [ 11.256074] Backtrace: [ 11.288067] [<00000000402cd944>] cpu_startup_entry+0x1e4/0x598 [ 11.368058] [<0000000040109528>] smp_callin+0x2c0/0x2f0 [ 11.436308] [<00000000402b53fc>] update_curr+0x18c/0x2d0 [ 11.508055] [<00000000402b73b8>] dequeue_entity+0x2c0/0x1030 [ 11.584040] [<00000000402b3cc0>] set_next_entity+0x80/0xd30 [ 11.660069] [<00000000402c1594>] pick_next_task_fair+0x614/0x720 [ 11.740085] [<000000004020dd34>] __schedule+0x394/0xa60 [ 11.808054] [<000000004020e488>] schedule+0x88/0x118 [ 11.876039] [<0000000040283d3c>] rescuer_thread+0x4d4/0x5b0 [ 11.948090] [<000000004028fc4c>] kthread+0x1ec/0x248 [ 12.016053] [<0000000040205020>] end_fault_vector+0x20/0xc0 [ 12.092239] [<00000000402050c0>] _switch_to_ret+0x0/0xf40 [ 12.164044] [ 12.184036] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0-1-parisc64-smp #1 Debian 4.8.7-1 [ 12.244040] Backtrace: [ 12.244040] [<000000004021c480>] show_stack+0x68/0x80 [ 12.244040] [<00000000406f332c>] dump_stack+0xec/0x168 [ 12.244040] [<000000004021c74c>] die_if_kernel+0x25c/0x430 [ 12.244040] [<000000004022d320>] handle_unaligned+0xb48/0xb50 [ 12.244040] [ 12.632066] ---[ end trace 9ca05a7215c7bbb2 ]--- [ 12.692036] Kernel panic - not syncing: Attempted to kill the idle task! We have the insn 0x43ffff80 in IIR but from IAOQ we should have: 4025d150: 0f f3 20 df ldd,s r19(r31),r31 4025d154: 0f 9f 00 9c ldw r31(ret0),ret0 4025d158: bf 80 20 58 cmpb,*<> r0,ret0,4025d18c <irq_exit+0xcc> Cpu0 has just completed running parisc_setup_cache_timing: [ 2.429981] Releasing cpu 1 now, hpa=fffffffffffa2000 [ 2.635751] CPU(s): 2 out of 2 PA8500 (PCX-W) at 440.000000 MHz online [ 2.726692] Setting cache flush threshold to 1024 kB [ 2.729932] Not-handled unaligned insn 0x43ffff80 [ 2.798114] Setting TLB flush threshold to 140 kB [ 2.928039] Unaligned handler failed, ret = -1 From the backtrace, cpu1 is in smp_callin: void __init smp_callin(void) { int slave_id = cpu_now_booting; smp_cpu_init(slave_id); preempt_disable(); flush_cache_all_local(); /* start with known state */ flush_tlb_all_local(NULL); local_irq_enable(); /* Interrupts have been off until now */ cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); So, it has just flushed its caches and the TLB. It would seem either the flushes in parisc_setup_cache_timing or smp_callin have corrupted kernel memory. The attached patch reworks parisc_setup_cache_timing to remove the races in setting the cache and TLB flush thresholds. It also corrects the number of bytes flushed in the TLB calculation. The patch flushes the cache and TLB on cpu0 before starting the secondary processors so that they are started from a known state. Tested with a few reboots on c8000. Signed-off-by: John David Anglin <dave.anglin@bell.net> Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--arch/parisc/kernel/cache.c31
-rw-r--r--arch/parisc/kernel/setup.c4
2 files changed, 16 insertions, 19 deletions
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 629eb464d5ba..c263301648f3 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -369,6 +369,7 @@ void __init parisc_setup_cache_timing(void)
369{ 369{
370 unsigned long rangetime, alltime; 370 unsigned long rangetime, alltime;
371 unsigned long size, start; 371 unsigned long size, start;
372 unsigned long threshold;
372 373
373 alltime = mfctl(16); 374 alltime = mfctl(16);
374 flush_data_cache(); 375 flush_data_cache();
@@ -382,17 +383,12 @@ void __init parisc_setup_cache_timing(void)
382 printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n", 383 printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n",
383 alltime, size, rangetime); 384 alltime, size, rangetime);
384 385
385 /* Racy, but if we see an intermediate value, it's ok too... */ 386 threshold = L1_CACHE_ALIGN(size * alltime / rangetime);
386 parisc_cache_flush_threshold = size * alltime / rangetime; 387 if (threshold > cache_info.dc_size)
387 388 threshold = cache_info.dc_size;
388 parisc_cache_flush_threshold = L1_CACHE_ALIGN(parisc_cache_flush_threshold); 389 if (threshold)
389 if (!parisc_cache_flush_threshold) 390 parisc_cache_flush_threshold = threshold;
390 parisc_cache_flush_threshold = FLUSH_THRESHOLD; 391 printk(KERN_INFO "Cache flush threshold set to %lu KiB\n",
391
392 if (parisc_cache_flush_threshold > cache_info.dc_size)
393 parisc_cache_flush_threshold = cache_info.dc_size;
394
395 printk(KERN_INFO "Setting cache flush threshold to %lu kB\n",
396 parisc_cache_flush_threshold/1024); 392 parisc_cache_flush_threshold/1024);
397 393
398 /* calculate TLB flush threshold */ 394 /* calculate TLB flush threshold */
@@ -401,7 +397,7 @@ void __init parisc_setup_cache_timing(void)
401 flush_tlb_all(); 397 flush_tlb_all();
402 alltime = mfctl(16) - alltime; 398 alltime = mfctl(16) - alltime;
403 399
404 size = PAGE_SIZE; 400 size = 0;
405 start = (unsigned long) _text; 401 start = (unsigned long) _text;
406 rangetime = mfctl(16); 402 rangetime = mfctl(16);
407 while (start < (unsigned long) _end) { 403 while (start < (unsigned long) _end) {
@@ -414,13 +410,10 @@ void __init parisc_setup_cache_timing(void)
414 printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n", 410 printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n",
415 alltime, size, rangetime); 411 alltime, size, rangetime);
416 412
417 parisc_tlb_flush_threshold = size * alltime / rangetime; 413 threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime);
418 parisc_tlb_flush_threshold *= num_online_cpus(); 414 if (threshold)
419 parisc_tlb_flush_threshold = PAGE_ALIGN(parisc_tlb_flush_threshold); 415 parisc_tlb_flush_threshold = threshold;
420 if (!parisc_tlb_flush_threshold) 416 printk(KERN_INFO "TLB flush threshold set to %lu KiB\n",
421 parisc_tlb_flush_threshold = FLUSH_TLB_THRESHOLD;
422
423 printk(KERN_INFO "Setting TLB flush threshold to %lu kB\n",
424 parisc_tlb_flush_threshold/1024); 417 parisc_tlb_flush_threshold/1024);
425} 418}
426 419
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index 81d6f6391944..2e66a887788e 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -334,6 +334,10 @@ static int __init parisc_init(void)
334 /* tell PDC we're Linux. Nevermind failure. */ 334 /* tell PDC we're Linux. Nevermind failure. */
335 pdc_stable_write(0x40, &osid, sizeof(osid)); 335 pdc_stable_write(0x40, &osid, sizeof(osid));
336 336
337 /* start with known state */
338 flush_cache_all_local();
339 flush_tlb_all_local(NULL);
340
337 processor_init(); 341 processor_init();
338#ifdef CONFIG_SMP 342#ifdef CONFIG_SMP
339 pr_info("CPU(s): %d out of %d %s at %d.%06d MHz online\n", 343 pr_info("CPU(s): %d out of %d %s at %d.%06d MHz online\n",