From patchwork Fri Apr 15 09:13:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 65885 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp1067294qge; Fri, 15 Apr 2016 02:14:12 -0700 (PDT) X-Received: by 10.98.65.14 with SMTP id o14mr27621035pfa.151.1460711652451; Fri, 15 Apr 2016 02:14:12 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p19si1438659pfi.248.2016.04.15.02.14.12; Fri, 15 Apr 2016 02:14:12 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753704AbcDOJN7 (ORCPT + 29 others); Fri, 15 Apr 2016 05:13:59 -0400 Received: from mailout1.w1.samsung.com ([210.118.77.11]:54034 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753362AbcDOJNv (ORCPT ); Fri, 15 Apr 2016 05:13:51 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O5O007K04AZCU70@mailout1.w1.samsung.com>; Fri, 15 Apr 2016 10:13:48 +0100 (BST) X-AuditID: cbfec7f4-f796c6d000001486-f4-5710b0cb3d2a Received: from eusync3.samsung.com ( [203.254.199.213]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 09.7E.05254.BC0B0175; Fri, 15 Apr 2016 10:13:47 +0100 (BST) Received: from amdc1339.digital.local ([106.116.147.30]) by eusync3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O5O00FAX4AVIY90@eusync3.samsung.com>; Fri, 15 Apr 2016 10:13:47 +0100 (BST) From: Marek Szyprowski To: linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Marek Szyprowski , Russell King - ARM Linux , Ulf Hansson , Greg Kroah-Hartman , Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz Subject: [PATCH v8] drivers: amba: properly handle devices with power domains Date: Fri, 15 Apr 2016 11:13:32 +0200 Message-id: <1460711612-5268-1-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.2 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpnluLIzCtJLcpLzFFi42I5/e/4Vd3TGwTCDVb/ULbYOGM9q0Xz4vVs Fq9fGFpsenyN1eLyrjlsFjPO72OyuH2Z12LtkbvsFsfXhjtwerQ097B53Lm2h81j/9w17B6b l9R79G1ZxejxeZNcAFsUl01Kak5mWWqRvl0CV8aaq0oF7/UrOpbuZW9g3KbexcjJISFgInH1 3hFWCFtM4sK99WxdjFwcQgJLGSU67i2BcpqYJPYc2AhWxSZgKNH1tosNxBYRyJaYv7ebHaSI WWAFk0T/wwdgCWEBX4nFDbuZQGwWAVWJqa/fM4PYvALuElfm97BDrJOT+P9yBdMERu4FjAyr GEVTS5MLipPScw31ihNzi0vz0vWS83M3MUKC58sOxsXHrA4xCnAwKvHwPogVCBdiTSwrrsw9 xCjBwawkwvtwPVCINyWxsiq1KD++qDQntfgQozQHi5I479xd70OEBNITS1KzU1MLUotgskwc nFINjLkljRkskxJ8vupeK/JYdtj/8rbHZ35MkTq7yXzNwtmlNi7fo999Sj9mziZ0RP5IbIth SoLvN4ao6mN9x/S6/s5zP21tabLN9F7N0cNmRQ3nX+02371pbQHzowJ2s4qwmSaWJyZw98W2 /1mx+1nuJzUGl/OsGyZpG+WFmVy5nxcybYHbesXoL0osxRmJhlrMRcWJALvuEQ0aAgAA Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org To read pid/cid registers, the probed device need to be properly turned on. When it is inside a power domain, the bus code should ensure that the given power domain is enabled before trying to access device's registers. However in some cases power domain (or clocks) might not be yet available. Returning -EPROBE_DEFER is not a solution in such case, because callers don't handle this special error code. Instead such devices are added to the special list and their registration is retried from periodic worker until all resources are available. Signed-off-by: Marek Szyprowski --- Changelog: v8: - replaced notifier with periodic workqueue on Greg request v7: https://lkml.org/lkml/2016/4/13/201 - replaced late_initcall approach with a notifier registered to device core v6: https://lkml.org/lkml/2016/4/12/414 - got back to v1-style approach on Russell King request to avoid ABI break - use list for storing deferred devices and retry their registration from late_initcall v5: https://lkml.org/lkml/2016/2/10/179 - added 2 more patches to avoid regression with existing drivers (nvdimm and sa1111), for more information, see https://lkml.org/lkml/2015/12/17/390 - changed thread name to "AMBA: add complete support for power domains" v4: https://lkml.org/lkml/2015/12/2/52 - fixed more issues pointed by Ulf Hansson and Russell King v3: https://lkml.org/lkml/2015/12/1/334 - fixed issues pointed by Ulf Hansson - dropped patch for exynos4210 dts, because it already got queued for merging v2: https://lkml.org/lkml/2015/11/26/229 - added 2 patches from 'On-demand device probing' thread (https://lkml.org/lkml/2015/9/29/189), which move PID/CIR reading from amba_device_add() to amba_match() - moved dev_pm_domain_attach() to amba_match(), which is allowed to return -EPROBE_DEFER v1: http://www.spinics.net/lists/arm-kernel/msg463185.html - initial version --- drivers/amba/bus.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 10 deletions(-) -- 1.9.2 diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index f0099360039e..a5b5c87e2114 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -336,16 +336,7 @@ static void amba_device_release(struct device *dev) kfree(d); } -/** - * amba_device_add - add a previously allocated AMBA device structure - * @dev: AMBA device allocated by amba_device_alloc - * @parent: resource parent for this devices resources - * - * Claim the resource, and read the device cell ID if not already - * initialized. Register the AMBA device with the Linux device - * manager. - */ -int amba_device_add(struct amba_device *dev, struct resource *parent) +static int amba_device_try_add(struct amba_device *dev, struct resource *parent) { u32 size; void __iomem *tmp; @@ -373,6 +364,12 @@ int amba_device_add(struct amba_device *dev, struct resource *parent) goto err_release; } + ret = dev_pm_domain_attach(&dev->dev, true); + if (ret == -EPROBE_DEFER) { + iounmap(tmp); + goto err_release; + } + ret = amba_get_enable_pclk(dev); if (ret == 0) { u32 pid, cid; @@ -398,6 +395,7 @@ int amba_device_add(struct amba_device *dev, struct resource *parent) } iounmap(tmp); + dev_pm_domain_detach(&dev->dev, true); if (ret) goto err_release; @@ -421,6 +419,88 @@ int amba_device_add(struct amba_device *dev, struct resource *parent) err_out: return ret; } + +/* + * Registration of AMBA device require reading its pid and cid registers. + * To do this, the device must be turned on (if it is a part of power domain) + * and have clocks enabled. However in some cases those resources might not be + * yet available. Returning EPROBE_DEFER is not a solution in such case, + * because callers don't handle this special error code. Instead such devices + * are added to the special list and their registration is retried from + * periodic worker, until all resources are available and registration succeeds. + */ +struct deferred_device { + struct amba_device *dev; + struct resource *parent; + struct list_head node; +}; + +static LIST_HEAD(deferred_devices); +static DEFINE_MUTEX(deferred_devices_lock); + +static void amba_deferred_retry_func(struct work_struct *dummy); +static DECLARE_DELAYED_WORK(deferred_retry_work, amba_deferred_retry_func); + +#define DEFERRED_DEVICE_TIMEOUT (msecs_to_jiffies(5 * 1000)) + +static void amba_deferred_retry_func(struct work_struct *dummy) +{ + struct deferred_device *ddev, *tmp; + + mutex_lock(&deferred_devices_lock); + + list_for_each_entry_safe(ddev, tmp, &deferred_devices, node) { + int ret = amba_device_try_add(ddev->dev, ddev->parent); + + if (ret == -EPROBE_DEFER) + continue; + + list_del_init(&ddev->node); + kfree(ddev); + } + + if (!list_empty(&deferred_devices)) + schedule_delayed_work(&deferred_retry_work, + DEFERRED_DEVICE_TIMEOUT); + + mutex_unlock(&deferred_devices_lock); +} + +/** + * amba_device_add - add a previously allocated AMBA device structure + * @dev: AMBA device allocated by amba_device_alloc + * @parent: resource parent for this devices resources + * + * Claim the resource, and read the device cell ID if not already + * initialized. Register the AMBA device with the Linux device + * manager. + */ +int amba_device_add(struct amba_device *dev, struct resource *parent) +{ + int ret = amba_device_try_add(dev, parent); + + if (ret == -EPROBE_DEFER) { + struct deferred_device *ddev; + + ddev = kmalloc(sizeof(*ddev), GFP_KERNEL); + if (!ddev) + return -ENOMEM; + + ddev->dev = dev; + ddev->parent = parent; + ret = 0; + + mutex_lock(&deferred_devices_lock); + + if (list_empty(&deferred_devices)) + schedule_delayed_work(&deferred_retry_work, + DEFERRED_DEVICE_TIMEOUT); + list_add_tail(&ddev->node, &deferred_devices); + + mutex_unlock(&deferred_devices_lock); + } + return ret; +} EXPORT_SYMBOL_GPL(amba_device_add); static struct amba_device *