Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM / Domains: Introduce dev_pm_domain_start()

For a subsystem/driver that either doesn't support runtime PM or makes use
of pm_runtime_set_active() during ->probe(), may try to access its device
when probing, even if it may not be fully powered on from the PM domain's
point of view. This may be the case when the used PM domain is a genpd
provider, that implements genpd's ->start|stop() device callbacks.

There are cases where the subsystem/driver managed to avoid the above
problem, simply by calling pm_runtime_enable() and pm_runtime_get_sync()
during ->probe(). However, this approach comes with a drawback, especially
if the subsystem/driver implements a ->runtime_resume() callback.

More precisely, the subsystem/driver then needs to use a device flag, which
is checked in its ->runtime_resume() callback, as to avoid powering on its
resources the first time the callback is invoked. This is needed because
the subsystem/driver has already powered on the resources for the device,
during ->probe() and before it called pm_runtime_get_sync().

In a way to avoid this boilerplate code and the inefficient check for "if
(first_time_suspend)" in the ->runtime_resume() callback for these
subsystems/drivers, let's introduce and export a dev_pm_domain_start()
function, that may be called during ->probe() instead.

Moreover, let the dev_pm_domain_start() invoke an optional ->start()
callback, added to the struct dev_pm_domain, as to allow a PM domain
specific implementation.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Ulf Hansson and committed by
Rafael J. Wysocki
ca765a8c 31f4f5b4

+27
+20
drivers/base/power/common.c
··· 188 188 EXPORT_SYMBOL_GPL(dev_pm_domain_detach); 189 189 190 190 /** 191 + * dev_pm_domain_start - Start the device through its PM domain. 192 + * @dev: Device to start. 193 + * 194 + * This function should typically be called during probe by a subsystem/driver, 195 + * when it needs to start its device from the PM domain's perspective. Note 196 + * that, it's assumed that the PM domain is already powered on when this 197 + * function is called. 198 + * 199 + * Returns 0 on success and negative error values on failures. 200 + */ 201 + int dev_pm_domain_start(struct device *dev) 202 + { 203 + if (dev->pm_domain && dev->pm_domain->start) 204 + return dev->pm_domain->start(dev); 205 + 206 + return 0; 207 + } 208 + EXPORT_SYMBOL_GPL(dev_pm_domain_start); 209 + 210 + /** 191 211 * dev_pm_domain_set - Set PM domain of a device. 192 212 * @dev: Device whose PM domain is to be set. 193 213 * @pd: PM domain to be set, or NULL.
+2
include/linux/pm.h
··· 637 637 * struct dev_pm_domain - power management domain representation. 638 638 * 639 639 * @ops: Power management operations associated with this domain. 640 + * @start: Called when a user needs to start the device via the domain. 640 641 * @detach: Called when removing a device from the domain. 641 642 * @activate: Called before executing probe routines for bus types and drivers. 642 643 * @sync: Called after successful driver probe. ··· 649 648 */ 650 649 struct dev_pm_domain { 651 650 struct dev_pm_ops ops; 651 + int (*start)(struct device *dev); 652 652 void (*detach)(struct device *dev, bool power_off); 653 653 int (*activate)(struct device *dev); 654 654 void (*sync)(struct device *dev);
+5
include/linux/pm_domain.h
··· 366 366 struct device *dev_pm_domain_attach_by_name(struct device *dev, 367 367 const char *name); 368 368 void dev_pm_domain_detach(struct device *dev, bool power_off); 369 + int dev_pm_domain_start(struct device *dev); 369 370 void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); 370 371 #else 371 372 static inline int dev_pm_domain_attach(struct device *dev, bool power_on) ··· 384 383 return NULL; 385 384 } 386 385 static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} 386 + static inline int dev_pm_domain_start(struct device *dev) 387 + { 388 + return 0; 389 + } 387 390 static inline void dev_pm_domain_set(struct device *dev, 388 391 struct dev_pm_domain *pd) {} 389 392 #endif