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

PM: domains: Add flags to specify power on attach/detach

Calling dev_pm_domain_attach()/dev_pm_domain_detach() in bus driver
probe/remove functions can affect system behavior when the drivers
attached to the bus use devres-managed resources. Since devres actions
may need to access device registers, calling dev_pm_domain_detach() too
early, i.e., before these actions complete, can cause failures on some
systems. One such example is Renesas RZ/G3S SoC-based platforms.

If the device clocks are managed via PM domains, invoking
dev_pm_domain_detach() in the bus driver's remove function removes the
device's clocks from the PM domain, preventing any subsequent
pm_runtime_resume*() calls from enabling those clocks.

The second argument of dev_pm_domain_attach() specifies whether the PM
domain should be powered on during attachment. Likewise, the second
argument of dev_pm_domain_detach() indicates whether the domain should be
powered off during detachment.

Upcoming changes address the issue described above (initially for the
platform bus only) by deferring the call to dev_pm_domain_detach() until
after devres_release_all() in device_unbind_cleanup(). The detach_power_off
field in struct dev_pm_info stores the detach power off info from the
second argument of dev_pm_domain_attach().

Because there are cases where the device's PM domain power-on/off behavior
must be conditional (e.g., in i2c_device_probe()), the patch introduces
PD_FLAG_ATTACH_POWER_ON and PD_FLAG_DETACH_POWER_OFF flags to be passed
to dev_pm_domain_attach().

Finally, dev_pm_domain_attach() and its users are updated to use the newly
introduced PD_FLAG_ATTACH_POWER_ON and PD_FLAG_DETACH_POWER_OFF macros.

