From patchwork Fri Sep 9 15:17:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jon Hunter X-Patchwork-Id: 9323757 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 94ABF60752 for ; Fri, 9 Sep 2016 15:17:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 84FB329F4C for ; Fri, 9 Sep 2016 15:17:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7957B29F4E; Fri, 9 Sep 2016 15:17:49 +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=ham 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 6333C29F4C for ; Fri, 9 Sep 2016 15:17:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751121AbcIIPRr (ORCPT ); Fri, 9 Sep 2016 11:17:47 -0400 Received: from hqemgate15.nvidia.com ([216.228.121.64]:18301 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750882AbcIIPRq (ORCPT ); Fri, 9 Sep 2016 11:17:46 -0400 Received: from hqnvupgp08.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com id ; Fri, 09 Sep 2016 08:17:49 -0700 Received: from HQMAIL104.nvidia.com ([172.20.12.94]) by hqnvupgp08.nvidia.com (PGP Universal service); Fri, 09 Sep 2016 08:12:42 -0700 X-PGP-Universal: processed; by hqnvupgp08.nvidia.com on Fri, 09 Sep 2016 08:12:42 -0700 Received: from UKMAIL101.nvidia.com (10.26.138.13) by HQMAIL104.nvidia.com (172.18.146.11) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Fri, 9 Sep 2016 15:17:28 +0000 Received: from [10.21.132.106] (10.21.132.106) by UKMAIL101.nvidia.com (10.26.138.13) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Fri, 9 Sep 2016 15:17:21 +0000 Subject: Re: [PATCH 08/10] PM / Domains: Add support for removing PM domains To: Ulf Hansson References: <1471340976-5379-1-git-send-email-jonathanh@nvidia.com> <1471340976-5379-9-git-send-email-jonathanh@nvidia.com> CC: "Rafael J. Wysocki" , Kevin Hilman , Thierry Reding , Kukjin Kim , Krzysztof Kozlowski , "Alexander Aring" , Eric Anholt , "linux-pm@vger.kernel.org" , "linux-arm-kernel@lists.infradead.org" , "linux-tegra@vger.kernel.org" From: Jon Hunter Message-ID: <63871fe6-cda6-2a95-9c09-e4b3ebfa3419@nvidia.com> Date: Fri, 9 Sep 2016 16:17:33 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: X-Originating-IP: [10.21.132.106] X-ClientProxiedBy: DRUKMAIL102.nvidia.com (10.25.59.20) To UKMAIL101.nvidia.com (10.26.138.13) 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 On 09/09/16 14:54, Jon Hunter wrote: > On 08/09/16 12:49, Ulf Hansson wrote: >> On 16 August 2016 at 11:49, Jon Hunter wrote: >>> The genpd framework allows users to add PM domains via the pm_genpd_init() >>> function, however, there is no corresponding function to remove a PM >>> domain. For most devices this may be fine as the PM domains are never >>> removed, however, for devices that wish to populate the PM domains from >>> within a driver, having the ability to remove a PM domain if the probing >>> of the device fails or the driver is unloaded is necessary. >>> >>> Add the function pm_genpd_remove() to remove a PM domain by referencing >>> it's generic_pm_domain structure. >>> >>> PM domains can only be removed if they are not a parent domain to >>> another PM domain and have no devices associated with them. >> >> I think we should also check if the there's is a provider registered >> for the genpd, as it should also prevent the genpd from being removed. >> Right? > > Yes I would agree. I had thought that after patch #4 of this series that > only the provider itself would be able to call this. However, we should > probably still verify that the provider has correctly remove itself. So now I have the following. I am still not 100% happy. I cannot clear the ->provider when calling of_genpd_del_provider() and so I cannot use this to verify if the provider is present and so I need to check the list of providers and it gets a bit messy. I have been wracking my brains to find a better alternative (including a single function to remove the provider and domains at once but there are issues with that as well). I think that long term it may make sense to reference the providers exclusively by the fwnode_handle and make the list of provider non-DT specific. I could do it now, but it would increase the series. Cheers Jon --- drivers/base/power/domain.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 +++ 2 files changed, 94 insertions(+) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 82f87038f108..57c64fc1a164 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -39,6 +39,8 @@ static LIST_HEAD(gpd_list); static DEFINE_MUTEX(gpd_list_lock); +static bool genpd_provider_present(struct device_node *np); + /* * Get the generic PM domain for a particular struct device. * This validates the struct device pointer, the PM domain pointer, @@ -1356,6 +1358,68 @@ int pm_genpd_init(struct generic_pm_domain *genpd, } EXPORT_SYMBOL_GPL(pm_genpd_init); +static int genpd_remove(struct generic_pm_domain *genpd) +{ + struct gpd_link *l, *link; + + if (IS_ERR_OR_NULL(genpd)) + return -EINVAL; + + mutex_lock(&genpd->lock); + + if (is_of_node(genpd->provider)) { + if (genpd_provider_present(to_of_node(genpd->provider))) { + mutex_unlock(&genpd->lock); + pr_err("Provider present, unable to remove %s\n", + genpd->name); + return -EBUSY; + } + } + + if (!list_empty(&genpd->master_links) || genpd->device_count) { + mutex_unlock(&genpd->lock); + pr_err("%s: unable to remove %s\n", __func__, genpd->name); + return -EBUSY; + } + + list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) { + list_del(&link->master_node); + list_del(&link->slave_node); + kfree(link); + } + + list_del(&genpd->gpd_list_node); + mutex_unlock(&genpd->lock); + cancel_work_sync(&genpd->power_off_work); + pr_debug("%s: removed %s\n", __func__, genpd->name); + + return 0; +} + +/** + * pm_genpd_remove - Remove a generic I/O PM domain + * @genpd: Pointer to PM domain that is to be removed. + * + * To remove the PM domain, this function: + * - Removes the PM domain as a subdomain to any parent domains, + * if it was added. + * - Removes the PM domain from the list of registered PM domains. + * + * The PM domain will only be removed, if it is not a parent to any + * other PM domain and has no devices associated with it. + */ +int pm_genpd_remove(struct generic_pm_domain *genpd) +{ + int ret; + + mutex_lock(&gpd_list_lock); + ret = genpd_remove(genpd); + mutex_unlock(&gpd_list_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(pm_genpd_remove); + #ifdef CONFIG_PM_GENERIC_DOMAINS_OF typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, @@ -1563,6 +1627,26 @@ void of_genpd_del_provider(struct device_node *np) EXPORT_SYMBOL_GPL(of_genpd_del_provider); /** + * genpd_provider_present() - Verify if a PM domain provider is present + * @np: Device node pointer associated with the PM domain provider + */ +static bool genpd_provider_present(struct device_node *np) +{ + struct of_genpd_provider *cp; + + mutex_lock(&of_genpd_mutex); + list_for_each_entry(cp, &of_genpd_providers, link) { + if (cp->node == np) { + mutex_unlock(&of_genpd_mutex); + return true; + } + } + mutex_unlock(&of_genpd_mutex); + + return false; +} + +/** * genpd_get_from_provider() - Look-up PM domain * @genpdspec: OF phandle args to use for look-up * @@ -1798,6 +1882,11 @@ out: return ret ? -EPROBE_DEFER : 0; } EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); +#else +static bool genpd_provider_present(struct device_node *np) +{ + return false; +} #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index e71764ac7248..4aa285e44eb0 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -129,6 +129,7 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *target); extern int pm_genpd_init(struct generic_pm_domain *genpd, struct dev_power_governor *gov, bool is_off); +extern int pm_genpd_remove(struct generic_pm_domain *genpd); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; @@ -164,6 +165,10 @@ static inline int pm_genpd_init(struct generic_pm_domain *genpd, { return -ENOSYS; } +static inline int pm_genpd_remove(struct generic_pm_domain *genpd) +{ + return -ENOTSUPP; +} #endif static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,