From patchwork Sat Sep 6 17:52:36 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ga=C3=ABl_PORTAY?= X-Patchwork-Id: 386646 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 4E04614017A for ; Sun, 7 Sep 2014 03:53:19 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752407AbaIFRxJ (ORCPT ); Sat, 6 Sep 2014 13:53:09 -0400 Received: from mail-wg0-f42.google.com ([74.125.82.42]:42413 "EHLO mail-wg0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752120AbaIFRxA (ORCPT ); Sat, 6 Sep 2014 13:53:00 -0400 Received: by mail-wg0-f42.google.com with SMTP id x12so1433566wgg.1 for ; Sat, 06 Sep 2014 10:52:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=Nv9TRqaF7/ohs6xiJ6So//RK3udf2tBr8Oandb87qlE=; b=rntmCvSsHpMygn692YtBv5glDKc4fHrVQD5Hx5Vn9BB+h8NP6H5BdNxxUB/0TH7Jz9 pdcODQ6818UcgzYaPWxDK+VLnl+2MooNx+scF0+d3vhY6y7GwuAyM3sMtgssqWd+JMED CCorpfYMa5QLMRxIdK7FlNu2OnrWXeoNXYkGkZdjJpdS7pU3aK13rNd7nahoS7u3HWpN s+nmwZOSywcw0ScSgha5NRrFXxnYIzNDeTDRGOQNJ4xrGeSGePjscYoKqrAV1tdYaRpn fIyrvezVEtgrhTExXb5dU6qUhKI62XWfttN7mfPAZy/miLvZM00gtfxyPZmEiD49Vs5c Whaw== X-Received: by 10.194.84.175 with SMTP id a15mr20972046wjz.12.1410025979217; Sat, 06 Sep 2014 10:52:59 -0700 (PDT) Received: from localhost.localdomain ([78.206.137.189]) by mx.google.com with ESMTPSA id ll20sm5697978wic.14.2014.09.06.10.52.57 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 06 Sep 2014 10:52:58 -0700 (PDT) From: =?UTF-8?q?Ga=C3=ABl=20PORTAY?= To: Arnd Bergmann , Daniel Lezcano , Greg Kroah-Hartman , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org, Nicolas Ferre , Thomas Gleixner , Thierry Reding , Boris Brezillon , Alexandre Belloni , Jean-Christophe PLAGNIOL-VILLARD Cc: =?utf-8?q?Ga=C3=ABl=20PORTAY?= Subject: [PATCHv4 3/4] ARM: at91/tclib: mask interruptions at shutdown and probe Date: Sat, 6 Sep 2014 19:52:36 +0200 Message-Id: <1410025957-5952-4-git-send-email-gael.portay@gmail.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1410025957-5952-1-git-send-email-gael.portay@gmail.com> References: <1410025957-5952-1-git-send-email-gael.portay@gmail.com> MIME-Version: 1.0 Sender: linux-pwm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org Shutdown properly the timer counter block by masking interruptions. Otherwise, a segmentation may happen when kexec-ing a new kernel (see backtrace below). An interruption may happen before the handler is set, leading to a kernel segmentation fault. Furthermore, we make sure the interruptions are masked when the driver is initialized. This will prevent freshly kexec-ed kernel from crashing when launched from a kernel which does not properly mask interruptions at shutdown. The backtrace below happened after kexec-ing a new kernel, from a kernel that did not shut down properly leaving interruptions unmasked. Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 80000005 [#1] ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 3.16.0+ #144 task: c1828aa0 ti: c182a000 task.ti: c182a000 PC is at 0x0 LR is at ch2_irq+0x28/0x30 pc : [<00000000>] lr : [] psr: 000000d3 sp : c182bd38 ip : c182bd48 fp : c182bd44 r10: c0373390 r9 : c1825b00 r8 : 60000053 r7 : 00000000 r6 : 00000000 r5 : 00000013 r4 : c036e800 r3 : 00000000 r2 : 00002004 r1 : c036e760 r0 : c036e760 Flags: nzcv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel Control: 0005317f Table: 20004000 DAC: 00000017 Process swapper (pid: 1, stack limit = 0xc182a1c0) Stack: (0xc182bd38 to 0xc182c000) bd20: c182bd7c c182bd48 bd40: c0045430 c01db8ec 00000000 c18c6f40 c182bd74 c1825b00 c035cec4 00000000 bd60: c182be2c 60000053 c1825b34 00000000 c182bd94 c182bd80 c0045570 c0045408 bd80: 00000000 c1825b00 c182bdac c182bd98 c0047f34 c0045550 00000013 c036619c bda0: c182bdc4 c182bdb0 c0044da4 c0047e98 0000007f 00000013 c182bde4 c182bdc8 bdc0: c0009e34 c0044d8c fefff000 c0046728 60000053 ffffffff c182bdf4 c182bde8 bde0: c00086a8 c0009ddc c182be74 c182bdf8 c000cb80 c0008674 00000000 00000013 be00: 00000000 00014200 c1825b00 c036e800 00000013 c035ed98 60000053 c1825b34 be20: 00000000 c182be74 c182be20 c182be40 c0047994 c0046728 60000053 ffffffff be40: 00000013 c036e800 c182be64 c1825b00 00000013 c036e800 c035ed98 c03874bc be60: 00000004 c036e700 c182be94 c182be78 c004689c c0046398 c036e760 c18c6080 be80: 00000000 c035ed10 c182bedc c182be98 c0348b08 c004684c 0000000c c034dac8 bea0: 004c4b3f c028c338 c036e760 00000013 c014ecc8 c18e67e0 c035b9c0 c0348884 bec0: c035b9c0 c182a020 00000000 00000000 c182bf54 c182bee0 c00089fc c0348894 bee0: c00da51c c1ffcc78 c182bf0c c182bef8 c002d100 c002d09c c1ffcc78 00000000 bf00: c182bf54 c182bf10 c002d308 c0336570 c182bf3c c0334e44 00000003 00000003 bf20: 00000030 c0334b44 c0044d74 00000003 00000003 c034dac8 c0350a94 c0373440 bf40: c0373440 00000030 c182bf94 c182bf58 c0336d24 c000890c 00000003 00000003 bf60: c0336560 c182bf64 c182bf64 6e616e0d 00000000 c0272fc8 00000000 00000000 bf80: 00000000 00000000 c182bfac c182bf98 c0272fd8 c0336bd8 c182a000 00000000 bfa0: 00000000 c182bfb0 c00095d0 c0272fd8 00000000 00000000 00000000 00000000 bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 374d27cd 33cc33e4 Backtrace: [] (ch2_irq) from [] (handle_irq_event_percpu+0x38/0x148) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x30/0x40) r10:00000000 r9:c1825b34 r8:60000053 r7:c182be2c r6:00000000 r5:c035cec4 r4:c1825b00 [] (handle_irq_event) from [] (handle_fasteoi_irq+0xac/0x11c) r4:c1825b00 r3:00000000 [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x28/0x38) r5:c036619c r4:00000013 [] (generic_handle_irq) from [] (handle_IRQ+0x68/0x88) r4:00000013 r3:0000007f [] (handle_IRQ) from [] (at91_aic_handle_irq+0x44/0x4c) r6:ffffffff r5:60000053 r4:c0046728 r3:fefff000 [] (at91_aic_handle_irq) from [] (__irq_svc+0x40/0x4c) Exception stack(0xc182bdf8 to 0xc182be40) bde0: 00000000 00000013 be00: 00000000 00014200 c1825b00 c036e800 00000013 c035ed98 60000053 c1825b34 be20: 00000000 c182be74 c182be20 c182be40 c0047994 c0046728 60000053 ffffffff [] (__setup_irq) from [] (setup_irq+0x60/0x8c) r10:c036e700 r9:00000004 r8:c03874bc r7:c035ed98 r6:c036e800 r5:00000013 r4:c1825b00 [] (setup_irq) from [] (tcb_clksrc_init+0x284/0x31c) r6:c035ed10 r5:00000000 r4:c18c6080 r3:c036e760 [] (tcb_clksrc_init) from [] (do_one_initcall+0x100/0x1b4) r10:00000000 r9:00000000 r8:c182a020 r7:c035b9c0 r6:c0348884 r5:c035b9c0 r4:c18e67e0 [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x224) r9:00000030 r8:c0373440 r7:c0373440 r6:c0350a94 r5:c034dac8 r4:00000003 [] (kernel_init_freeable) from [] (kernel_init+0x10/0xec) r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0272fc8 r4:00000000 [] (kernel_init) from [] (ret_from_fork+0x14/0x24) r4:00000000 r3:c182a000 Code: bad PC value ---[ end trace 5b30f0017e282e47 ]--- Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Gaƫl PORTAY Acked-by: Boris Brezillon Acked-by: Daniel Lezcano --- drivers/misc/atmel_tclib.c | 16 ++++++++++++++++ include/linux/atmel_tc.h | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index d505d1e..0ca05c3 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c @@ -109,6 +109,7 @@ static int __init tc_probe(struct platform_device *pdev) struct clk *clk; int irq; struct resource *r; + unsigned int i; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -157,18 +158,33 @@ static int __init tc_probe(struct platform_device *pdev) if (tc->irq[2] < 0) tc->irq[2] = irq; + for (i = 0; i < 3; i++) + writel(ATMEL_TC_ALL_IRQ, tc->regs + ATMEL_TC_REG(i, IDR)); + spin_lock(&tc_list_lock); list_add_tail(&tc->node, &tc_list); spin_unlock(&tc_list_lock); + platform_set_drvdata(pdev, tc); + return 0; } +static void tc_shutdown(struct platform_device *pdev) +{ + int i; + struct atmel_tc *tc = platform_get_drvdata(pdev); + + for (i = 0; i < 3; i++) + writel(ATMEL_TC_ALL_IRQ, tc->regs + ATMEL_TC_REG(i, IDR)); +} + static struct platform_driver tc_driver = { .driver = { .name = "atmel_tcb", .of_match_table = of_match_ptr(atmel_tcb_dt_ids), }, + .shutdown = tc_shutdown, }; static int __init tc_init(void) diff --git a/include/linux/atmel_tc.h b/include/linux/atmel_tc.h index d8aa884..b87c1c7 100644 --- a/include/linux/atmel_tc.h +++ b/include/linux/atmel_tc.h @@ -260,5 +260,10 @@ extern const u8 atmel_tc_divisors[5]; #define ATMEL_TC_LDRAS (1 << 5) /* RA loading */ #define ATMEL_TC_LDRBS (1 << 6) /* RB loading */ #define ATMEL_TC_ETRGS (1 << 7) /* external trigger */ +#define ATMEL_TC_ALL_IRQ (ATMEL_TC_COVFS | ATMEL_TC_LOVRS | \ + ATMEL_TC_CPAS | ATMEL_TC_CPBS | \ + ATMEL_TC_CPCS | ATMEL_TC_LDRAS | \ + ATMEL_TC_LDRBS | ATMEL_TC_ETRGS) \ + /* all IRQs */ #endif