PM / Domains: Add support for removing PM domains
Subsystems (8)
Jon Hunter
maintainerv2 cover PM / Domains: Add support for removing PM domains
In order to safely remove PM domains there are a few changes that need to be made to ensure that no one is holding an external reference to a PM domain after it has been removed. One solution, implemented here, solves this by eliminating external references to PM domain.
Changes from V1:
- Added test when removing a PM domain to ensure the PM domain provider has been removed.
- Re-organised patches 8-10 so that patch #8 adds the code to verify if the provider is present, patch #9 adds basic support for removing PM domains and patch #10 adds support for removing PM domains by provider.
Changes from initial RFC:
- Renamed functions made static per Ulf's feedback.
- Added patch to clean-up provider/xlate APIs per Ulf's feedback
- Re-worked and simplified the association between PM domains and PM domain providers. Dropped the 'provider_data' variable from the generic_pm_domain structure in favour of using the fwnode_handle.
- Split patch for removing PM domains into multiple patches per Ulf's feedback.
Jon Hunter (10):
PM / Domains: Add new helper functions for device-tree
ARM: EXYNOS: Remove calls to of_genpd_get_from_provider()
staging: board: Remove calls to of_genpd_get_from_provider() PM / Domains: Don't expose generic_pm_domain structure to clients PM / Domains: Don't expose xlate and provider helper functions PM / Domains: Verify the PM domain is present when adding a provider PM / Domains: Prepare for adding support to remove PM domains PM / Domains: Store the provider in the PM domain structure PM / Domains: Add support for removing PM domains
PM / Domains: Add support for removing nested PM domains by provider
drivers/base/power/domain.c | 353 +++++++++++++++++++++++++++++++++++---- drivers/soc/samsung/pm_domains.c | 23 +-- drivers/staging/board/board.c | 9 +- include/linux/pm_domain.h | 74 ++++---- 4 files changed, 364 insertions(+), 95 deletions(-)
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 1/10 PM / Domains: Add new helper functions for device-tree
Ideally, if we are returning a reference to a PM domain via a call to of_genpd_get_from_provider(), then we should keep track of such references via a reference count. The reference count could then be used to determine if a PM domain can be safely removed. Alternatively, it is possible to avoid such external references by providing APIs to access the PM domain and hence, eliminate any calls to of_genpd_get_from_provider().
Add new helper functions for adding a device and a subdomain to a PM domain when using device-tree, so that external calls to of_genpd_get_from_provider() can be removed.
--- drivers/base/power/domain.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 16 ++++++++++++++++ 2 files changed, 62 insertions(+)
drivers/base/power/domain.c +46 -0
@@ -1502,6 +1502,52 @@ struct generic_pm_domain *of_genpd_get_from_provider(EXPORT_SYMBOL_GPL (of_genpd_get_from_provider);/** +* of_genpd_add_device() - Add a device to an I/O PM domain +* @genpdspec: OF phandle args to use for look-up PM domain +* @dev: Device to be added. +* +* Looks-up an I/O PM domain based upon phandle args provided and adds +* the device to the PM domain. Returns a negative error code on failure. +*/ +int of_genpd_add_device (struct of_phandle_args *genpdspec,struct device *dev) +{ +struct generic_pm_domain *genpd; + + genpd =of_genpd_get_from_provider (genpdspec); +if (IS_ERR (genpd)) +return PTR_ERR (genpd); + +return pm_genpd_add_device (genpd, dev); +} +EXPORT_SYMBOL_GPL (of_genpd_add_device); + +/** +* of_genpd_add_subdomain - Add a subdomain to an I/O PM domain. +* @parent_spec: OF phandle args to use for parent PM domain look-up +* @subdomain_spec: OF phandle args to use for subdomain look-up +* +* Looks-up a parent PM domain and subdomain based upon phandle args +* provided and adds the subdomain to the parent PM domain. Returns a +* negative error code on failure. +*/ +int of_genpd_add_subdomain (struct of_phandle_args *parent_spec, +struct of_phandle_args *subdomain_spec) +{ +struct generic_pm_domain *parent, *subdomain; + + parent =of_genpd_get_from_provider (parent_spec); +if (IS_ERR (parent)) +return PTR_ERR (parent); + + subdomain =of_genpd_get_from_provider (subdomain_spec); +if (IS_ERR (subdomain)) +return PTR_ERR (subdomain); + +return pm_genpd_add_subdomain (parent, subdomain); +} +EXPORT_SYMBOL_GPL (of_genpd_add_subdomain); + +/** * genpd_dev_pm_detach - Detach a device from its PM domain. * @dev: Device to detach. * @power_off: Currently not used
include/linux/pm_domain.h +16 -0
@@ -208,6 +208,10 @@ struct generic_pm_domain *__of_genpd_xlate_simple(struct generic_pm_domain *__of_genpd_xlate_onecell (struct of_phandle_args *genpdspec,void *data); +extern int of_genpd_add_device (struct of_phandle_args *args, +struct device *dev); +extern int of_genpd_add_subdomain (struct of_phandle_args *parent, +struct of_phandle_args *new_subdomain);int genpd_dev_pm_attach (struct device *dev);#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
@@ -227,6 +231,18 @@ static inline struct generic_pm_domain *of_genpd_get_from_provider(#define __of_genpd_xlate_simple NULL#define __of_genpd_xlate_onecell NULL +static inline int of_genpd_add_device (struct of_phandle_args *args, +struct device *dev) +{ +return -ENODEV ; +} + +static inline int of_genpd_add_subdomain (struct of_phandle_args *parent, +struct of_phandle_args *new_subdomain) +{ +return -ENODEV ; +} +static inline int genpd_dev_pm_attach (struct device *dev) {return -ENODEV ;
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 2/10 ARM: EXYNOS: Remove calls to of_genpd_get_from_provider()
In reply to Jon HunterUpdate the EXYNOS PM domain code to use the of_genpd_add_subdomain() and remove any calls to of_genpd_get_from_provider().
--- drivers/soc/samsung/pm_domains.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-)
drivers/soc/samsung/pm_domains.c +8 -15
@@ -215,29 +215,22 @@ static __init int exynos4_pm_init_power_domain(void)/* Assign the child power domains to their parents */ for_each_matching_node (np, exynos_pm_domain_of_match) { -struct generic_pm_domain *child_domain, *parent_domain; -struct of_phandle_args args; +struct of_phandle_args child, parent; - args.np = np; - args.args_count =0 ; - child_domain =of_genpd_get_from_provider (&args); -if (IS_ERR (child_domain)) -continue ; + child.np = np; + child.args_count =0 ;if (of_parse_phandle_with_args (np,"power-domains" , -"#power-domain-cells" ,0 , &args) !=0 ) -continue ; - - parent_domain =of_genpd_get_from_provider (&args); -if (IS_ERR (parent_domain)) +"#power-domain-cells" ,0 , + &parent) !=0 )continue ; -if (pm_genpd_add_subdomain (parent_domain, child_domain)) +if (of_genpd_add_subdomain (&parent, &child))pr_warn ("%s failed to add subdomain: %s\n" , - parent_domain->name, child_domain->name); + parent.np->name, child.np->name);else pr_info ("%s has as child subdomain: %s.\n" , - parent_domain->name, child_domain->name); + parent.np->name, child.np->name); }return 0 ;
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 3/10 staging: board: Remove calls to of_genpd_get_from_provider()
In reply to Jon HunterUpdate the staging/board PM domain code to use the of_genpd_add_subdomain() and remove any calls to of_genpd_get_from_provider().
--- drivers/staging/board/board.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/staging/board/board.c +1 -8
@@ -140,7 +140,6 @@ static int board_staging_add_dev_domain(struct platform_device *pdev, const char *domain) {struct of_phandle_args pd_args; -struct generic_pm_domain *pd;struct device_node *np; np =of_find_node_by_path (domain);
@@ -151,14 +150,8 @@ static int board_staging_add_dev_domain(struct platform_device *pdev, pd_args.np = np; pd_args.args_count =0 ; - pd =of_genpd_get_from_provider (&pd_args); -if (IS_ERR (pd)) { -pr_err ("Cannot find genpd %s (%ld)\n" , domain,PTR_ERR (pd)); -return PTR_ERR (pd); - } -pr_debug ("Found genpd %s for device %s\n" , pd->name, pdev->name); -return pm_genpd_add_device (pd, &pdev->dev); +return of_genpd_add_device (&pd_args, &pdev->dev); }#else static inline int board_staging_add_dev_domain(struct platform_device *pdev,
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 4/10 PM / Domains: Don't expose generic_pm_domain structure to clients
In reply to Jon HunterThere should be no need to expose the generic_pm_domain structure to clients and this eliminates the need to implement reference counting for any external reference to a PM domain. Therefore, make the functions pm_genpd_lookup_dev() and of_genpd_get_from_provider() private to the PM domain core. The functions are renamed in accordance with the naming conventions for genpd static functions.
--- drivers/base/power/domain.c | 19 +++++++++---------- include/linux/pm_domain.h | 14 -------------- 2 files changed, 9 insertions(+), 24 deletions(-)
drivers/base/power/domain.c +9 -10
@@ -45,7 +45,7 @@ static DEFINE_MUTEX(gpd_list_lock);* and checks that the PM domain pointer is a real generic PM domain. * Any failure results in NULL being returned. */ -struct generic_pm_domain *pm_genpd_lookup_dev (struct device *dev) +static struct generic_pm_domain *genpd_lookup_dev (struct device *dev) {struct generic_pm_domain *genpd =NULL , *gpd;
@@ -1119,7 +1119,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,dev_dbg (dev,"%s()\n" , __func__); -if (!genpd || genpd !=pm_genpd_lookup_dev (dev)) +if (!genpd || genpd !=genpd_lookup_dev (dev))return -EINVAL ;/* The above validation also means we have existing domain_data. */
@@ -1466,7 +1466,7 @@ void of_genpd_del_provider(struct device_node *np)EXPORT_SYMBOL_GPL (of_genpd_del_provider);/** -* of_genpd_get_from_provider() - Look-up PM domain +* genpd_get_from_provider() - Look-up PM domain * @genpdspec: OF phandle args to use for look-up * * Looks for a PM domain provider under the node specified by @genpdspec and if
@@ -1476,7 +1476,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);* Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() * on failure. */ -struct generic_pm_domain *of_genpd_get_from_provider ( +static struct generic_pm_domain *genpd_get_from_provider (struct of_phandle_args *genpdspec) {struct generic_pm_domain *genpd =ERR_PTR (-ENOENT );
@@ -1499,7 +1499,6 @@ struct generic_pm_domain *of_genpd_get_from_provider(return genpd; } -EXPORT_SYMBOL_GPL (of_genpd_get_from_provider);/** * of_genpd_add_device() - Add a device to an I/O PM domain
@@ -1513,7 +1512,7 @@ int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev) {struct generic_pm_domain *genpd; - genpd =of_genpd_get_from_provider (genpdspec); + genpd =genpd_get_from_provider (genpdspec);if (IS_ERR (genpd))return PTR_ERR (genpd);
@@ -1535,11 +1534,11 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, {struct generic_pm_domain *parent, *subdomain; - parent =of_genpd_get_from_provider (parent_spec); + parent =genpd_get_from_provider (parent_spec);if (IS_ERR (parent))return PTR_ERR (parent); - subdomain =of_genpd_get_from_provider (subdomain_spec); + subdomain =genpd_get_from_provider (subdomain_spec);if (IS_ERR (subdomain))return PTR_ERR (subdomain);
@@ -1561,7 +1560,7 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)unsigned int i;int ret =0 ; - pd =pm_genpd_lookup_dev (dev); + pd =genpd_lookup_dev (dev);if (!pd)return ;
@@ -1642,7 +1641,7 @@ int genpd_dev_pm_attach(struct device *dev)return -ENOENT ; } - pd =of_genpd_get_from_provider (&pd_args); + pd =genpd_get_from_provider (&pd_args);of_node_put (pd_args.np);if (IS_ERR (pd)) { dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
include/linux/pm_domain.h +0 -14
@@ -116,7 +116,6 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)return to_gpd_data (dev->power.subsys_data->domain_data); } -extern struct generic_pm_domain *pm_genpd_lookup_dev (struct device *dev);extern int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev,struct gpd_timing_data *td);
@@ -138,10 +137,6 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) {return ERR_PTR (-ENOSYS ); } -static inline struct generic_pm_domain *pm_genpd_lookup_dev (struct device *dev) -{ -return NULL ; -}static inline int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev,struct gpd_timing_data *td)
@@ -199,9 +194,6 @@ typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,int __of_genpd_add_provider (struct device_node *np,genpd_xlate_t xlate,void *data);void of_genpd_del_provider (struct device_node *np); -struct generic_pm_domain *of_genpd_get_from_provider ( -struct of_phandle_args *genpdspec); -struct generic_pm_domain *__of_genpd_xlate_simple (struct of_phandle_args *genpdspec,void *data);
@@ -222,12 +214,6 @@ static inline int __of_genpd_add_provider(struct device_node *np, }static inline void of_genpd_del_provider (struct device_node *np) {} -static inline struct generic_pm_domain *of_genpd_get_from_provider ( -struct of_phandle_args *genpdspec) -{ -return NULL ; -} -#define __of_genpd_xlate_simple NULL#define __of_genpd_xlate_onecell NULL
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 5/10 PM / Domains: Don't expose xlate and provider helper functions
In reply to Jon HunterFunctions __of_genpd_xlate_simple(), __of_genpd_xlate_onecell() and __of_genpd_add_provider() are not used outside of the core generic PM domain code. Therefore, reduce the number of APIs exposed by making these static. At the same time don't expose the typedef for genpd_xlate_t either and make this a local definition as well.
The functions are renamed to follow the naming conventions for static functions in the generic PM domain core.
--- drivers/base/power/domain.c | 49 ++++++++++++++++++++++++++++++++++----------- include/linux/pm_domain.h | 42 +++++++++++++------------------------- 2 files changed, 51 insertions(+), 40 deletions(-)
drivers/base/power/domain.c +37 -12
@@ -1329,6 +1329,10 @@ int pm_genpd_init(struct generic_pm_domain *genpd,EXPORT_SYMBOL_GPL (pm_genpd_init);#ifdef CONFIG_PM_GENERIC_DOMAINS_OF + +typedef struct generic_pm_domain *(*genpd_xlate_t )(struct of_phandle_args *args, +void *data); +/* * Device Tree based PM domain providers. *
@@ -1340,8 +1344,8 @@ EXPORT_SYMBOL_GPL(pm_genpd_init);* maps a PM domain specifier retrieved from the device tree to a PM domain. * * Two simple mapping functions have been provided for convenience: -* - __of_genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. -* - __of_genpd_xlate_onecell() for mapping of multiple PM domains per node by +* - genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. +* - genpd_xlate_onecell() for mapping of multiple PM domains per node by * index. */
@@ -1366,7 +1370,7 @@ static LIST_HEAD(of_genpd_providers);static DEFINE_MUTEX (of_genpd_mutex);/** -* __of_genpd_xlate_simple() - Xlate function for direct node-domain mapping +* genpd_xlate_simple() - Xlate function for direct node-domain mapping * @genpdspec: OF phandle args to map into a PM domain * @data: xlate function private data - pointer to struct generic_pm_domain *
@@ -1374,7 +1378,7 @@ static DEFINE_MUTEX(of_genpd_mutex);* have their own device tree nodes. The private data of xlate function needs * to be a valid pointer to struct generic_pm_domain. */ -struct generic_pm_domain *__of_genpd_xlate_simple ( +static struct generic_pm_domain *genpd_xlate_simple (struct of_phandle_args *genpdspec,void *data) {
@@ -1382,10 +1386,9 @@ struct generic_pm_domain *__of_genpd_xlate_simple(return ERR_PTR (-EINVAL );return data; } -EXPORT_SYMBOL_GPL (__of_genpd_xlate_simple);/** -* __of_genpd_xlate_onecell() - Xlate function using a single index. +* genpd_xlate_onecell() - Xlate function using a single index. * @genpdspec: OF phandle args to map into a PM domain * @data: xlate function private data - pointer to struct genpd_onecell_data *
@@ -1394,7 +1397,7 @@ EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple);* A single cell is used as an index into an array of PM domains specified in * the genpd_onecell_data struct when registering the provider. */ -struct generic_pm_domain *__of_genpd_xlate_onecell ( +static struct generic_pm_domain *genpd_xlate_onecell (struct of_phandle_args *genpdspec,void *data) {
@@ -1414,16 +1417,15 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(return genpd_data->domains[idx]; } -EXPORT_SYMBOL_GPL (__of_genpd_xlate_onecell);/** -* __of_genpd_add_provider() - Register a PM domain provider for a node +* genpd_add_provider() - Register a PM domain provider for a node * @np: Device node pointer associated with the PM domain provider. * @xlate: Callback for decoding PM domain from phandle arguments. * @data: Context pointer for @xlate callback. */ -int __of_genpd_add_provider (struct device_node *np,genpd_xlate_t xlate, -void *data) +static int genpd_add_provider (struct device_node *np,genpd_xlate_t xlate, +void *data) {struct of_genpd_provider *cp;
@@ -1442,7 +1444,30 @@ int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,return 0 ; } -EXPORT_SYMBOL_GPL (__of_genpd_add_provider); + +/** +* of_genpd_add_provider_simple() - Register a simple PM domain provider +* @np: Device node pointer associated with the PM domain provider. +* @genpd: Pointer to PM domain associated with the PM domain provider. +*/ +int of_genpd_add_provider_simple (struct device_node *np, +struct generic_pm_domain *genpd) +{ +return genpd_add_provider (np, genpd_xlate_simple, genpd); +} +EXPORT_SYMBOL_GPL (of_genpd_add_provider_simple); + +/** +* of_genpd_add_provider_onecell() - Register a onecell PM domain provider +* @np: Device node pointer associated with the PM domain provider. +* @data: Pointer to the data associated with the PM domain provider. +*/ +int of_genpd_add_provider_onecell (struct device_node *np, +struct genpd_onecell_data *data) +{ +return genpd_add_provider (np, genpd_xlate_onecell, data); +} +EXPORT_SYMBOL_GPL (of_genpd_add_provider_onecell);/** * of_genpd_del_provider() - Remove a previously registered PM domain provider
include/linux/pm_domain.h +14 -28
65 lines not on this page · raw message
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 6/10 PM / Domains: Verify the PM domain is present when adding a provider
In reply to Jon HunterWhen a PM domain provider is added, there is currently no way to tell if any PM domains associated with the provider are present. Naturally, the PM domain provider should not be registered if the PM domains have not been added. Nonetheless, verify that the PM domain(s) associated with a provider are present when registering the PM domain provider.
This change adds a dependency on the function pm_genpd_present() when CONFIG_PM_GENERIC_DOMAINS_OF is enabled and so ensure this function is available when CONFIG_PM_GENERIC_DOMAINS_OF selected.
--- drivers/base/power/domain.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
drivers/base/power/domain.c +38 -3
@@ -586,7 +586,7 @@ static int __init genpd_poweroff_unused(void) }late_initcall (genpd_poweroff_unused); -#ifdef CONFIG_PM_SLEEP +#if defined(CONFIG_PM_SLEEP ) || defined(CONFIG_PM_GENERIC_DOMAINS_OF )/** * pm_genpd_present - Check if the given PM domain has been initialized.
@@ -606,6 +606,10 @@ static bool pm_genpd_present(const struct generic_pm_domain *genpd)return false; } +#endif + +#ifdef CONFIG_PM_SLEEP +static bool genpd_dev_active_wakeup (struct generic_pm_domain *genpd,struct device *dev) {
@@ -1453,7 +1457,19 @@ static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,int of_genpd_add_provider_simple (struct device_node *np,struct generic_pm_domain *genpd) { -return genpd_add_provider (np, genpd_xlate_simple, genpd); +int ret = -EINVAL ; + +if (!np || !genpd) +return -EINVAL ; + +mutex_lock (&gpd_list_lock); + +if (pm_genpd_present (genpd)) + ret =genpd_add_provider (np, genpd_xlate_simple, genpd); + +mutex_unlock (&gpd_list_lock); + +return ret; }EXPORT_SYMBOL_GPL (of_genpd_add_provider_simple);
@@ -1465,7 +1481,26 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);int of_genpd_add_provider_onecell (struct device_node *np,struct genpd_onecell_data *data) { -return genpd_add_provider (np, genpd_xlate_onecell, data); +unsigned int i; +int ret; + +if (!np || !data) +return -EINVAL ; + +mutex_lock (&gpd_list_lock); + +for (i =0 ; i < data->num_domains; i++) { +if (!pm_genpd_present (data->domains[i])) { +mutex_unlock (&gpd_list_lock); +return -EINVAL ; + } + } + + ret =genpd_add_provider (np, genpd_xlate_onecell, data); + +mutex_unlock (&gpd_list_lock); + +return ret; }EXPORT_SYMBOL_GPL (of_genpd_add_provider_onecell);
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 7/10 PM / Domains: Prepare for adding support to remove PM domains
In reply to Jon HunterIn order to remove PM domains safely from the list of PM domains, it is necessary to adding locking for the PM domain list around any places where devices or subdomains are added to a PM domain.
There are places where a reference to a PM domain is obtained via calling of_genpd_get_from_provider() before adding the device or the subdomain. In these cases a lock for the PM domain list needs to be held around the call to of_genpd_get_from_provider() and the call to add the device/subdomain. To avoid deadlocks by multiple attempts to obtain the PM domain list lock, add functions genpd_add_device() and genpd_add_subdomain() which require the user to hold the PM domain list lock when calling.
--- drivers/base/power/domain.c | 97 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 24 deletions(-)
drivers/base/power/domain.c +73 -24
@@ -1060,14 +1060,8 @@ static void genpd_free_dev_data(struct device *dev,dev_pm_put_subsys_data (dev); } -/** -* __pm_genpd_add_device - Add a device to an I/O PM domain. -* @genpd: PM domain to add the device to. -* @dev: Device to be added. -* @td: Set of PM QoS timing parameters to attach to the device. -*/ -int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev, -struct gpd_timing_data *td) +static int genpd_add_device (struct generic_pm_domain *genpd,struct device *dev, +struct gpd_timing_data *td) {struct generic_pm_domain_data *gpd_data;int ret =0 ;
@@ -1107,6 +1101,24 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,return ret; } + +/** +* __pm_genpd_add_device - Add a device to an I/O PM domain. +* @genpd: PM domain to add the device to. +* @dev: Device to be added. +* @td: Set of PM QoS timing parameters to attach to the device. +*/ +int __pm_genpd_add_device (struct generic_pm_domain *genpd,struct device *dev, +struct gpd_timing_data *td) +{ +int ret; + +mutex_lock (&gpd_list_lock); + ret =genpd_add_device (genpd, dev, td); +mutex_unlock (&gpd_list_lock); + +return ret; +}EXPORT_SYMBOL_GPL (__pm_genpd_add_device);/**
@@ -1160,13 +1172,8 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, }EXPORT_SYMBOL_GPL (pm_genpd_remove_device); -/** -* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. -* @genpd: Master PM domain to add the subdomain to. -* @subdomain: Subdomain to be added. -*/ -int pm_genpd_add_subdomain (struct generic_pm_domain *genpd, -struct generic_pm_domain *subdomain) +static int genpd_add_subdomain (struct generic_pm_domain *genpd, +struct generic_pm_domain *subdomain) {struct gpd_link *link, *itr;int ret =0 ;
@@ -1209,6 +1216,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,kfree (link);return ret; } + +/** +* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. +* @genpd: Master PM domain to add the subdomain to. +* @subdomain: Subdomain to be added. +*/ +int pm_genpd_add_subdomain (struct generic_pm_domain *genpd, +struct generic_pm_domain *subdomain) +{ +int ret; + +mutex_lock (&gpd_list_lock); + ret =genpd_add_subdomain (genpd, subdomain); +mutex_unlock (&gpd_list_lock); + +return ret; +}EXPORT_SYMBOL_GPL (pm_genpd_add_subdomain);/**
@@ -1571,12 +1595,22 @@ static struct generic_pm_domain *genpd_get_from_provider(int of_genpd_add_device (struct of_phandle_args *genpdspec,struct device *dev) {struct generic_pm_domain *genpd; +int ret; + +mutex_lock (&gpd_list_lock); genpd =genpd_get_from_provider (genpdspec); -if (IS_ERR (genpd)) -return PTR_ERR (genpd); +if (IS_ERR (genpd)) { + ret =PTR_ERR (genpd); + goto out; + } + + ret =genpd_add_device (genpd, dev,NULL ); -return pm_genpd_add_device (genpd, dev); +out: +mutex_unlock (&gpd_list_lock); + +return ret; }EXPORT_SYMBOL_GPL (of_genpd_add_device);
@@ -1593,16 +1627,28 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, struct of_phandle_args *subdomain_spec) {struct generic_pm_domain *parent, *subdomain; +int ret; + +mutex_lock (&gpd_list_lock); parent =genpd_get_from_provider (parent_spec); -if (IS_ERR (parent)) -return PTR_ERR (parent); +if (IS_ERR (parent)) { + ret =PTR_ERR (parent); + goto out; + } subdomain =genpd_get_from_provider (subdomain_spec); -if (IS_ERR (subdomain)) -return PTR_ERR (subdomain); +if (IS_ERR (subdomain)) { + ret =PTR_ERR (subdomain); + goto out; + } + + ret =genpd_add_subdomain (parent, subdomain); -return pm_genpd_add_subdomain (parent, subdomain); +out: +mutex_unlock (&gpd_list_lock); + +return ret; }EXPORT_SYMBOL_GPL (of_genpd_add_subdomain);
@@ -1701,9 +1747,11 @@ int genpd_dev_pm_attach(struct device *dev)return -ENOENT ; } +mutex_lock (&gpd_list_lock); pd =genpd_get_from_provider (&pd_args);of_node_put (pd_args.np);if (IS_ERR (pd)) { +mutex_unlock (&gpd_list_lock);dev_dbg (dev,"%s() failed to find PM domain: %ld\n" , __func__,PTR_ERR (pd));return -EPROBE_DEFER ;
@@ -1712,13 +1760,14 @@ int genpd_dev_pm_attach(struct device *dev)dev_dbg (dev,"adding to PM domain %s\n" , pd->name);for (i =1 ; i <GENPD_RETRY_MAX_MS ; i <<=1 ) { - ret =pm_genpd_add_device (pd, dev); + ret =genpd_add_device (pd, dev,NULL );if (ret != -EAGAIN )break ;mdelay (i);cond_resched (); } +mutex_unlock (&gpd_list_lock);if (ret <0 ) { dev_err(dev, "failed to add to PM domain %s: %d",
Signature · 1 line
2.1.4
Jon Hunter
maintainerPATCH v2 8/10 PM / Domains: Store the provider in the PM domain structure
In reply to Jon HunterIt is possible that a device has more than one provider of PM domains and to support the removal of a PM domain by provider, it is necessary to store a reference to the provider in the PM domain structure. Therefore, store a reference to the firmware node handle in the PM domain structure and populate it when providers (only device-tree based providers are currently supported by PM domains) are registered.
Please note that when removing PM domains, it is necessary to verify that the PM domain provider has been removed from the list of providers before the PM domain can be removed. To do this add another member to the PM domain structure that indicates if the provider is present and set this member accordingly when providers are added and removed.
Initialise the 'provider' and 'has_provider' members of the generic_pm_domain structure when a PM domains is added by calling pm_genpd_init().
--- drivers/base/power/domain.c | 42 +++++++++++++++++++++++++++++++++++++----- include/linux/pm_domain.h | 2 ++ 2 files changed, 39 insertions(+), 5 deletions(-)
drivers/base/power/domain.c +37 -5
@@ -1306,6 +1306,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->device_count =0 ; genpd->max_off_time_ns =-1 ; genpd->max_off_time_changed = true; + genpd->provider =NULL ; + genpd->has_provider = false; genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; genpd->domain.ops.runtime_resume = genpd_runtime_resume; genpd->domain.ops.prepare = pm_genpd_prepare;
@@ -1491,6 +1493,11 @@ int of_genpd_add_provider_simple(struct device_node *np,if (pm_genpd_present (genpd)) ret =genpd_add_provider (np, genpd_xlate_simple, genpd); +if (!ret) { + genpd->provider = &np->fwnode; + genpd->has_provider = true; + } +mutex_unlock (&gpd_list_lock);return ret;
@@ -1506,7 +1513,7 @@ int of_genpd_add_provider_onecell(struct device_node *np, struct genpd_onecell_data *data) {unsigned int i; -int ret; +int ret = -EINVAL ;if (!np || !data)return -EINVAL ;
@@ -1514,13 +1521,26 @@ int of_genpd_add_provider_onecell(struct device_node *np,mutex_lock (&gpd_list_lock);for (i =0 ; i < data->num_domains; i++) { -if (!pm_genpd_present (data->domains[i])) { -mutex_unlock (&gpd_list_lock); -return -EINVAL ; - } +if (!pm_genpd_present (data->domains[i])) + goto error; + + data->domains[i]->provider = &np->fwnode; + data->domains[i]->has_provider = true; } ret =genpd_add_provider (np, genpd_xlate_onecell, data); +if (ret <0 ) + goto error; + +mutex_unlock (&gpd_list_lock); + +return 0 ; + +error: +while (i--) { + data->domains[i]->provider =NULL ; + data->domains[i]->has_provider = false; + }mutex_unlock (&gpd_list_lock);
@@ -1535,10 +1555,21 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell);void of_genpd_del_provider (struct device_node *np) {struct of_genpd_provider *cp; +struct generic_pm_domain *gpd; +mutex_lock (&gpd_list_lock);mutex_lock (&of_genpd_mutex);list_for_each_entry (cp, &of_genpd_providers, link) {if (cp->node == np) { +/* +* For each PM domain associated with the +* provider, set the 'has_provider' to false +* so that the PM domain can be safely removed. +*/ +list_for_each_entry (gpd, &gpd_list, gpd_list_node) +if (gpd->provider == &np->fwnode) + gpd->has_provider = false; +list_del (&cp->link);of_node_put (cp->node);kfree (cp);
@@ -1546,6 +1577,7 @@ void of_genpd_del_provider(struct device_node *np) } }mutex_unlock (&of_genpd_mutex); +mutex_unlock (&gpd_list_lock); }EXPORT_SYMBOL_GPL (of_genpd_del_provider);
include/linux/pm_domain.h +2 -0
@@ -51,6 +51,8 @@ struct generic_pm_domain {struct mutex lock;struct dev_power_governor *gov;struct work_struct power_off_work; +struct fwnode_handle *provider;/* Identity of the domain provider */ +bool has_provider;const char *name;atomic_t sd_count;/* Number of subdomains with power "on" */ enum gpd_status status;/* Current state of the domain */
Signature · 1 line
2.1.4
PATCH v2 8/10 PM / Domains: Store the provider in the PM domain structure
Quoted 13 lines · Jon Hunter
It is possible that a device has more than one provider of PM domains and to support the removal of a PM domain by provider, it is necessary to store a reference to the provider in the PM domain structure. Therefore, store a reference to the firmware node handle in the PM domain structure and populate it when providers (only device-tree based providers are currently supported by PM domains) are registered.
Please note that when removing PM domains, it is necessary to verify that the PM domain provider has been removed from the list of providers before the PM domain can be removed. To do this add another member to the PM domain structure that indicates if the provider is present and set this member accordingly when providers are added and removed.
Quoted 5 lines
Initialise the 'provider' and '
has_provider' members of thegeneric_pm_domainstructure when a PM domains is added by callingpm_genpd_init().Signed-off-by Jon Hunter <[email protected]>
Kind regards
Uffe
Quoted 116 lines
--- drivers/base/power/domain.c | 42 +++++++++++++++++++++++++++++++++++++----- include/linux/pm_domain.h | 2 ++ 2 files changed, 39 insertions(+), 5 deletions(-)drivers/base/power/domain.c +37
-5@@ -1306,6 +1306,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->device_count =0 ; genpd->max_off_time_ns =-1 ; genpd->max_off_time_changed = true; + genpd->provider =NULL ; + genpd->has_provider = false; genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; genpd->domain.ops.runtime_resume = genpd_runtime_resume; genpd->domain.ops.prepare = pm_genpd_prepare;@@ -1491,6 +1493,11 @@ int of_genpd_add_provider_simple(struct device_node *np,if (pm_genpd_present (genpd)) ret =genpd_add_provider (np, genpd_xlate_simple, genpd); +if (!ret) { + genpd->provider = &np->fwnode; + genpd->has_provider = true; + } +mutex_unlock (&gpd_list_lock);return ret;@@ -1506,7 +1513,7 @@ int of_genpd_add_provider_onecell(struct device_node *np, struct genpd_onecell_data *data) {unsigned int i; -int ret; +int ret = -EINVAL ;if (!np || !data)return -EINVAL ;@@ -1514,13 +1521,26 @@ int of_genpd_add_provider_onecell(struct device_node *np,mutex_lock (&gpd_list_lock);for (i =0 ; i < data->num_domains; i++) { -if (!pm_genpd_present (data->domains[i])) { -mutex_unlock (&gpd_list_lock); -return -EINVAL ; - } +if (!pm_genpd_present (data->domains[i])) + goto error; + + data->domains[i]->provider = &np->fwnode; + data->domains[i]->has_provider = true; } ret =genpd_add_provider (np, genpd_xlate_onecell, data); +if (ret <0 ) + goto error; + +mutex_unlock (&gpd_list_lock); + +return 0 ; + +error: +while (i--) { + data->domains[i]->provider =NULL ; + data->domains[i]->has_provider = false; + }mutex_unlock (&gpd_list_lock);@@ -1535,10 +1555,21 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell);void of_genpd_del_provider (struct device_node *np) {struct of_genpd_provider *cp; +struct generic_pm_domain *gpd; +mutex_lock (&gpd_list_lock);mutex_lock (&of_genpd_mutex);list_for_each_entry (cp, &of_genpd_providers, link) {if (cp->node == np) { +/* +* For each PM domain associated with the +* provider, set the 'has_provider' to false +* so that the PM domain can be safely removed. +*/ +list_for_each_entry (gpd, &gpd_list, gpd_list_node) +if (gpd->provider == &np->fwnode) + gpd->has_provider = false; +list_del (&cp->link);of_node_put (cp->node);kfree (cp);@@ -1546,6 +1577,7 @@ void of_genpd_del_provider(struct device_node *np) } }mutex_unlock (&of_genpd_mutex); +mutex_unlock (&gpd_list_lock); }EXPORT_SYMBOL_GPL (of_genpd_del_provider);include/linux/pm_domain.h +2
-1@@ -51,6 +51,8 @@ struct generic_pm_domain {struct mutex lock;struct dev_power_governor *gov;struct work_struct power_off_work; +struct fwnode_handle *provider;/* Identity of the domain provider */ +bool has_provider;const char *name;atomic_t sd_count;/* Number of subdomains with power "on" */ enum gpd_status status;/* Current state of the domain */ --2.1.4
Jon Hunter
maintainerPATCH v2 9/10 PM / Domains: Add support for removing PM domains
In reply to Jon HunterThe 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. Note that the bulk of the code that removes the PM domain is placed in a separate local function genpd_remove() (which is called by pm_genpd_remove()). The code is structured in this way to prepare for adding another function to remove a PM domain by provider that will also call genpd_remove(). Note that users of genpd_remove() must call this function with the mutex, gpd_list_lock, held.
PM domains can only be removed if the associated provider has been removed, they are not a parent domain to another PM domain and have no devices associated with them.
--- drivers/base/power/domain.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 ++++ 2 files changed, 65 insertions(+)
drivers/base/power/domain.c +60 -0
@@ -1358,6 +1358,66 @@ 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 (genpd->has_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 the associated provider has +* been removed, 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,
include/linux/pm_domain.h +5 -0
@@ -130,6 +130,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;
@@ -165,6 +166,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,
Signature · 1 line
2.1.4
PATCH v2 9/10 PM / Domains: Add support for removing PM domains
Quoted 16 lines · Jon Hunter
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'sgeneric_pm_domainstructure. Note that the bulk of the code that removes the PM domain is placed in a separate local functiongenpd_remove()(which is called bypm_genpd_remove()). The code is structured in this way to prepare for adding another function to remove a PM domain by provider that will also callgenpd_remove(). Note that users ofgenpd_remove()must call this function with the mutex,gpd_list_lock, held.
Quoted 5 lines
PM domains can only be removed if the associated provider has been removed, they are not a parent domain to another PM domain and have no devices associated with them.
Signed-off-by Jon Hunter <[email protected]>
Kind regards
Uffe
Quoted 102 lines
--- drivers/base/power/domain.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 ++++ 2 files changed, 65 insertions(+)drivers/base/power/domain.c +60
-0@@ -1358,6 +1358,66 @@ 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 (genpd->has_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 the associated provider has +* been removed, 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,include/linux/pm_domain.h +5
-1@@ -130,6 +130,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;@@ -165,6 +166,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, --2.1.4
Jon Hunter
maintainerPATCH v2 10/10 PM / Domains: Add support for removing nested PM domains by provider
In reply to Jon HunterIf a device supports PM domains that are subdomains of another PM domain, then the PM domains should be removed in reverse order to ensure that the subdomains are removed first. Furthermore, if there is more than one provider, then there needs to be a way to remove the domains in reverse order for a specific provider.
Add the function of_genpd_remove_last() to remove the last PM domain added by a given PM domain provider and return the generic_pm_domain structure for the PM domain that was removed.
--- drivers/base/power/domain.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 7 +++++++ 2 files changed, 42 insertions(+)
drivers/base/power/domain.c +35 -0
@@ -1745,6 +1745,41 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,EXPORT_SYMBOL_GPL (of_genpd_add_subdomain);/** +* of_genpd_remove_last - Remove the last PM domain registered for a provider +* @provider: Pointer to device structure associated with provider +* +* Find the last PM domain that was added by a particular provider and +* remove this PM domain from the list of PM domains. The provider is +* identified by the 'provider' device structure that is passed. The PM +* domain will only be removed, if the provider associated with domain +* has been removed. +* +* Returns a valid pointer to struct generic_pm_domain on success or +* ERR_PTR() on failure. +*/ +struct generic_pm_domain *of_genpd_remove_last (struct device_node *np) +{ +struct generic_pm_domain *gpd, *genpd =ERR_PTR (-ENOENT ); +int ret; + +if (IS_ERR_OR_NULL (np)) +return ERR_PTR (-EINVAL ); + +mutex_lock (&gpd_list_lock); +list_for_each_entry (gpd, &gpd_list, gpd_list_node) { +if (gpd->provider == &np->fwnode) { + ret =genpd_remove (gpd); + genpd = ret ?ERR_PTR (ret) : gpd; +break ; + } + } +mutex_unlock (&gpd_list_lock); + +return genpd; +} +EXPORT_SYMBOL_GPL (of_genpd_remove_last); + +/** * genpd_dev_pm_detach - Detach a device from its PM domain. * @dev: Device to detach. * @power_off: Currently not used
include/linux/pm_domain.h +7 -0
@@ -204,6 +204,7 @@ extern int of_genpd_add_device(struct of_phandle_args *args, struct device *dev);extern int of_genpd_add_subdomain (struct of_phandle_args *parent,struct of_phandle_args *new_subdomain); +extern struct generic_pm_domain *of_genpd_remove_last (struct device_node *np);int genpd_dev_pm_attach (struct device *dev);#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
@@ -237,6 +238,12 @@ static inline int genpd_dev_pm_attach(struct device *dev) {return -ENODEV ; } + +static inline +struct generic_pm_domain *of_genpd_remove_last (struct device_node *np) +{ +return ERR_PTR (-ENOTSUPP ); +}#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ #ifdef CONFIG_PM
Signature · 1 line
2.1.4
PATCH v2 10/10 PM / Domains: Add support for removing nested PM domains by provider
Quoted 11 lines · Jon Hunter
If a device supports PM domains that are subdomains of another PM domain, then the PM domains should be removed in reverse order to ensure that the subdomains are removed first. Furthermore, if there is more than one provider, then there needs to be a way to remove the domains in reverse order for a specific provider.
Add the function
of_genpd_remove_last()to remove the last PM domain added by a given PM domain provider and return thegeneric_pm_domainstructure for the PM domain that was removed.Signed-off-by Jon Hunter <[email protected]>
Kind regards
Uffe
Quoted 83 lines
--- drivers/base/power/domain.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 7 +++++++ 2 files changed, 42 insertions(+)drivers/base/power/domain.c +35
-0@@ -1745,6 +1745,41 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,EXPORT_SYMBOL_GPL (of_genpd_add_subdomain);/** +* of_genpd_remove_last - Remove the last PM domain registered for a provider +* @provider: Pointer to device structure associated with provider +* +* Find the last PM domain that was added by a particular provider and +* remove this PM domain from the list of PM domains. The provider is +* identified by the 'provider' device structure that is passed. The PM +* domain will only be removed, if the provider associated with domain +* has been removed. +* +* Returns a valid pointer to struct generic_pm_domain on success or +* ERR_PTR() on failure. +*/ +struct generic_pm_domain *of_genpd_remove_last (struct device_node *np) +{ +struct generic_pm_domain *gpd, *genpd =ERR_PTR (-ENOENT ); +int ret; + +if (IS_ERR_OR_NULL (np)) +return ERR_PTR (-EINVAL ); + +mutex_lock (&gpd_list_lock); +list_for_each_entry (gpd, &gpd_list, gpd_list_node) { +if (gpd->provider == &np->fwnode) { + ret =genpd_remove (gpd); + genpd = ret ?ERR_PTR (ret) : gpd; +break ; + } + } +mutex_unlock (&gpd_list_lock); + +return genpd; +} +EXPORT_SYMBOL_GPL (of_genpd_remove_last); + +/** * genpd_dev_pm_detach - Detach a device from its PM domain. * @dev: Device to detach. * @power_off: Currently not used include/linux/pm_domain.h +7
-1@@ -204,6 +204,7 @@ extern int of_genpd_add_device(struct of_phandle_args *args, struct device *dev);extern int of_genpd_add_subdomain (struct of_phandle_args *parent,struct of_phandle_args *new_subdomain); +extern struct generic_pm_domain *of_genpd_remove_last (struct device_node *np);int genpd_dev_pm_attach (struct device *dev);#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ @@ -237,6 +238,12 @@ static inline int genpd_dev_pm_attach(struct device *dev) {return -ENODEV ; } + +static inline +struct generic_pm_domain *of_genpd_remove_last (struct device_node *np) +{ +return ERR_PTR (-ENOTSUPP ); +}#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ #ifdef CONFIG_PM --2.1.4
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
v2 cover PM / Domains: Add support for removing PM domains
In reply to Jon HunterQuoted 33 lines · Jon Hunter
In order to safely remove PM domains there are a few changes that need to be made to ensure that no one is holding an external reference to a PM domain after it has been removed. One solution, implemented here, solves this by eliminating external references to PM domain.
Changes from V1:
- Added test when removing a PM domain to ensure the PM domain provider has been removed.
- Re-organised patches 8-10 so that patch #8 adds the code to verify if the provider is present, patch #9 adds basic support for removing PM domains and patch #10 adds support for removing PM domains by provider.Changes from initial RFC:
- Renamed functions made static per Ulf's feedback.
- Added patch to clean-up provider/xlate APIs per Ulf's feedback
- Re-worked and simplified the association between PM domains and PM domain providers. Dropped the 'provider_data' variable from thegeneric_pm_domainstructure in favour of using thefwnode_handle.
- Split patch for removing PM domains into multiple patches per Ulf's feedback.Jon Hunter (10):
PM / Domains: Add new helper functions for device-tree
ARM: EXYNOS: Remove calls toof_genpd_get_from_provider()
staging: board: Remove calls toof_genpd_get_from_provider()PM / Domains: Don't exposegeneric_pm_domainstructure to clients PM / Domains: Don't expose xlate and provider helper functions PM / Domains: Verify the PM domain is present when adding a provider PM / Domains: Prepare for adding support to remove PM domains PM / Domains: Store the provider in the PM domain structure PM / Domains: Add support for removing PM domains
PM / Domains: Add support for removing nested PM domains by provider
Quoted 9 lines
drivers/base/power/domain.c | 353 +++++++++++++++++++++++++++++++++++---- drivers/soc/samsung/pm_domains.c | 23 +-- drivers/staging/board/board.c | 9 +- include/linux/pm_domain.h | 74 ++++---- 4 files changed, 364 insertions(+), 95 deletions(-)--
2.1.4
Jon, thanks for being patient and keep working on this series! I have now completed the review and I am happy with this version.
Also, I remember Krzysztof requested an immutable branch for this series, I guess Rafael can arrange that if still needed!?
Kind regards
Uffe
v2 cover PM / Domains: Add support for removing PM domains
Quoted 44 lines · Ulf Hansson
Quoted 33 lines · Jon Hunter
In order to safely remove PM domains there are a few changes that need to be made to ensure that no one is holding an external reference to a PM domain after it has been removed. One solution, implemented here, solves this by eliminating external references to PM domain.
Changes from V1:
- Added test when removing a PM domain to ensure the PM domain provider has been removed.
- Re-organised patches 8-10 so that patch #8 adds the code to verify if the provider is present, patch #9 adds basic support for removing PM domains and patch #10 adds support for removing PM domains by provider.Changes from initial RFC:
- Renamed functions made static per Ulf's feedback.
- Added patch to clean-up provider/xlate APIs per Ulf's feedback
- Re-worked and simplified the association between PM domains and PM domain providers. Dropped the 'provider_data' variable from thegeneric_pm_domainstructure in favour of using thefwnode_handle.
- Split patch for removing PM domains into multiple patches per Ulf's feedback.Jon Hunter (10):
PM / Domains: Add new helper functions for device-tree
ARM: EXYNOS: Remove calls toof_genpd_get_from_provider()
staging: board: Remove calls toof_genpd_get_from_provider()PM / Domains: Don't exposegeneric_pm_domainstructure to clients PM / Domains: Don't expose xlate and provider helper functions PM / Domains: Verify the PM domain is present when adding a provider PM / Domains: Prepare for adding support to remove PM domains PM / Domains: Store the provider in the PM domain structure PM / Domains: Add support for removing PM domains
PM / Domains: Add support for removing nested PM domains by providerQuoted 9 lines
drivers/base/power/domain.c | 353 +++++++++++++++++++++++++++++++++++---- drivers/soc/samsung/pm_domains.c | 23 +-- drivers/staging/board/board.c | 9 +- include/linux/pm_domain.h | 74 ++++---- 4 files changed, 364 insertions(+), 95 deletions(-)--
2.1.4
Quoted 5 lines
Jon, thanks for being patient and keep working on this series! I have now completed the review and I am happy with this version.
Also, I remember Krzysztof requested an immutable branch for this series, I guess Rafael can arrange that if still needed!?
Yes, I can do that.
I think I'll get to these patches later today and if not, then tomorrow.
Thanks,
Rafael
v2 cover PM / Domains: Add support for removing PM domains
In reply to Jon HunterQuoted 21 lines · Jon Hunter
In order to safely remove PM domains there are a few changes that need to be made to ensure that no one is holding an external reference to a PM domain after it has been removed. One solution, implemented here, solves this by eliminating external references to PM domain.
Changes from V1:
- Added test when removing a PM domain to ensure the PM domain provider has been removed.
- Re-organised patches 8-10 so that patch #8 adds the code to verify if the provider is present, patch #9 adds basic support for removing PM domains and patch #10 adds support for removing PM domains by provider.Changes from initial RFC:
- Renamed functions made static per Ulf's feedback.
- Added patch to clean-up provider/xlate APIs per Ulf's feedback
- Re-worked and simplified the association between PM domains and PM domain providers. Dropped the 'provider_data' variable from thegeneric_pm_domainstructure in favour of using thefwnode_handle.
- Split patch for removing PM domains into multiple patches per Ulf's feedback.
Quoted 11 lines
Jon Hunter (10):
PM / Domains: Add new helper functions for device-tree
ARM: EXYNOS: Remove calls toof_genpd_get_from_provider()
staging: board: Remove calls toof_genpd_get_from_provider()PM / Domains: Don't exposegeneric_pm_domainstructure to clients PM / Domains: Don't expose xlate and provider helper functions PM / Domains: Verify the PM domain is present when adding a provider PM / Domains: Prepare for adding support to remove PM domains PM / Domains: Store the provider in the PM domain structure PM / Domains: Add support for removing PM domains
PM / Domains: Add support for removing nested PM domains by provider
All applied.
I'll expose a branch containing them after they've spent a couple of days in linux-next.
Thanks,
Rafael