From patchwork Fri Apr 1 11:44:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 64847 Delivered-To: patch@linaro.org Received: by 10.112.199.169 with SMTP id jl9csp683691lbc; Fri, 1 Apr 2016 04:44:21 -0700 (PDT) X-Received: by 10.98.76.22 with SMTP id z22mr9165361pfa.78.1459511058566; Fri, 01 Apr 2016 04:44:18 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ly11si20891397pab.100.2016.04.01.04.44.18; Fri, 01 Apr 2016 04:44:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-gpio-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-gpio-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-gpio-owner@vger.kernel.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753104AbcDALoR (ORCPT + 4 others); Fri, 1 Apr 2016 07:44:17 -0400 Received: from mail-lf0-f48.google.com ([209.85.215.48]:35607 "EHLO mail-lf0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752565AbcDALoP (ORCPT ); Fri, 1 Apr 2016 07:44:15 -0400 Received: by mail-lf0-f48.google.com with SMTP id k79so79870619lfb.2 for ; Fri, 01 Apr 2016 04:44:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=Ej/RmxZGiOa6zIdCqM+8p5LUNSCocAX6Mkp4hUSb/d4=; b=WIOn5sNzUbfF5+Y3zd739XRvPN21dKN4jXaOz3i/4gsWhBUsv1o5DUMUX7eP3K40FJ 6wEmoFbVdgf+HdlSzErIqf20CUXJiQCYWH20uMliHAYje9KLDhOTSJ9geMix0ntvAbW1 ml1n553BUinIQWT79E+DRfWrt/9o69L3gpeCw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=Ej/RmxZGiOa6zIdCqM+8p5LUNSCocAX6Mkp4hUSb/d4=; b=ROU7bIZOkrj48nnhp/SCkfN8HCplqsBYvv3QCocz4rVzkovlogFNXMA7oldEGPBECq OqiYHd0jjzbSOsUFMnd3zXKl31rI48zFQJ/7Ivb2w3pFs++H8cyUqAbZa7jioG51donL bn23sV/uySTbRjvcCBMJmzRWYOwGxFHq+r1mtfzd/0O1blmEdDAHy8W9FMBqzYq9mK7B pB0ggsDHbY6975N26DPx5dOvTFEMISYf3vcp8AzNWuf+z7MoLs13pAfACWRn0BsRsfCU yhjWDkoPzS/3icX8k8CGS+b9o5Za1D0AVuI1Pocvd+HlojijQH2iCHmaaEoYwV16i/oW bJug== X-Gm-Message-State: AD7BkJL+8JptJ56Gs4XiJAUgKrJKJcp8qSzJXJeJkEUSfFxAtry6gFPYtZdsavOMItk3Wij0 X-Received: by 10.25.84.16 with SMTP id i16mr1678511lfb.88.1459511053934; Fri, 01 Apr 2016 04:44:13 -0700 (PDT) Received: from localhost.localdomain ([85.235.10.227]) by smtp.gmail.com with ESMTPSA id 102sm2122766lfy.41.2016.04.01.04.44.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Apr 2016 04:44:12 -0700 (PDT) From: Linus Walleij To: linux-gpio@vger.kernel.org, Alexandre Courbot , Alexander Stein Cc: Linus Walleij , linux-input@vger.kernel.org, Tomeu Vizoso , Guenter Roeck Subject: [PATCH] gpiolib: handle probe deferrals better Date: Fri, 1 Apr 2016 13:44:08 +0200 Message-Id: <1459511048-24084-1-git-send-email-linus.walleij@linaro.org> X-Mailer: git-send-email 2.4.3 Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org The gpiolib does not currently return probe deferrals from the .to_irq() hook while the GPIO drivers are being initialized. Further: it keeps returning -EPROBE_DEFER for gpio[d]_get() even after all builtin drivers have initialized. Fix this thusly: - Move the assignment of .to_irq() to the last step when using gpiolib_irqchip_add() so we can't get spurious calls into the .to_irq() function until all set-up is finished. - Put in a late_initcall_sync() to set a boolean state variable to indicate that we're not gonna defer any longer. Since deferred probe happens at late_initcall() time, using late_initcall_sync() should be fine. - After this point, return hard errors (-ENXIO) from both gpio[d]_get() and .to_irq(). This way we should (at least for all drivers using GPIOLIB_IRQCHIP) be getting proper deferrals from both gpio[d]_get() and .to_irq() until the irqchip side is properly set up, and then proper errors after all drivers should have been probed. This problem was first seen with gpio-keys. Cc: linux-input@vger.kernel.org Cc: Tomeu Vizoso Cc: Guenter Roeck Reported-by: Alexander Stein Signed-off-by: Linus Walleij --- Alexander: please test this, you need Guether's patches too, I have it all on my "fixes" branch in the GPIO git: https://git.kernel.org/cgit/linux/kernel/git/linusw/linux-gpio.git/log/?h=fixes Tomeu: I think you're the authority on deferred probe these days. Is this the right way for a subsystem to switch from returning -EPROBE_DEFER to instead returning an unrecoverable error? Guenther: I applied this on top of your patches, please check it if you can, you're smarter than me with this stuff. --- drivers/gpio/gpiolib.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b747c76fd2b1..426a93f9d79e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -68,7 +68,9 @@ LIST_HEAD(gpio_devices); static void gpiochip_free_hogs(struct gpio_chip *chip); static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); +/* These keep the state of the library */ static bool gpiolib_initialized; +static bool gpiolib_builtin_ready; static inline void desc_set_label(struct gpio_desc *d, const char *label) { @@ -1093,7 +1095,6 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, gpiochip->irqchip = irqchip; gpiochip->irq_handler = handler; gpiochip->irq_default_type = type; - gpiochip->to_irq = gpiochip_to_irq; gpiochip->lock_key = lock_key; gpiochip->irqdomain = irq_domain_add_simple(of_node, gpiochip->ngpio, first_irq, @@ -1129,6 +1130,12 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, } acpi_gpiochip_request_interrupts(gpiochip); + /* + * Wait with this until last, as someone may be asynchronously + * calling .to_irq() and needs to be getting probe deferrals until + * this point. + */ + gpiochip->to_irq = gpiochip_to_irq; return 0; } @@ -1366,12 +1373,21 @@ done: int gpiod_request(struct gpio_desc *desc, const char *label) { - int status = -EPROBE_DEFER; + int status; struct gpio_device *gdev; VALIDATE_DESC(desc); gdev = desc->gdev; + /* + * Defer requests until all built-in drivers have had a chance + * to probe, then give up and return a hard error. + */ + if (!gpiolib_builtin_ready) + status = -EPROBE_DEFER; + else + status = -ENXIO; + if (try_module_get(gdev->owner)) { status = __gpiod_request(desc, label); if (status < 0) @@ -1993,18 +2009,27 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep); * gpiod_to_irq() - return the IRQ corresponding to a GPIO * @desc: gpio whose IRQ will be returned (already requested) * - * Return the IRQ corresponding to the passed GPIO, or an error code in case of - * error. + * Return the IRQ corresponding to the passed GPIO, or an error code. */ int gpiod_to_irq(const struct gpio_desc *desc) { - struct gpio_chip *chip; - int offset; + struct gpio_chip *chip; + int offset; VALIDATE_DESC(desc); chip = desc->gdev->chip; offset = gpio_chip_hwgpio(desc); - return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; + + if (chip->to_irq) + return chip->to_irq(chip, offset); + /* + * We will wait for new GPIO drivers to arrive until the + * late initcalls. After that we stop deferring and return + * a hard error. + */ + if (!gpiolib_builtin_ready) + return -EPROBE_DEFER; + return -ENXIO; } EXPORT_SYMBOL_GPL(gpiod_to_irq); @@ -2883,6 +2908,14 @@ static int __init gpiolib_dev_init(void) } core_initcall(gpiolib_dev_init); +static int __init gpiolib_late_done(void) +{ + /* Flag that we're not deferring probes anymore */ + gpiolib_builtin_ready = true; + return 0; +} +late_initcall_sync(gpiolib_late_done); + #ifdef CONFIG_DEBUG_FS static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)