From patchwork Sat Aug 17 14:56:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 2845995 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9A2BDBF546 for ; Sat, 17 Aug 2013 14:57:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8A2AC2022F for ; Sat, 17 Aug 2013 14:57:45 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 569382022D for ; Sat, 17 Aug 2013 14:57:44 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VAhwX-0000lj-PO; Sat, 17 Aug 2013 14:57:30 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VAhwV-0006sQ-IP; Sat, 17 Aug 2013 14:57:27 +0000 Received: from mail-lb0-f170.google.com ([209.85.217.170]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VAhwR-0006rw-HU for linux-arm-kernel@lists.infradead.org; Sat, 17 Aug 2013 14:57:24 +0000 Received: by mail-lb0-f170.google.com with SMTP id r10so2082535lbi.29 for ; Sat, 17 Aug 2013 07:56:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=7Ck6AxGAjDvkBr8OIp+qhlHHkPZOxwrNuCJtML47FO0=; b=Sg9E8MW8e1boclgIf5ekHS2grDqjSOnFSbBs5WhukRegB755y6Anzx9IKpr2wv4aD0 cVX3x9xK502tXvY4+b9HFBPHPEakrsPgXMilWzDQ5wa2jWrcUjQSOnXQg7rRgu8qaoIT zmTKcgfuCC6wrVb7JnkYs63KYBxbPPppVC14LU19fxEUEjdI7wk2M+MAlAxLOrXu6iab xwiYD2vK/moPn901XNYyJJPbokuyPvwn8wZh1n8u9RPvpuDTJemGpp+5PHT37ThPMbBC HWQRl4NZufuvvh8zT+VMU89E2xGqvRhHg7/iZx/DadcER+VNMqvC54GGcQcMwIdH8i1/ Usrg== X-Gm-Message-State: ALoCoQlSWChMo5JrU5qAXRXohpx399jya5UryJjud4HHoaiW7kHKjhHpAlERVwpnUfSTBcw5qGx+ X-Received: by 10.152.120.37 with SMTP id kz5mr3138295lab.21.1376751419724; Sat, 17 Aug 2013 07:56:59 -0700 (PDT) Received: from localhost.localdomain (c83-249-210-71.bredband.comhem.se. [83.249.210.71]) by mx.google.com with ESMTPSA id ao4sm1084945lac.1.1969.12.31.16.00.00 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Sat, 17 Aug 2013 07:56:58 -0700 (PDT) From: Linus Walleij To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v2] pinctrl: queue GPIO operations instead of defering Date: Sat, 17 Aug 2013 16:56:50 +0200 Message-Id: <1376751410-14560-1-git-send-email-linus.walleij@linaro.org> X-Mailer: git-send-email 1.8.1.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130817_105723_882277_DE80323C X-CRM114-Status: GOOD ( 20.51 ) X-Spam-Score: -2.6 (--) Cc: Lars Poeschel , Linus Walleij , Stephen Warren , Haojian Zhuang , Javier Martinez Canillas X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 We currently defer probing of the caller if a pinctrl GPIO request or direction setting comes in before the range mapping a certain GPIO to a certain pin controller is available. This can end up with a circular dependency: the GPIO driver needs the pin controller to be ready and the pin controller need the GPIO driver to be ready. This also happens if pin controllers and GPIO controllers compiled as modules are inserted in a certain order. To break this circular dependence, queue any GPIO operations coming to the framework until the range is ready, instead of deferring the probe of the caller. On the Nomadik we get this situation with the pinctrl driver when moving to requesting GPIOs off the gpiochip right after it has been added, and with this patch the boot dilemma is sorted out nicely, as can be seen in this condensed bootlog: pinctrl core: initialized pinctrl subsystem gpio 101e4000.gpio: at address cc852000 gpio 101e5000.gpio: at address cc854000 gpio 101e6000.gpio: at address cc856000 pinctrl core: queueing pinctrl request for GPIO 104 gpio 101e7000.gpio: at address cc858000 pinctrl core: requested queued GPIO 104 pinctrl-nomadik pinctrl.0: initialized Nomadik pin control driver ChangeLog v1->v2: - Apart from queueing requests, also queue direction setting operations. Cc: Haojian Zhuang Cc: Lars Poeschel Cc: Javier Martinez Canillas Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index a97b717..41c7479 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -404,7 +404,111 @@ static int pinctrl_get_device_gpio_range(unsigned gpio, } } - return -EPROBE_DEFER; + return -EINVAL; +} + +/** + * enum pinctrl_gpio_operation - queued operations type for GPIOs + * @PINCTRL_GPIO_REQUEST: queued request operation + * @PINCTRL_SET_DIR_OUT: queued set as output operation + * @PINCTRL_SET_DIR_IN: queued set as input operation + */ +enum pinctrl_gpio_operation { + PINCTRL_GPIO_REQUEST, + PINCTRL_GPIO_DIR_OUT, + PINCTRL_GPIO_DIR_IN, +}; + +/** + * struct pinctrl_gpio_op - a queue list holder + * @node: a list node for list processing + * @gpio: the targeted gpio for this operation + * @request: true of this is a request, then the gpio will be requested + * @input: if this is not a request, we're setting the direction + * Queued GPIO range-based deferred operations are stored in this list. + */ +struct pinctrl_gpio_op { + struct list_head node; + int gpio; + enum pinctrl_gpio_operation op; +}; + +static LIST_HEAD(pinctrl_queued_gpio_ops); + +static int pinctrl_queue_gpio_operation(int gpio, + enum pinctrl_gpio_operation op) +{ + struct pinctrl_gpio_op *qop; + + /* + * We get to this point if pinctrl_*_gpio() is called + * from a GPIO driver which does not yet have a registered + * pinctrl driver backend, and thus no ranges are defined for + * it. This could happen during system start up or if we're + * probing pin controllers as modules. Queue the request and + * handle it when and if the range arrives. + */ + qop = kzalloc(sizeof(struct pinctrl_gpio_op), GFP_KERNEL); + if (!qop) + return -ENOMEM; + qop->gpio = gpio; + qop->op = op; + list_add_tail(&qop->node, &pinctrl_queued_gpio_ops); + pr_info("queueing pinctrl request for GPIO %d\n", qop->gpio); + return 0; +} + + +/** + * pinctrl_process_queued_gpio_ops() - process queued GPIO operations + * + * This is called whenever a new GPIO range is added to see if some GPIO + * driver has outstanding operations to GPIOs in the range, and then these + * get processed at this point. + */ +static void pinctrl_process_queued_gpio_ops(void) +{ + struct list_head *node, *tmp; + + list_for_each_safe(node, tmp, &pinctrl_queued_gpio_ops) { + struct pinctrl_gpio_op *op = + list_entry(node, struct pinctrl_gpio_op, node); + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range *range; + int pin; + int ret; + + ret = pinctrl_get_device_gpio_range(op->gpio, &pctldev, &range); + if (ret) + continue; + + /* Convert to the pin controllers number space */ + pin = gpio_to_pin(range, op->gpio); + + switch(op->op) { + case PINCTRL_GPIO_REQUEST: + ret = pinmux_request_gpio(pctldev, range, pin, op->gpio); + if (ret) + pr_err("failed to request queued GPIO %d\n", + op->gpio); + else + pr_info("requested queued GPIO %d\n", op->gpio); + break; + case PINCTRL_GPIO_DIR_IN: + case PINCTRL_GPIO_DIR_OUT: + ret = pinmux_gpio_direction(pctldev, range, pin, + op->op == PINCTRL_GPIO_DIR_IN); + if (ret) + pr_err("failed to set direction on queued GPIO %d\n", + op->gpio); + break; + default: + pr_err("unknown queued GPIO operation\n"); + break; + } + list_del(node); + kfree(op); + } } /** @@ -421,6 +525,8 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev, mutex_lock(&pctldev->mutex); list_add_tail(&range->node, &pctldev->gpio_ranges); mutex_unlock(&pctldev->mutex); + /* Maybe we have outstanding GPIO requests for this range? */ + pinctrl_process_queued_gpio_ops(); } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range); @@ -552,8 +658,8 @@ int pinctrl_request_gpio(unsigned gpio) ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { if (pinctrl_ready_for_gpio_range(gpio)) - ret = 0; - return ret; + return 0; + return pinctrl_queue_gpio_operation(gpio, PINCTRL_GPIO_REQUEST); } /* Convert to the pin controllers number space */ @@ -604,7 +710,16 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input) ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { - return ret; + /* Maybe this pin does not have a pinctrl back-end at all? */ + if (pinctrl_ready_for_gpio_range(gpio)) + return 0; + /* Que the operation until the range arrives */ + if (input) + return pinctrl_queue_gpio_operation(gpio, + PINCTRL_GPIO_DIR_IN); + else + return pinctrl_queue_gpio_operation(gpio, + PINCTRL_GPIO_DIR_OUT); } mutex_lock(&pctldev->mutex);