Skip to content

Commit 3784fad

Browse files
committed
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()
2 parents 483e4a1 + fe7c758 commit 3784fad

File tree

4 files changed

+27
-31
lines changed

4 files changed

+27
-31
lines changed

drivers/base/core.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,18 @@ static void device_link_release_fn(struct work_struct *work)
486486
/* Ensure that all references to the link object have been dropped. */
487487
device_link_synchronize_removal();
488488

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);
490501

491502
put_device(link->consumer);
492503
put_device(link->supplier);

drivers/base/power/runtime.c

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -308,13 +308,10 @@ static int rpm_get_suppliers(struct device *dev)
308308
/**
309309
* pm_runtime_release_supplier - Drop references to device link's supplier.
310310
* @link: Target device link.
311-
* @check_idle: Whether or not to check if the supplier device is idle.
312311
*
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.
316313
*/
317-
void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
314+
void pm_runtime_release_supplier(struct device_link *link)
318315
{
319316
struct device *supplier = link->supplier;
320317

@@ -327,18 +324,18 @@ void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
327324
while (refcount_dec_not_one(&link->rpm_active) &&
328325
atomic_read(&supplier->power.usage_count) > 0)
329326
pm_runtime_put_noidle(supplier);
330-
331-
if (check_idle)
332-
pm_request_idle(supplier);
333327
}
334328

335329
static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
336330
{
337331
struct device_link *link;
338332

339333
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
340-
device_links_read_lock_held())
341-
pm_runtime_release_supplier(link, try_to_suspend);
334+
device_links_read_lock_held()) {
335+
pm_runtime_release_supplier(link);
336+
if (try_to_suspend)
337+
pm_request_idle(link->supplier);
338+
}
342339
}
343340

344341
static void rpm_put_suppliers(struct device *dev)
@@ -1771,7 +1768,6 @@ void pm_runtime_get_suppliers(struct device *dev)
17711768
if (link->flags & DL_FLAG_PM_RUNTIME) {
17721769
link->supplier_preactivated = true;
17731770
pm_runtime_get_sync(link->supplier);
1774-
refcount_inc(&link->rpm_active);
17751771
}
17761772

17771773
device_links_read_unlock(idx);
@@ -1791,19 +1787,8 @@ void pm_runtime_put_suppliers(struct device *dev)
17911787
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
17921788
device_links_read_lock_held())
17931789
if (link->supplier_preactivated) {
1794-
bool put;
1795-
17961790
link->supplier_preactivated = false;
1797-
1798-
spin_lock_irq(&dev->power.lock);
1799-
1800-
put = pm_runtime_status_suspended(dev) &&
1801-
refcount_dec_not_one(&link->rpm_active);
1802-
1803-
spin_unlock_irq(&dev->power.lock);
1804-
1805-
if (put)
1806-
pm_runtime_put(link->supplier);
1791+
pm_runtime_put(link->supplier);
18071792
}
18081793

18091794
device_links_read_unlock(idx);
@@ -1838,7 +1823,8 @@ void pm_runtime_drop_link(struct device_link *link)
18381823
return;
18391824

18401825
pm_runtime_drop_link_count(link->consumer);
1841-
pm_runtime_release_supplier(link, true);
1826+
pm_runtime_release_supplier(link);
1827+
pm_request_idle(link->supplier);
18421828
}
18431829

18441830
static bool pm_runtime_need_not_resume(struct device *dev)

drivers/devfreq/exynos-bus.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,9 @@ static int exynos_bus_probe(struct platform_device *pdev)
447447
}
448448
}
449449

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);
453453
pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
454454
dev_name(dev), min_freq, max_freq);
455455

include/linux/pm_runtime.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
8888
extern void pm_runtime_put_suppliers(struct device *dev);
8989
extern void pm_runtime_new_link(struct device *dev);
9090
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);
9292

9393
extern int devm_pm_runtime_enable(struct device *dev);
9494

@@ -314,8 +314,7 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
314314
static inline void pm_runtime_put_suppliers(struct device *dev) {}
315315
static inline void pm_runtime_new_link(struct device *dev) {}
316316
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) {}
319318

320319
#endif /* !CONFIG_PM */
321320

0 commit comments

Comments
 (0)