From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-lf0-f49.google.com ([209.85.215.49]:33025 "EHLO mail-lf0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965799AbcKLOBQ (ORCPT ); Sat, 12 Nov 2016 09:01:16 -0500 Received: by mail-lf0-f49.google.com with SMTP id c13so30437893lfg.0 for ; Sat, 12 Nov 2016 06:01:15 -0800 (PST) From: Linus Walleij To: linux-gpio@vger.kernel.org, Alexandre Courbot Cc: Linus Walleij , stable@vger.kernel.org, Patrice Chotard Subject: [PATCH] gpio: do not double-check direction on sleeping chips Date: Sat, 12 Nov 2016 15:01:09 +0100 Message-Id: <1478959269-18531-1-git-send-email-linus.walleij@linaro.org> Sender: stable-owner@vger.kernel.org List-ID: When locking a GPIO line as IRQ, we go to lengths to double-check that the line is really set as input before marking it as used for IRQ. This is not good on GPIO chips that can sleep, because this function is called in IRQ-safe context. Just skip this if it can't be checked quickly. Currently this happens on sleeping expanders such as STMPE or TC3589x: BUG: scheduling while atomic: swapper/1/0x00000002 Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.0-rc1+ #38 Hardware name: Nomadik STn8815 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (__schedule_bug+0x54/0x80) [] (__schedule_bug) from [] (__schedule+0x3a0/0x460) [] (__schedule) from [] (schedule+0x54/0xb8) (...) This patch fixes that problem and relies on the direction read from the chip when it was added. Cc: stable@vger.kernel.org Fixes: 9c10280d85c1 ("gpio: flush direction status in gpiochip_lock_as_irq()") Cc: Patrice Chotard Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0fc3a0d37c8..4575c2c5f293 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2664,8 +2664,11 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) if (IS_ERR(desc)) return PTR_ERR(desc); - /* Flush direction if something changed behind our back */ - if (chip->get_direction) { + /* + * If it's fast: flush the direction setting if something changed + * behind our back + */ + if (!chip->can_sleep && chip->get_direction) { int dir = chip->get_direction(chip, offset); if (dir) -- 2.7.4