Skip to content

Commit 56a94f1

Browse files
Damian EppelKAGA-KOKO
Damian Eppel
authored andcommitted
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 raspberrypi#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: 7114cd7 ("clocksource: exynos_mct: use (request/free)_irq calls for local timer registration") Reported-by: Krzysztof Kozlowski <[email protected]> Reviewed-by: Krzysztof Kozlowski <[email protected]> Tested-by: Krzysztof Kozlowski <[email protected]> Tested-by: Marcin Jabrzyk <[email protected]> Signed-off-by: Damian Eppel <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]> Cc: <[email protected]>
1 parent 407a2c7 commit 56a94f1

File tree

1 file changed

+30
-13
lines changed

1 file changed

+30
-13
lines changed

drivers/clocksource/exynos_mct.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -462,15 +462,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
462462
exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
463463

464464
if (mct_int_type == MCT_INT_SPI) {
465-
evt->irq = mct_irqs[MCT_L0_IRQ + cpu];
466-
if (request_irq(evt->irq, exynos4_mct_tick_isr,
467-
IRQF_TIMER | IRQF_NOBALANCING,
468-
evt->name, mevt)) {
469-
pr_err("exynos-mct: cannot register IRQ %d\n",
470-
evt->irq);
465+
466+
if (evt->irq == -1)
471467
return -EIO;
472-
}
473-
irq_force_affinity(mct_irqs[MCT_L0_IRQ + cpu], cpumask_of(cpu));
468+
469+
irq_force_affinity(evt->irq, cpumask_of(cpu));
470+
enable_irq(evt->irq);
474471
} else {
475472
enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
476473
}
@@ -483,10 +480,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
483480
static void exynos4_local_timer_stop(struct clock_event_device *evt)
484481
{
485482
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
486-
if (mct_int_type == MCT_INT_SPI)
487-
free_irq(evt->irq, this_cpu_ptr(&percpu_mct_tick));
488-
else
483+
if (mct_int_type == MCT_INT_SPI) {
484+
if (evt->irq != -1)
485+
disable_irq_nosync(evt->irq);
486+
} else {
489487
disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
488+
}
490489
}
491490

492491
static int exynos4_mct_cpu_notify(struct notifier_block *self,
@@ -518,7 +517,7 @@ static struct notifier_block exynos4_mct_cpu_nb = {
518517

519518
static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base)
520519
{
521-
int err;
520+
int err, cpu;
522521
struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
523522
struct clk *mct_clk, *tick_clk;
524523

@@ -545,7 +544,25 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem
545544
WARN(err, "MCT: can't request IRQ %d (%d)\n",
546545
mct_irqs[MCT_L0_IRQ], err);
547546
} 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+
}
549566
}
550567

551568
err = register_cpu_notifier(&exynos4_mct_cpu_nb);

0 commit comments

Comments
 (0)