From patchwork Tue Sep 20 10:28:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jon Hunter X-Patchwork-Id: 9341415 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 331CB607D0 for ; Tue, 20 Sep 2016 10:28:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2351629E91 for ; Tue, 20 Sep 2016 10:28:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 17FF629EBB; Tue, 20 Sep 2016 10:28:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4CD9C29E91 for ; Tue, 20 Sep 2016 10:28:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753805AbcITK2g (ORCPT ); Tue, 20 Sep 2016 06:28:36 -0400 Received: from hqemgate16.nvidia.com ([216.228.121.65]:18752 "EHLO hqemgate16.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753745AbcITK2d (ORCPT ); Tue, 20 Sep 2016 06:28:33 -0400 Received: from hqnvupgp08.nvidia.com (Not Verified[216.228.121.13]) by hqemgate16.nvidia.com id ; Tue, 20 Sep 2016 03:28:29 -0700 Received: from HQMAIL103.nvidia.com ([172.20.187.11]) by hqnvupgp08.nvidia.com (PGP Universal service); Tue, 20 Sep 2016 03:22:55 -0700 X-PGP-Universal: processed; by hqnvupgp08.nvidia.com on Tue, 20 Sep 2016 03:22:55 -0700 Received: from HQMAIL105.nvidia.com (172.20.187.12) by HQMAIL103.nvidia.com (172.20.187.11) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Tue, 20 Sep 2016 10:27:56 +0000 Received: from hqnvemgw01.nvidia.com (172.20.150.20) by HQMAIL105.nvidia.com (172.20.187.12) with Microsoft SMTP Server id 15.0.1210.3 via Frontend Transport; Tue, 20 Sep 2016 10:27:56 +0000 Received: from jonathanh-lm.nvidia.com (Not Verified[10.21.132.118]) by hqnvemgw01.nvidia.com with Trustwave SEG (v7, 5, 5, 8150) id ; Tue, 20 Sep 2016 03:27:56 -0700 From: Jon Hunter To: "Rafael J. Wysocki" , Kevin Hilman , Ulf Hansson CC: , , , Jon Hunter Subject: [RFC PATCH 2/3] PM / Domains: Add support for devices with multiple domains Date: Tue, 20 Sep 2016 11:28:06 +0100 Message-ID: <1474367287-10402-3-git-send-email-jonathanh@nvidia.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1474367287-10402-1-git-send-email-jonathanh@nvidia.com> References: <1474367287-10402-1-git-send-email-jonathanh@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some devices may require more than one PM domain to operate and this is not currently by the PM domain framework. Furthermore, the current Linux 'device' structure only allows devices to be associated with a single PM domain and so cannot easily be associated with more than one. To allow devices to be associated with more than one PM domain, if multiple domains are defined for a given device (eg. via device-tree), then: 1. Create a new PM domain for this device. The name of the new PM domain created matches the device name for which it was created for. 2. Register the new PM domain as a sub-domain for all PM domains required by the device. 3. Attach the device to the new PM domain. By default the newly created PM domain is assumed to be in the 'off' state to ensure that any parent PM domains will be turned on if not already on when the new PM domain is turned on. When a device associated with more than one PM domain is detached, wait for any power-off work to complete, then remove the PM domain that was created for the device by calling pm_genpd_remove() (this also removes it as a child to any other PM domains) and free the memory for the PM domain. For devices using device-tree, devices that require multiple PM domains are detected by seeing if the 'power-domains' property has more than one entry defined. Signed-off-by: Jon Hunter --- Here is an example output from pm_genpd_summary following this change for the Tegra210 XHCI device: domain status slaves /device runtime status ---------------------------------------------------------------------- 70090000.usb on /devices/platform/70090000.usb unsupported xusbc on 70090000.usb xusbb off-0 xusba on 70090000.usb I am not sure if this is confusing to have a device and domain with the same name. So let me know if you have any thoughts! drivers/base/power/domain.c | 102 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 382735949591..ee39824c03b3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1826,7 +1826,7 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) { struct generic_pm_domain *pd; unsigned int i; - int ret = 0; + int count, ret = 0; pd = genpd_lookup_dev(dev); if (!pd) @@ -1851,6 +1851,19 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) /* Check if PM domain can be powered off after removing this device. */ genpd_queue_power_off_work(pd); + + count = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (count > 1) { + cancel_work_sync(&pd->power_off_work); + + ret = pm_genpd_remove(pd); + if (ret < 0) + dev_err(dev, "failed to remove PM domain %s: %d\n", + pd->name, ret); + + kfree(pd); + } } static void genpd_dev_pm_sync(struct device *dev) @@ -1898,6 +1911,73 @@ static int genpd_dev_pm_attach_device(struct device *dev, } +static int genpd_dev_pm_attach_one(struct device *dev) +{ + struct generic_pm_domain *pd; + int ret; + + mutex_lock(&gpd_list_lock); + pd = genpd_dev_pm_lookup(dev, 0); + if (IS_ERR(pd)) { + mutex_unlock(&gpd_list_lock); + return PTR_ERR(pd); + } + + ret = genpd_dev_pm_attach_device(dev, pd); + mutex_unlock(&gpd_list_lock); + + return ret; +} + +static int genpd_dev_pm_attach_many(struct device *dev, unsigned int count) +{ + struct generic_pm_domain *pd, *parent; + unsigned int i; + int ret; + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + pd->name = dev_name(dev); + + ret = pm_genpd_init(pd, NULL, true); + if (ret < 0) + goto err_free; + + mutex_lock(&gpd_list_lock); + for (i = 0; i < count; i++) { + parent = genpd_dev_pm_lookup(dev, i); + if (IS_ERR(parent)) { + ret = PTR_ERR(parent); + goto err_remove; + } + + ret = genpd_add_subdomain(parent, pd); + if (ret < 0) + goto err_remove; + + } + + ret = genpd_dev_pm_attach_device(dev, pd); + if (ret < 0) + goto err_remove; + + mutex_unlock(&gpd_list_lock); + + return ret; + +err_remove: + WARN_ON(genpd_remove(pd)); + + mutex_unlock(&gpd_list_lock); + +err_free: + kfree(pd); + + return ret; +} + /** * genpd_dev_pm_attach - Attach a device to its PM domain using DT. * @dev: Device to attach. @@ -1915,8 +1995,7 @@ static int genpd_dev_pm_attach_device(struct device *dev, */ int genpd_dev_pm_attach(struct device *dev) { - struct generic_pm_domain *pd; - int ret; + int count; if (!dev->of_node) return -ENODEV; @@ -1924,17 +2003,12 @@ int genpd_dev_pm_attach(struct device *dev) if (dev->pm_domain) return -EEXIST; - mutex_lock(&gpd_list_lock); - pd = genpd_dev_pm_lookup(dev, 0); - if (IS_ERR(pd)) { - mutex_unlock(&gpd_list_lock); - return -EPROBE_DEFER; - } - - ret = genpd_dev_pm_attach_device(dev, pd); - mutex_lock(&gpd_list_lock); - - return ret; + count = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (count > 1) + return genpd_dev_pm_attach_many(dev, count); + else + return genpd_dev_pm_attach_one(dev); } EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */