From patchwork Fri Jan 30 14:21:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damian Eppel X-Patchwork-Id: 5750561 Return-Path: X-Original-To: patchwork-linux-samsung-soc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D601E9F38E for ; Fri, 30 Jan 2015 14:22:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C2B2A202AE for ; Fri, 30 Jan 2015 14:22:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AECD420270 for ; Fri, 30 Jan 2015 14:22:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1762352AbbA3OWT (ORCPT ); Fri, 30 Jan 2015 09:22:19 -0500 Received: from mailout2.samsung.com ([203.254.224.25]:28631 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1762348AbbA3OWQ (ORCPT ); Fri, 30 Jan 2015 09:22:16 -0500 Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0NIZ00HPGUL17XB0@mailout2.samsung.com>; Fri, 30 Jan 2015 23:22:13 +0900 (KST) X-AuditID: cbfee61a-f79c06d000004e71-db-54cb93950ba6 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 15.DA.20081.5939BC45; Fri, 30 Jan 2015 23:22:13 +0900 (KST) Received: from AMDC1552.digital.local ([106.116.48.103]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0NIZ00IZ7UKR3M00@mmp1.samsung.com>; Fri, 30 Jan 2015 23:22:13 +0900 (KST) From: Damian Eppel To: daniel.lezcano@linaro.org, tglx@linutronix.de, kgene@kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org Cc: kyungmin.park@samsung.com, b.zolnierkie@samsung.com, Damian Eppel , stable@vger.kernel.org Subject: [PATCH] clocksource: exynos_mct: fix for sleeping in atomic ctx handling cpu hotplug notif. Date: Fri, 30 Jan 2015 15:21:31 +0100 Message-id: <1422627691-10774-1-git-send-email-d.eppel@samsung.com> X-Mailer: git-send-email 1.9.1 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupjluLIzCtJLcpLzFFi42I5/e+xgO7UyadDDNpPiVlsnLGe1eLSo5ds FvM+y1r0P37NbHG26Q27xabH11gtLu+aw2Yx4/w+JosFGx8xWmzeNJXZgctj06pONo871/aw ebw7d47dY/OSeo++LasYPT5vkgtgi+KySUnNySxLLdK3S+DK6OjdxlZwxrBi7/8vjA2MhzS7 GDk5JARMJN7PXcIKYYtJXLi3nq2LkYtDSGARo8SyHZvYIZwOJonvh+4zg1SxCWhINK/eDFYl IrCOUWLb7pVADgcHs0CpxPlb2SA1wgJpEjcvfwKrZxFQlbjyeSojiM0r4CxxcNtZRohtchIn j01mncDIvYCRYRWjaGpBckFxUnquoV5xYm5xaV66XnJ+7iZGcCg9k9rBuLLB4hCjAAejEg/v gqenQoRYE8uKK3MPMUpwMCuJ8E6ZdDpEiDclsbIqtSg/vqg0J7X4EKM0B4uSOK+SfVuIkEB6 YklqdmpqQWoRTJaJg1OqgbFq1pnQqaemtAqYOJwy65kYdEghJrbppMPxAI1lCp9LbrSvvyFx 4ouIUMu+b3suVfGIGN2X+DTNcuaRN+ETbTsltzq89C97WSV/ad5lhsvPWzSnbA/5FnB54RTm s//MZCYJ/Z+UnRxf7Fz2yGLCrb3sJ7nqPq7jWfS3eKFDlaCup1s/lxibpIgSS3FGoqEWc1Fx IgB0J65lIQIAAA== Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This is to fix an issue of sleeping in atomic context when processing hotplug notifications in Exynos MCT(Multi-Core Timer). The issue was reproducible on Exynos 3250 (Rinato board) and Exynos 5420 (Arndale Octa board). 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). root@target:~# echo 0 > /sys/devices/system/cpu/cpu1/online [ 25.157867] IRQ18 no longer affine to CPU1 ... [ 25.158445] CPU1: shutdown root@target:~# echo 1 > /sys/devices/system/cpu/cpu1/online [ 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] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 40.786747] [] (show_stack) from [] (dump_stack+0x70/0xbc) [ 40.786767] [] (dump_stack) from [] (kmem_cache_alloc+0xd8/0x170) [ 40.786785] [] (kmem_cache_alloc) from [] (request_threaded_irq+0x64/0x128) [ 40.786804] [] (request_threaded_irq) from [] (exynos4_local_timer_setup+0xc0/0x13c) [ 40.786820] [] (exynos4_local_timer_setup) from [] (exynos4_mct_cpu_notify+0x30/0xa8) [ 40.786838] [] (exynos4_mct_cpu_notify) from [] (notifier_call_chain+0x44/0x84) [ 40.786857] [] (notifier_call_chain) from [] (__cpu_notify+0x28/0x44) [ 40.786873] [] (__cpu_notify) from [] (secondary_start_kernel+0xec/0x150) [ 40.786886] [] (secondary_start_kernel) from [<40008764>] (0x40008764) Solution: Clockevent irqs cannot be requested/freed every time cpu is hot-plugged/unplugged as CPU_STARTING/CPU_DYING notifications that signals hotplug or unplug events are sent with both preemption and local interrupts disabled. Since request_irq() may sleep it is moved to the initialization stage and performed for all possible cpus prior putting them online. Then, in the case of hotplug event the irq asociated with the given cpu will simply be enabled. Similarly on cpu unplug event the interrupt is not freed but just disabled. Note that after successful request_irq() call for a clockevent device associated to given cpu the requested irq is disabled (via disable_irq()). That is to make things symmetric as we expect hotplug event as a next thing (which will enable irq again). This should not pose any problems because at the time of requesting irq the clockevent device is not fully initialized yet, therefore should not produce interrupts at that point. For disabling an irq at cpu unplug notification disable_irq_nosync() is chosen which is a non-blocking function. This again shouldn't be a problem as prior sending CPU_DYING notification interrupts are migrated away from the cpu. Fixes: 7114cd749a12 ("clocksource: exynos_mct: use (request/free)_irq calls for local timer registration") Signed-off-by: Damian Eppel Cc: Reported-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Tested-by: Marcin Jabrzyk --- drivers/clocksource/exynos_mct.c | 45 ++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 83564c9..9beca58 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -466,15 +466,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt) exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); if (mct_int_type == MCT_INT_SPI) { - evt->irq = mct_irqs[MCT_L0_IRQ + cpu]; - if (request_irq(evt->irq, exynos4_mct_tick_isr, - IRQF_TIMER | IRQF_NOBALANCING, - evt->name, mevt)) { - pr_err("exynos-mct: cannot register IRQ %d\n", - evt->irq); + + if (evt->irq == -1) return -EIO; - } - irq_force_affinity(mct_irqs[MCT_L0_IRQ + cpu], cpumask_of(cpu)); + + irq_force_affinity(evt->irq, cpumask_of(cpu)); + enable_irq(evt->irq); } else { enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0); } @@ -487,10 +484,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt) static void exynos4_local_timer_stop(struct clock_event_device *evt) { evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); - if (mct_int_type == MCT_INT_SPI) - free_irq(evt->irq, this_cpu_ptr(&percpu_mct_tick)); - else + if (mct_int_type == MCT_INT_SPI) { + if (evt->irq != -1) + disable_irq_nosync(evt->irq); + } else { disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); + } } static int exynos4_mct_cpu_notify(struct notifier_block *self, @@ -522,7 +521,7 @@ static struct notifier_block exynos4_mct_cpu_nb = { static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { - int err; + int err, cpu; struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); struct clk *mct_clk, *tick_clk; @@ -549,7 +548,27 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem WARN(err, "MCT: can't request IRQ %d (%d)\n", mct_irqs[MCT_L0_IRQ], err); } else { - irq_set_affinity(mct_irqs[MCT_L0_IRQ], cpumask_of(0)); + for_each_possible_cpu(cpu) { + int mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; + struct mct_clock_event_device *pcpu_mevt = + per_cpu_ptr(&percpu_mct_tick, cpu); + + pcpu_mevt->evt.irq = -1; + + if (request_irq(mct_irq, + exynos4_mct_tick_isr, + IRQF_TIMER | IRQF_NOBALANCING, + pcpu_mevt->name, pcpu_mevt)) { + pr_err("exynos-mct: cannot register IRQ (cpu%d)\n", + cpu); + + continue; + } + pcpu_mevt->evt.irq = mct_irq; + irq_force_affinity(mct_irq, cpumask_of(cpu)); + + disable_irq(mct_irq); + } } err = register_cpu_notifier(&exynos4_mct_cpu_nb);