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: 19281 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qe0-f71.google.com (mail-qe0-f71.google.com [209.85.128.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id E5A5B248D9 for ; Sat, 17 Aug 2013 14:57:03 +0000 (UTC) Received: by mail-qe0-f71.google.com with SMTP id 1sf268019qee.2 for ; Sat, 17 Aug 2013 07:57:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-gm-message-state:delivered-to:from:to:cc:subject :date:message-id:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=7Ck6AxGAjDvkBr8OIp+qhlHHkPZOxwrNuCJtML47FO0=; b=gyOY1DZzx4KGgv9uOQif+bKF2BUI9B/N6OdBM29i566kPMK2sMTB7DeiZN1CAlj9lr CchhXviDLX4EHRgCUlQT7TUo2taNcgFonbv8klFdaTHfIunTJDo6TWOsrL8mJplPiSvH 1VYmgtCoSxt3YGBub7Ie4G9MHM3CcIFCj4Q9v+An58K1Wquzxjq6UtljP7KZ/b6I8JeH B6ipUfv/mPBjLxA+MOpyIMuAU4Fg6RYvMTscaUedsw/rxVIG4iBxH6NZe4vJCbcrbuPj HW6+4M4DSF4ym47FwChlczMkvxdb4IXvBe0K4ruSW7QKSO4LbdWoplsMk8Z7bkId9Y/9 N32g== X-Received: by 10.236.56.70 with SMTP id l46mr1162766yhc.2.1376751423056; Sat, 17 Aug 2013 07:57:03 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.110.195 with SMTP id ic3ls1139460qeb.62.gmail; Sat, 17 Aug 2013 07:57:02 -0700 (PDT) X-Received: by 10.58.211.227 with SMTP id nf3mr637490vec.20.1376751422889; Sat, 17 Aug 2013 07:57:02 -0700 (PDT) Received: from mail-vb0-f53.google.com (mail-vb0-f53.google.com [209.85.212.53]) by mx.google.com with ESMTPS id aj7si669896vec.21.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 17 Aug 2013 07:57:02 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.53 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.53; Received: by mail-vb0-f53.google.com with SMTP id i3so2354146vbh.12 for ; Sat, 17 Aug 2013 07:57:02 -0700 (PDT) X-Gm-Message-State: ALoCoQkfu2LFmkI3yAQvqQ0UrppF4Wh0TazWKM8UKdrHODNpnR/tsuPEw4xwYq5+wm6UweRdiyi4 X-Received: by 10.58.217.167 with SMTP id oz7mr3450981vec.15.1376751422481; Sat, 17 Aug 2013 07:57:02 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp11557vcz; Sat, 17 Aug 2013 07:57:01 -0700 (PDT) X-Received: by 10.112.126.37 with SMTP id mv5mr2445641lbb.20.1376751420816; Sat, 17 Aug 2013 07:57:00 -0700 (PDT) Received: from mail-la0-f48.google.com (mail-la0-f48.google.com [209.85.215.48]) by mx.google.com with ESMTPS id g2si1280134laa.167.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 17 Aug 2013 07:57:00 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.215.48 is neither permitted nor denied by best guess record for domain of linus.walleij@linaro.org) client-ip=209.85.215.48; Received: by mail-la0-f48.google.com with SMTP id er20so2256172lab.7 for ; Sat, 17 Aug 2013 07:56:59 -0700 (PDT) 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 Cc: Stephen Warren , Linus Walleij , Haojian Zhuang , Lars Poeschel , Javier Martinez Canillas 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-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: linus.walleij@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.53 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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);