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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'pm-5.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management fixes from Rafael Wysocki:
"These fix a NULL pointer dereference in a devfreq driver and a runtime
PM framework issue that may cause a supplier device to be suspended
before its consumer.

Specifics:

- Fix NULL pointer dereference related to printing a diagnostic
message in the exynos-bus devfreq driver (Christian Marangi)

- Fix race condition in the runtime PM framework which in some cases
may cause a supplier device to be suspended when its consumer is
still active (Rafael Wysocki)"

* tag 'pm-5.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
PM / devfreq: exynos-bus: Fix NULL pointer dereference
PM: runtime: Fix supplier device management during consumer probe
PM: runtime: Redefine pm_runtime_release_supplier()

+27 -31
+12 -1
drivers/base/core.c
··· 486 486 /* Ensure that all references to the link object have been dropped. */ 487 487 device_link_synchronize_removal(); 488 488 489 - pm_runtime_release_supplier(link, true); 489 + pm_runtime_release_supplier(link); 490 + /* 491 + * If supplier_preactivated is set, the link has been dropped between 492 + * the pm_runtime_get_suppliers() and pm_runtime_put_suppliers() calls 493 + * in __driver_probe_device(). In that case, drop the supplier's 494 + * PM-runtime usage counter to remove the reference taken by 495 + * pm_runtime_get_suppliers(). 496 + */ 497 + if (link->supplier_preactivated) 498 + pm_runtime_put_noidle(link->supplier); 499 + 500 + pm_request_idle(link->supplier); 490 501 491 502 put_device(link->consumer); 492 503 put_device(link->supplier);
+10 -24
drivers/base/power/runtime.c
··· 308 308 /** 309 309 * pm_runtime_release_supplier - Drop references to device link's supplier. 310 310 * @link: Target device link. 311 - * @check_idle: Whether or not to check if the supplier device is idle. 312 311 * 313 - * Drop all runtime PM references associated with @link to its supplier device 314 - * and if @check_idle is set, check if that device is idle (and so it can be 315 - * suspended). 312 + * Drop all runtime PM references associated with @link to its supplier device. 316 313 */ 317 - void pm_runtime_release_supplier(struct device_link *link, bool check_idle) 314 + void pm_runtime_release_supplier(struct device_link *link) 318 315 { 319 316 struct device *supplier = link->supplier; 320 317 ··· 324 327 while (refcount_dec_not_one(&link->rpm_active) && 325 328 atomic_read(&supplier->power.usage_count) > 0) 326 329 pm_runtime_put_noidle(supplier); 327 - 328 - if (check_idle) 329 - pm_request_idle(supplier); 330 330 } 331 331 332 332 static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend) ··· 331 337 struct device_link *link; 332 338 333 339 list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, 334 - device_links_read_lock_held()) 335 - pm_runtime_release_supplier(link, try_to_suspend); 340 + device_links_read_lock_held()) { 341 + pm_runtime_release_supplier(link); 342 + if (try_to_suspend) 343 + pm_request_idle(link->supplier); 344 + } 336 345 } 337 346 338 347 static void rpm_put_suppliers(struct device *dev) ··· 1768 1771 if (link->flags & DL_FLAG_PM_RUNTIME) { 1769 1772 link->supplier_preactivated = true; 1770 1773 pm_runtime_get_sync(link->supplier); 1771 - refcount_inc(&link->rpm_active); 1772 1774 } 1773 1775 1774 1776 device_links_read_unlock(idx); ··· 1787 1791 list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, 1788 1792 device_links_read_lock_held()) 1789 1793 if (link->supplier_preactivated) { 1790 - bool put; 1791 - 1792 1794 link->supplier_preactivated = false; 1793 - 1794 - spin_lock_irq(&dev->power.lock); 1795 - 1796 - put = pm_runtime_status_suspended(dev) && 1797 - refcount_dec_not_one(&link->rpm_active); 1798 - 1799 - spin_unlock_irq(&dev->power.lock); 1800 - 1801 - if (put) 1802 - pm_runtime_put(link->supplier); 1795 + pm_runtime_put(link->supplier); 1803 1796 } 1804 1797 1805 1798 device_links_read_unlock(idx); ··· 1823 1838 return; 1824 1839 1825 1840 pm_runtime_drop_link_count(link->consumer); 1826 - pm_runtime_release_supplier(link, true); 1841 + pm_runtime_release_supplier(link); 1842 + pm_request_idle(link->supplier); 1827 1843 } 1828 1844 1829 1845 static bool pm_runtime_need_not_resume(struct device *dev)
+3 -3
drivers/devfreq/exynos-bus.c
··· 447 447 } 448 448 } 449 449 450 - max_state = bus->devfreq->profile->max_state; 451 - min_freq = (bus->devfreq->profile->freq_table[0] / 1000); 452 - max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000); 450 + max_state = bus->devfreq->max_state; 451 + min_freq = (bus->devfreq->freq_table[0] / 1000); 452 + max_freq = (bus->devfreq->freq_table[max_state - 1] / 1000); 453 453 pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n", 454 454 dev_name(dev), min_freq, max_freq); 455 455
+2 -3
include/linux/pm_runtime.h
··· 88 88 extern void pm_runtime_put_suppliers(struct device *dev); 89 89 extern void pm_runtime_new_link(struct device *dev); 90 90 extern void pm_runtime_drop_link(struct device_link *link); 91 - extern void pm_runtime_release_supplier(struct device_link *link, bool check_idle); 91 + extern void pm_runtime_release_supplier(struct device_link *link); 92 92 93 93 extern int devm_pm_runtime_enable(struct device *dev); 94 94 ··· 314 314 static inline void pm_runtime_put_suppliers(struct device *dev) {} 315 315 static inline void pm_runtime_new_link(struct device *dev) {} 316 316 static inline void pm_runtime_drop_link(struct device_link *link) {} 317 - static inline void pm_runtime_release_supplier(struct device_link *link, 318 - bool check_idle) {} 317 + static inline void pm_runtime_release_supplier(struct device_link *link) {} 319 318 320 319 #endif /* !CONFIG_PM */ 321 320