This change is preparatory.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com> # I2C
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/20250703112708.1621607-2-claudiu.beznea.uj@bp.renesas.com
[ rjw: Changelog adjustments ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Claudiu Beznea and committed by
Rafael J. Wysocki
d42c7c6f 9047685c

+23 -17
+2 -2
drivers/amba/bus.c
··· 138 138 void __iomem *tmp; 139 139 int i, ret; 140 140 141 - ret = dev_pm_domain_attach(&dev->dev, true); 141 + ret = dev_pm_domain_attach(&dev->dev, PD_FLAG_ATTACH_POWER_ON); 142 142 if (ret) { 143 143 dev_dbg(&dev->dev, "can't get PM domain: %d\n", ret); 144 144 goto err_out; ··· 291 291 if (ret < 0) 292 292 break; 293 293 294 - ret = dev_pm_domain_attach(dev, true); 294 + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 295 295 if (ret) 296 296 break; 297 297
+1 -1
drivers/base/auxiliary.c
··· 217 217 struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 218 218 int ret; 219 219 220 - ret = dev_pm_domain_attach(dev, true); 220 + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 221 221 if (ret) { 222 222 dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret); 223 223 return ret;
+1 -1
drivers/base/platform.c
··· 1396 1396 if (ret < 0) 1397 1397 return ret; 1398 1398 1399 - ret = dev_pm_domain_attach(_dev, true); 1399 + ret = dev_pm_domain_attach(_dev, PD_FLAG_ATTACH_POWER_ON); 1400 1400 if (ret) 1401 1401 goto out; 1402 1402
+3 -3
drivers/base/power/common.c
··· 83 83 /** 84 84 * dev_pm_domain_attach - Attach a device to its PM domain. 85 85 * @dev: Device to attach. 86 - * @power_on: Used to indicate whether we should power on the device. 86 + * @flags: indicate whether we should power on/off the device on attach/detach 87 87 * 88 88 * The @dev may only be attached to a single PM domain. By iterating through 89 89 * the available alternatives we try to find a valid PM domain for the device. ··· 100 100 * Returns 0 on successfully attached PM domain, or when it is found that the 101 101 * device doesn't need a PM domain, else a negative error code. 102 102 */ 103 - int dev_pm_domain_attach(struct device *dev, bool power_on) 103 + int dev_pm_domain_attach(struct device *dev, u32 flags) 104 104 { 105 105 int ret; 106 106 107 107 if (dev->pm_domain) 108 108 return 0; 109 109 110 - ret = acpi_dev_pm_attach(dev, power_on); 110 + ret = acpi_dev_pm_attach(dev, !!(flags & PD_FLAG_ATTACH_POWER_ON)); 111 111 if (!ret) 112 112 ret = genpd_dev_pm_attach(dev); 113 113
+1 -1
drivers/clk/qcom/apcs-sdx55.c
··· 111 111 * driver, there seems to be no better place to do this. So do it here! 112 112 */ 113 113 cpu_dev = get_cpu_device(0); 114 - ret = dev_pm_domain_attach(cpu_dev, true); 114 + ret = dev_pm_domain_attach(cpu_dev, PD_FLAG_ATTACH_POWER_ON); 115 115 if (ret) { 116 116 dev_err_probe(dev, ret, "can't get PM domain: %d\n", ret); 117 117 goto err;
+1 -1
drivers/gpu/drm/display/drm_dp_aux_bus.c
··· 57 57 container_of(aux_ep, struct dp_aux_ep_device_with_data, aux_ep); 58 58 int ret; 59 59 60 - ret = dev_pm_domain_attach(dev, true); 60 + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 61 61 if (ret) 62 62 return dev_err_probe(dev, ret, "Failed to attach to PM Domain\n"); 63 63
+1 -1
drivers/i2c/i2c-core-base.c
··· 573 573 goto err_clear_wakeup_irq; 574 574 575 575 do_power_on = !i2c_acpi_waive_d0_probe(dev); 576 - status = dev_pm_domain_attach(&client->dev, do_power_on); 576 + status = dev_pm_domain_attach(&client->dev, do_power_on ? PD_FLAG_ATTACH_POWER_ON : 0); 577 577 if (status) 578 578 goto err_clear_wakeup_irq; 579 579
+1 -1
drivers/mmc/core/sdio_bus.c
··· 161 161 if (!id) 162 162 return -ENODEV; 163 163 164 - ret = dev_pm_domain_attach(dev, false); 164 + ret = dev_pm_domain_attach(dev, 0); 165 165 if (ret) 166 166 return ret; 167 167
+1 -1
drivers/rpmsg/rpmsg_core.c
··· 479 479 struct rpmsg_endpoint *ept = NULL; 480 480 int err; 481 481 482 - err = dev_pm_domain_attach(dev, true); 482 + err = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 483 483 if (err) 484 484 goto out; 485 485
+1 -1
drivers/soundwire/bus_type.c
··· 101 101 /* 102 102 * attach to power domain but don't turn on (last arg) 103 103 */ 104 - ret = dev_pm_domain_attach(dev, false); 104 + ret = dev_pm_domain_attach(dev, 0); 105 105 if (ret) 106 106 return ret; 107 107
+1 -1
drivers/spi/spi.c
··· 427 427 if (spi->irq < 0) 428 428 spi->irq = 0; 429 429 430 - ret = dev_pm_domain_attach(dev, true); 430 + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 431 431 if (ret) 432 432 return ret; 433 433
+1 -1
drivers/tty/serdev/core.c
··· 399 399 const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver); 400 400 int ret; 401 401 402 - ret = dev_pm_domain_attach(dev, true); 402 + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 403 403 if (ret) 404 404 return ret; 405 405
+8 -2
include/linux/pm_domain.h
··· 36 36 * isn't specified, the index just follows the 37 37 * index for the attached PM domain. 38 38 * 39 + * PD_FLAG_ATTACH_POWER_ON: Power on the domain during attach. 40 + * 41 + * PD_FLAG_DETACH_POWER_OFF: Power off the domain during detach. 42 + * 39 43 */ 40 44 #define PD_FLAG_NO_DEV_LINK BIT(0) 41 45 #define PD_FLAG_DEV_LINK_ON BIT(1) 42 46 #define PD_FLAG_REQUIRED_OPP BIT(2) 47 + #define PD_FLAG_ATTACH_POWER_ON BIT(3) 48 + #define PD_FLAG_DETACH_POWER_OFF BIT(4) 43 49 44 50 struct dev_pm_domain_attach_data { 45 51 const char * const *pd_names; ··· 507 501 #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ 508 502 509 503 #ifdef CONFIG_PM 510 - int dev_pm_domain_attach(struct device *dev, bool power_on); 504 + int dev_pm_domain_attach(struct device *dev, u32 flags); 511 505 struct device *dev_pm_domain_attach_by_id(struct device *dev, 512 506 unsigned int index); 513 507 struct device *dev_pm_domain_attach_by_name(struct device *dev, ··· 524 518 void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); 525 519 int dev_pm_domain_set_performance_state(struct device *dev, unsigned int state); 526 520 #else 527 - static inline int dev_pm_domain_attach(struct device *dev, bool power_on) 521 + static inline int dev_pm_domain_attach(struct device *dev, u32 flags) 528 522 { 529 523 return 0; 530 524 }