On Wed, 24 Jun 2020 at 12:33, Daniel Baluta daniel.baluta@oss.nxp.com wrote:
From: Daniel Baluta daniel.baluta@nxp.com
This patch introduces helpers support for multi PM domains.
API consists of:
- dev_multi_pm_attach - powers up all PM domains associated with a given
device. Because we can attach one PM domain per device, we create virtual devices (children of initial device) and associate PM domains one per virtual device.
- dev_multi_pm_detach - detaches all virtual devices from PM domains
attached with.
Nit pick: I suggest to rename the helpers into dev_pm_domain_attach|detach_multi(), to be more consistent with existing function names. It's a bit long I admit that, but I prefer the consistency.
Signed-off-by: Daniel Baluta daniel.baluta@nxp.com
drivers/base/power/common.c | 93 +++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 19 ++++++++ 2 files changed, 112 insertions(+)
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index bbddb267c2e6..b0a4d0109810 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -228,3 +228,96 @@ void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd) device_pm_check_callbacks(dev); } EXPORT_SYMBOL_GPL(dev_pm_domain_set);
+/**
- dev_multi_pm_attach - power up device associated power domains
- @dev: The device used to lookup the PM domains
- Parse device's OF node to find all PM domains specifiers. For each power
- domain found, create a virtual device and associate it with the
- current power domain.
- This function should typically be invoked by a driver during the
- probe phase, in the case its device requires power management through
- multiple PM domains.
- Returns a pointer to @dev_multi_pm_domain_data if successfully attached PM
- domains, NULL when the device doesn't need a PM domain or when single
- power-domains exists for it, else an ERR_PTR() in case of
- failures.
- */
+struct dev_multi_pm_domain_data *dev_multi_pm_attach(struct device *dev) +{
struct dev_multi_pm_domain_data *mpd, *retp;
int num_domains;
int i;
num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
"#power-domain-cells");
if (num_domains < 2)
return NULL;
dev_pm_domain_attach_* is typically wrapper functions, allowing different types of PM domains to be supported. For example, dev_pm_domain_attach() calls acpi_dev_pm_attach() and genpd_dev_pm_attach(). While dev_pm_domain_attach_by_id() only calls genpd_dev_pm_attach_by_id(), as there's no corresponding interface for the acpi PM domain.
The above said, I don't think another layer should be needed here, but there is something missing that makes this consistent with the behaviour of the above mentioned functions.
How about adding a genpd OF helper ("of_genpd_num_domains(struct device_node *)"), that deals with the above parsing and returns the number of domains for the device? In this way, if of_genpd_num_domains() returns an error code or zero, it's easier to continue to try with other PM domain providers (if/when that is supported).
mpd = devm_kzalloc(dev, sizeof(*mpd), GFP_KERNEL);
if (!mpd)
return ERR_PTR(-ENOMEM);
mpd->dev = dev;
mpd->num_domains = num_domains;
mpd->virt_devs = devm_kmalloc_array(dev, mpd->num_domains,
sizeof(*mpd->virt_devs),
GFP_KERNEL);
if (!mpd->virt_devs)
return ERR_PTR(-ENOMEM);
mpd->links = devm_kmalloc_array(dev, mpd->num_domains,
sizeof(*mpd->links), GFP_KERNEL);
if (!mpd->links)
return ERR_PTR(-ENOMEM);
for (i = 0; i < mpd->num_domains; i++) {
mpd->virt_devs[i] = dev_pm_domain_attach_by_id(dev, i);
if (IS_ERR(mpd->virt_devs[i])) {
retp = (struct dev_multi_pm_domain_data *)
mpd->virt_devs[i];
goto exit_unroll_pm;
}
mpd->links[i] = device_link_add(dev, mpd->virt_devs[i],
DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
As a suggestion to be a little bit more flexible, perhaps these bits should be given as an in-parameter instead. Potentially we could then also treat the in-parameter being zero, as that no device link should be added.
Although, it's kind of hard to know as the users of this interface aren't really widely known yet.
if (!mpd->links[i]) {
retp = ERR_PTR(-ENOMEM);
dev_pm_domain_detach(mpd->virt_devs[i], false);
goto exit_unroll_pm;
}
}
return mpd;
+exit_unroll_pm:
while (--i >= 0) {
device_link_del(mpd->links[i]);
dev_pm_domain_detach(mpd->virt_devs[i], false);
}
return retp;
+} +EXPORT_SYMBOL(dev_multi_pm_attach);
[...]
Kind regards Uffe