History

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.

Ulf Hansson committed 7 years ago

Commit ca765a81 parent 31f4f5b3 files · +27 −0Browse files

Unified · Split

3 files
  1. drivers/base/power/common.c +20 −0
  2. include/linux/pm.h +2 −0
  3. include/linux/pm_domain.h +5 −0
drivers/base/power/common.c+20−0
@@ -187,6 +187,26 @@ void dev_pm_domain_detach(struct device *dev, bool power_off) · 186 unmodified lines
187}187}
188EXPORT_SYMBOL_GPL(dev_pm_domain_detach);188EXPORT_SYMBOL_GPL(dev_pm_domain_detach);
189 189
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 */
201int 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}
208EXPORT_SYMBOL_GPL(dev_pm_domain_start);
209
190/**210/**
191 * dev_pm_domain_set - Set PM domain of a device.211 * dev_pm_domain_set - Set PM domain of a device.
192 * @dev: Device whose PM domain is to be set.212 * @dev: Device whose PM domain is to be set.
include/linux/pm.h+2−0
@@ -637,6 +637,7 @@ extern void dev_pm_put_subsys_data(struct device *dev); · 636 unmodified lines
637 * struct dev_pm_domain - power management domain representation.637 * struct dev_pm_domain - power management domain representation.
638 *638 *
639 * @ops: Power management operations associated with this domain.639 * @ops: Power management operations associated with this domain.
640 * @start: Called when a user needs to start the device via the domain.
640 * @detach: Called when removing a device from the domain.641 * @detach: Called when removing a device from the domain.
641 * @activate: Called before executing probe routines for bus types and drivers.642 * @activate: Called before executing probe routines for bus types and drivers.
642 * @sync: Called after successful driver probe.643 * @sync: Called after successful driver probe.
@@ -648,6 +649,7 @@ extern void dev_pm_put_subsys_data(struct device *dev); · 5 unmodified lines
648 */649 */
649struct dev_pm_domain {650struct dev_pm_domain {
650 struct dev_pm_ops ops;651 struct dev_pm_ops ops;
652 int (*start)(struct device *dev);
651 void (*detach)(struct device *dev, bool power_off);653 void (*detach)(struct device *dev, bool power_off);
652 int (*activate)(struct device *dev);654 int (*activate)(struct device *dev);
653 void (*sync)(struct device *dev);655 void (*sync)(struct device *dev);
include/linux/pm_domain.h+5−0
@@ -366,6 +366,7 @@ struct device *dev_pm_domain_attach_by_id(struct device *dev, · 365 unmodified lines
366struct device *dev_pm_domain_attach_by_name(struct device *dev,366struct device *dev_pm_domain_attach_by_name(struct device *dev,
367 const char *name);367 const char *name);
368void dev_pm_domain_detach(struct device *dev, bool power_off);368void dev_pm_domain_detach(struct device *dev, bool power_off);
369int dev_pm_domain_start(struct device *dev);
369void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);370void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);
370#else371#else
371static inline int dev_pm_domain_attach(struct device *dev, bool power_on)372static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
@@ -383,6 +384,10 @@ static inline struct device *dev_pm_domain_attach_by_name(struct device *dev, · 11 unmodified lines
383 return NULL;384 return NULL;
384}385}
385static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}386static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
387static inline int dev_pm_domain_start(struct device *dev)
388{
389 return 0;
390}
386static inline void dev_pm_domain_set(struct device *dev,391static inline void dev_pm_domain_set(struct device *dev,
387 struct dev_pm_domain *pd) {}392 struct dev_pm_domain *pd) {}
388#endif393#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t