On Wed, 24 Jun 2020 at 12:33, Daniel Baluta <daniel.baluta@xxxxxxxxxxx> wrote: > > From: Daniel Baluta <daniel.baluta@xxxxxxx> > > This patch introduces helpers support for multi PM domains. > > API consists of: > > 1) 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. > > 2) 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@xxxxxxx> > --- > 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