summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-06-14 04:01:52 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-06-14 04:01:52 -0400
commit47e5abfb546a3ace23a77453dc2e9db92704c5ac (patch)
treef11b476c37b667f8783f5f597fe2cfe9f9aacf64 /drivers/base
parentd09fcecb0c797b884ce65daa37c121a2786bb17b (diff)
PM / core: Fix supplier device runtime PM usage counter imbalance
If a device link is added via device_link_add() by the driver of the link's consumer device, the supplier's runtime PM usage counter is going to be dropped by the pm_runtime_put_suppliers() call in driver_probe_device(). However, in that case it is not incremented unless the supplier driver is already present and the link is not stateless. That leads to a runtime PM usage counter imbalance for the supplier device in a few cases. To prevent that from happening, bump up the supplier runtime PM usage counter in device_link_add() for all links with the DL_FLAG_PM_RUNTIME flag set that are added at the consumer probe time. Use pm_runtime_get_noresume() for that as the callers of device_link_add() who want the supplier to be resumed by it are expected to pass DL_FLAG_RPM_ACTIVE in flags to it anyway, but additionally resume the supplier if the link is added during consumer driver probe to retain the existing behavior for the callers depending on it. Fixes: 21d5c57b3726 (PM / runtime: Use device links) Reported-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Cc: 4.10+ <stable@vger.kernel.org> # 4.10+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/core.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 36622b52e419..df3e1a44707a 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -236,6 +236,13 @@ struct device_link *device_link_add(struct device *consumer,
236 link->rpm_active = true; 236 link->rpm_active = true;
237 } 237 }
238 pm_runtime_new_link(consumer); 238 pm_runtime_new_link(consumer);
239 /*
240 * If the link is being added by the consumer driver at probe
241 * time, balance the decrementation of the supplier's runtime PM
242 * usage counter after consumer probe in driver_probe_device().
243 */
244 if (consumer->links.status == DL_DEV_PROBING)
245 pm_runtime_get_noresume(supplier);
239 } 246 }
240 get_device(supplier); 247 get_device(supplier);
241 link->supplier = supplier; 248 link->supplier = supplier;
@@ -255,12 +262,12 @@ struct device_link *device_link_add(struct device *consumer,
255 switch (consumer->links.status) { 262 switch (consumer->links.status) {
256 case DL_DEV_PROBING: 263 case DL_DEV_PROBING:
257 /* 264 /*
258 * Balance the decrementation of the supplier's 265 * Some callers expect the link creation during
259 * runtime PM usage counter after consumer probe 266 * consumer driver probe to resume the supplier
260 * in driver_probe_device(). 267 * even without DL_FLAG_RPM_ACTIVE.
261 */ 268 */
262 if (flags & DL_FLAG_PM_RUNTIME) 269 if (flags & DL_FLAG_PM_RUNTIME)
263 pm_runtime_get_sync(supplier); 270 pm_runtime_resume(supplier);
264 271
265 link->status = DL_STATE_CONSUMER_PROBE; 272 link->status = DL_STATE_CONSUMER_PROBE;
266 break; 273 break;