From patchwork Fri Mar 21 14:46:25 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Jacques Hiblot X-Patchwork-Id: 3874831 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 C2062BF540 for ; Fri, 21 Mar 2014 14:50:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C950720295 for ; Fri, 21 Mar 2014 14:50:37 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id ABD2120279 for ; Fri, 21 Mar 2014 14:50:36 +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 1WR0mE-0001iY-RX; Fri, 21 Mar 2014 14:50: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 1WR0mC-0008J2-2N; Fri, 21 Mar 2014 14:50:28 +0000 Received: from mail-wg0-f52.google.com ([74.125.82.52]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WR0m7-0008H5-Gj for linux-arm-kernel@lists.infradead.org; Fri, 21 Mar 2014 14:50:25 +0000 Received: by mail-wg0-f52.google.com with SMTP id k14so1665059wgh.23 for ; Fri, 21 Mar 2014 07:49:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=XN5ApGzLxHCM44XV+/3hqVzdlEaBdH9G/YDtMt9W5KQ=; b=CLXO5H3MyUX0my/lkQG0TqN4xNKRmHcuiEpjFI3X/HhB0Nr8owrdtIe0xHSyRsUf3r GstUOEa4InJ9QdpKF3AG5jfQWHcIu4OmS/f9O+rhvr0YHnSZ2ejrGhtJ3c2ImTXL1rUb Xktz61E/eiG0CVhlpIyh9kpP9lGQ5EIQVsbLpL8yuZCMbDY3snWFkmqj/97BrOIvrDqK JiT+BcAlDQ4ywVuuctTUCced6txame46WSvcRgYH4sRtrxGhJJlxHEGqFKUnyuLp0sJu gr+ps2JmQgtx+s+6wxhcjjHNUWGDv7CHLw/AEQsbp3XHwsAxo/NxmutKHV4UoF5dWqRh bGew== X-Received: by 10.194.90.233 with SMTP id bz9mr12282551wjb.65.1395413398328; Fri, 21 Mar 2014 07:49:58 -0700 (PDT) Received: from stedf17-labo202.ds.jdsu.net. (4-161.80-90.static-ip.oleane.fr. [90.80.161.4]) by mx.google.com with ESMTPSA id bj3sm13805474wjb.14.2014.03.21.07.49.56 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 21 Mar 2014 07:49:57 -0700 (PDT) From: Jean-Jacques Hiblot To: grant.likely@secretlab.ca Subject: [PATCH v3 2/2] dt: platform driver: Fill the resources before probe and defer if needed Date: Fri, 21 Mar 2014 15:46:25 +0100 Message-Id: <1395413185-29763-3-git-send-email-jjhiblot@traphandler.com> X-Mailer: git-send-email 1.9.0 In-Reply-To: <1395413185-29763-1-git-send-email-jjhiblot@traphandler.com> References: <20140320161118.B7075C4067A@trevor.secretlab.ca> <1395413185-29763-1-git-send-email-jjhiblot@traphandler.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140321_105023_750931_8E57A8F4 X-CRM114-Status: GOOD ( 24.80 ) X-Spam-Score: -2.6 (--) Cc: devicetree@vger.kernel.org, Jean-Jacques Hiblot , gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, robh+dt@kernel.org, gregory.clement@free-electrons.com, linux-arm-kernel@lists.infradead.org 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=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_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 The goal of this patch is to allow drivers to be probed even if at the time of the DT parsing some of their IRQ ressources are not available yet. In the current situation, the IRQ resources of a platform device are filled from the DT at the time the device is created (of_device_alloc()). The drawback of this is that a device sitting close to the top of the DT (ahb for example) but depending on ressources that are initialized later (IRQ domain dynamically created for example) will fail to probe because the ressources don't exist at this time. This patch fills the resource structure only before the device is probed and will defer the probe if the IRQ resource is not yet available. Signed-off-by: Jean-Jacques Hiblot --- drivers/base/platform.c | 5 ++ drivers/of/platform.c | 114 ++++++++++++++++++++++++++++++++++---------- include/linux/device.h | 1 + include/linux/of_platform.h | 10 ++++ 4 files changed, 105 insertions(+), 25 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index bc78848..cee9b8d 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -481,6 +481,10 @@ static int platform_drv_probe(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); int ret; + ret = of_platform_device_prepare(dev); + if (ret) + goto error; + if (ACPI_HANDLE(_dev)) acpi_dev_pm_attach(_dev, true); @@ -488,6 +492,7 @@ static int platform_drv_probe(struct device *_dev) if (ret && ACPI_HANDLE(_dev)) acpi_dev_pm_detach(_dev, true); +error: if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported\n"); ret = -ENXIO; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 404d1da..ba6be4a 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -141,41 +141,17 @@ struct platform_device *of_device_alloc(struct device_node *np, struct device *parent) { struct platform_device *dev; - int rc, i, num_reg = 0, num_irq; - struct resource *res, temp_res; dev = platform_device_alloc("", -1); if (!dev) return NULL; - /* count the io and irq resources */ - if (of_can_translate_address(np)) - while (of_address_to_resource(np, num_reg, &temp_res) == 0) - num_reg++; - num_irq = of_irq_count(np); - - /* Populate the resource table */ - if (num_irq || num_reg) { - res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL); - if (!res) { - platform_device_put(dev); - return NULL; - } - - dev->num_resources = num_reg + num_irq; - dev->resource = res; - for (i = 0; i < num_reg; i++, res++) { - rc = of_address_to_resource(np, i, res); - WARN_ON(rc); - } - WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq); - } - dev->dev.of_node = of_node_get(np); #if defined(CONFIG_MICROBLAZE) dev->dev.dma_mask = &dev->archdata.dma_mask; #endif dev->dev.parent = parent; + dev->dev.of_device = 1; if (bus_id) dev_set_name(&dev->dev, "%s", bus_id); @@ -233,6 +209,94 @@ static struct platform_device *of_platform_device_create_pdata( return dev; } +static int of_reg_count(struct device_node *np) +{ + int nreg = 0; + if (of_can_translate_address(np)) { + struct resource temp_res; + while (of_address_to_resource(np, nreg, &temp_res) == 0) + nreg++; + } + return nreg; +} + +int of_platform_device_prepare(struct platform_device *dev) +{ + struct device_node *np; + int i, irq_index; + struct resource *res; + + /* + * This function applies only devices described in the DT and + * created by of_device_alloc(). + * Other platform devices have their ressources already populated. + */ + np = dev->dev.of_node; + if (!np || !dev->dev.of_device) + return 0; + + /* Populate the resource table */ + if (!dev->resource) { + int rc, nreg = 0, nirq; + /* count the io and irq resources */ + nreg = of_reg_count(np); + nirq = of_irq_count(np); + + if (!nirq && !nreg) + return 0; + + res = kzalloc(sizeof(*res) * (nirq + nreg), GFP_KERNEL); + if (!res) + return -ENOMEM; + + dev->resource = res; + dev->num_resources = nreg + nirq; + + for (i = 0; i < nreg; i++, res++) { + rc = of_address_to_resource(np, i, res); + if (WARN_ON(rc)) { + /* THIS IS BAD; don't try to defer probing */ + dev->num_resources = 0; + dev->resource = NULL; + kfree(res); + return rc; + } + } + + if (!rc && of_irq_to_resource_table(np, res, nirq) != nirq) + /* + * Not all irqs can be translated. redo the irq + * resources to check if the probe can be deferred + */ + goto redo_irq_resources; + + return 0; + } + +redo_irq_resources: + /* See which IRQ resources need to be redone */ + irq_index = 0; + for (i = 0, res = dev->resource; i < dev->num_resources; i++, res++) { + if (!res->flags) { + int rc; + /* + * If the IRQ can't be translated to a resource, check + * if its IRQ domain exists. + */ + rc = of_irq_to_resource(np, irq_index, res); + if (!rc) { + if (of_find_irq_domain(np, irq_index) == NULL) + return -EPROBE_DEFER; + return rc; + } + irq_index++; + } else if (res->flags & IORESOURCE_IRQ) + irq_index++; + } + return 0; +} +EXPORT_SYMBOL(of_platform_device_prepare); + /** * of_platform_device_create - Alloc, initialize and register an of_device * @np: pointer to node to create device for diff --git a/include/linux/device.h b/include/linux/device.h index 952b010..eb6ac66 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -785,6 +785,7 @@ struct device { bool offline_disabled:1; bool offline:1; + bool of_device:1; }; static inline struct device *kobj_to_dev(struct kobject *kobj) diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 05cb4a9..4e487ff 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -53,6 +53,16 @@ struct of_dev_auxdata { extern const struct of_device_id of_default_bus_match_table[]; +/* Populate the resource for a platform device */ +#ifdef CONFIG_OF +int of_platform_device_prepare(struct platform_device *dev); +#else +static inline int of_platform_device_prepare( + struct platform_device *dev) +{ + return 0; +} +#endif /* Platform drivers register/unregister */ extern struct platform_device *of_device_alloc(struct device_node *np, const char *bus_id,