Skip to content

Commit 1e83786

Browse files
storulfrafaeljw
authored andcommitted
PM / runtime: Fixup reference counting of device link suppliers at probe
In the driver core, before it invokes really_probe() it runtime resumes the suppliers for the device via calling pm_runtime_get_suppliers(), which also increases the runtime PM usage count for each of the available supplier. This makes sense, as to be able to allow the consumer device to be probed by its driver. However, if the driver decides to add a new supplier link during ->probe(), hence updating the list of suppliers, the following call to pm_runtime_put_suppliers(), invoked after really_probe() in the driver core, we get into trouble. More precisely, pm_runtime_put() gets called also for the new supplier(s), which is wrong as the driver core, didn't trigger pm_runtime_get_sync() to be called for it in the first place. In other words, the new supplier may be runtime suspended even in cases when it shouldn't. Fix this behaviour, by runtime resume suppliers according to the same conditions as managed by the runtime PM core, when runtime resume callbacks are being invoked. Additionally, don't try to runtime suspend any of the suppliers after really_probe(), but instead rely on that to happen via the consumer device, when it becomes runtime suspended. Fixes: 21d5c57 (PM / runtime: Use device links) Signed-off-by: Ulf Hansson <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 21c7336 commit 1e83786

File tree

3 files changed

+6
-30
lines changed

3 files changed

+6
-30
lines changed

drivers/base/dd.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
580580
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
581581
drv->bus->name, __func__, dev_name(dev), drv->name);
582582

583-
pm_runtime_get_suppliers(dev);
583+
pm_runtime_resume_suppliers(dev);
584584
if (dev->parent)
585585
pm_runtime_get_sync(dev->parent);
586586

@@ -591,7 +591,6 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
591591
if (dev->parent)
592592
pm_runtime_put(dev->parent);
593593

594-
pm_runtime_put_suppliers(dev);
595594
return ret;
596595
}
597596

drivers/base/power/runtime.c

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,37 +1563,16 @@ void pm_runtime_clean_up_links(struct device *dev)
15631563
}
15641564

15651565
/**
1566-
* pm_runtime_get_suppliers - Resume and reference-count supplier devices.
1566+
* pm_runtime_resume_suppliers - Resume supplier devices.
15671567
* @dev: Consumer device.
15681568
*/
1569-
void pm_runtime_get_suppliers(struct device *dev)
1569+
void pm_runtime_resume_suppliers(struct device *dev)
15701570
{
1571-
struct device_link *link;
15721571
int idx;
15731572

15741573
idx = device_links_read_lock();
15751574

1576-
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
1577-
if (link->flags & DL_FLAG_PM_RUNTIME)
1578-
pm_runtime_get_sync(link->supplier);
1579-
1580-
device_links_read_unlock(idx);
1581-
}
1582-
1583-
/**
1584-
* pm_runtime_put_suppliers - Drop references to supplier devices.
1585-
* @dev: Consumer device.
1586-
*/
1587-
void pm_runtime_put_suppliers(struct device *dev)
1588-
{
1589-
struct device_link *link;
1590-
int idx;
1591-
1592-
idx = device_links_read_lock();
1593-
1594-
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
1595-
if (link->flags & DL_FLAG_PM_RUNTIME)
1596-
pm_runtime_put(link->supplier);
1575+
rpm_get_suppliers(dev);
15971576

15981577
device_links_read_unlock(idx);
15991578
}

include/linux/pm_runtime.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ extern void pm_runtime_update_max_time_suspended(struct device *dev,
5656
s64 delta_ns);
5757
extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable);
5858
extern void pm_runtime_clean_up_links(struct device *dev);
59-
extern void pm_runtime_get_suppliers(struct device *dev);
60-
extern void pm_runtime_put_suppliers(struct device *dev);
59+
extern void pm_runtime_resume_suppliers(struct device *dev);
6160
extern void pm_runtime_new_link(struct device *dev);
6261
extern void pm_runtime_drop_link(struct device *dev);
6362

@@ -173,8 +172,7 @@ static inline unsigned long pm_runtime_autosuspend_expiration(
173172
static inline void pm_runtime_set_memalloc_noio(struct device *dev,
174173
bool enable){}
175174
static inline void pm_runtime_clean_up_links(struct device *dev) {}
176-
static inline void pm_runtime_get_suppliers(struct device *dev) {}
177-
static inline void pm_runtime_put_suppliers(struct device *dev) {}
175+
static inline void pm_runtime_resume_suppliers(struct device *dev) {}
178176
static inline void pm_runtime_new_link(struct device *dev) {}
179177
static inline void pm_runtime_drop_link(struct device *dev) {}
180178

0 commit comments

Comments
 (0)