aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamian Eppel <d.eppel@samsung.com>2015-06-26 09:23:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-06-26 15:53:01 -0400
commit56a94f13919c0db5958611b388e1581b4852f3c9 (patch)
tree765497df356a545fb036c304d50555c9b3075ebe
parent407a2c720556e8e340e06f6a7174f5d6d80cf9ea (diff)
clocksource: exynos_mct: Avoid blocking calls in the cpu hotplug notifier
Whilst testing cpu hotplug events on kernel configured with DEBUG_PREEMPT and DEBUG_ATOMIC_SLEEP we get following BUG message, caused by calling request_irq() and free_irq() in the context of hotplug notification (which is in this case atomic context). [ 40.785859] CPU1: Software reset [ 40.786660] BUG: sleeping function called from invalid context at mm/slub.c:1241 [ 40.786668] in_atomic(): 1, irqs_disabled(): 128, pid: 0, name: swapper/1 [ 40.786678] Preemption disabled at:[< (null)>] (null) [ 40.786681] [ 40.786692] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 3.19.0-rc4-00024-g7dca860 #36 [ 40.786698] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 40.786728] [<c0014a00>] (unwind_backtrace) from [<c0011980>] (show_stack+0x10/0x14) [ 40.786747] [<c0011980>] (show_stack) from [<c0449ba0>] (dump_stack+0x70/0xbc) [ 40.786767] [<c0449ba0>] (dump_stack) from [<c00c6124>] (kmem_cache_alloc+0xd8/0x170) [ 40.786785] [<c00c6124>] (kmem_cache_alloc) from [<c005d6f8>] (request_threaded_irq+0x64/0x128) [ 40.786804] [<c005d6f8>] (request_threaded_irq) from [<c0350b8c>] (exynos4_local_timer_setup+0xc0/0x13c) [ 40.786820] [<c0350b8c>] (exynos4_local_timer_setup) from [<c0350ca8>] (exynos4_mct_cpu_notify+0x30/0xa8) [ 40.786838] [<c0350ca8>] (exynos4_mct_cpu_notify) from [<c003b330>] (notifier_call_chain+0x44/0x84) [ 40.786857] [<c003b330>] (notifier_call_chain) from [<c0022fd4>] (__cpu_notify+0x28/0x44) [ 40.786873] [<c0022fd4>] (__cpu_notify) from [<c0013714>] (secondary_start_kernel+0xec/0x150) [ 40.786886] [<c0013714>] (secondary_start_kernel) from [<40008764>] (0x40008764) Interrupts cannot be requested/freed in the CPU_STARTING/CPU_DYING notifications which run on the hotplugged cpu with interrupts and preemption disabled. To avoid the issue, request the interrupts for all possible cpus in the boot code. The interrupts are marked NO_AUTOENABLE to avoid a racy request_irq/disable_irq() sequence. The flag prevents the request_irq() code from enabling the interrupt immediately. The interrupt is then enabled in the CPU_STARTING notifier of the hotplugged cpu and again disabled with disable_irq_nosync() in the CPU_DYING notifier. [ tglx: Massaged changelog to match the patch ] Fixes: 7114cd749a12 ("clocksource: exynos_mct: use (request/free)_irq calls for local timer registration") Reported-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Tested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Tested-by: Marcin Jabrzyk <m.jabrzyk@samsung.com> Signed-off-by: Damian Eppel <d.eppel@samsung.com> Cc: m.szyprowski@samsung.com Cc: kyungmin.park@samsung.com Cc: daniel.lezcano@linaro.org Cc: kgene@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1435324984-7328-1-git-send-email-d.eppel@samsung.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: <stable@vger.kernel.org>
-rw-r--r--drivers/clocksource/exynos_mct.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 935b05936dbd..9064ff743598 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -462,15 +462,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
462 exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); 462 exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
463 463
464 if (mct_int_type == MCT_INT_SPI) { 464 if (mct_int_type == MCT_INT_SPI) {
465 evt->irq = mct_irqs[MCT_L0_IRQ + cpu]; 465
466 if (request_irq(evt->irq, exynos4_mct_tick_isr, 466 if (evt->irq == -1)
467 IRQF_TIMER | IRQF_NOBALANCING,
468 evt->name, mevt)) {
469 pr_err("exynos-mct: cannot register IRQ %d\n",
470 evt->irq);
471 return -EIO; 467 return -EIO;
472 } 468
473 irq_force_affinity(mct_irqs[MCT_L0_IRQ + cpu], cpumask_of(cpu)); 469 irq_force_affinity(evt->irq, cpumask_of(cpu));
470 enable_irq(evt->irq);
474 } else { 471 } else {
475 enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0); 472 enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
476 } 473 }
@@ -483,10 +480,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
483static void exynos4_local_timer_stop(struct clock_event_device *evt) 480static void exynos4_local_timer_stop(struct clock_event_device *evt)
484{ 481{
485 evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); 482 evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
486 if (mct_int_type == MCT_INT_SPI) 483 if (mct_int_type == MCT_INT_SPI) {
487 free_irq(evt->irq, this_cpu_ptr(&percpu_mct_tick)); 484 if (evt->irq != -1)
488 else 485 disable_irq_nosync(evt->irq);
486 } else {
489 disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); 487 disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
488 }
490} 489}
491 490
492static int exynos4_mct_cpu_notify(struct notifier_block *self, 491static int exynos4_mct_cpu_notify(struct notifier_block *self,
@@ -518,7 +517,7 @@ static struct notifier_block exynos4_mct_cpu_nb = {
518 517
519static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) 518static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base)
520{ 519{
521 int err; 520 int err, cpu;
522 struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); 521 struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
523 struct clk *mct_clk, *tick_clk; 522 struct clk *mct_clk, *tick_clk;
524 523
@@ -545,7 +544,25 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem
545 WARN(err, "MCT: can't request IRQ %d (%d)\n", 544 WARN(err, "MCT: can't request IRQ %d (%d)\n",
546 mct_irqs[MCT_L0_IRQ], err); 545 mct_irqs[MCT_L0_IRQ], err);
547 } else { 546 } else {
548 irq_set_affinity(mct_irqs[MCT_L0_IRQ], cpumask_of(0)); 547 for_each_possible_cpu(cpu) {
548 int mct_irq = mct_irqs[MCT_L0_IRQ + cpu];
549 struct mct_clock_event_device *pcpu_mevt =
550 per_cpu_ptr(&percpu_mct_tick, cpu);
551
552 pcpu_mevt->evt.irq = -1;
553
554 irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
555 if (request_irq(mct_irq,
556 exynos4_mct_tick_isr,
557 IRQF_TIMER | IRQF_NOBALANCING,
558 pcpu_mevt->name, pcpu_mevt)) {
559 pr_err("exynos-mct: cannot register IRQ (cpu%d)\n",
560 cpu);
561
562 continue;
563 }
564 pcpu_mevt->evt.irq = mct_irq;
565 }
549 } 566 }
550 567
551 err = register_cpu_notifier(&exynos4_mct_cpu_nb); 568 err = register_cpu_notifier(&exynos4_mct_cpu_nb);