aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-09-27 15:54:52 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-09-27 15:54:52 -0400
commitad3c36a534bc7b945d7bffdda1c62e13bf93489a (patch)
tree5f7520f575891716577de33176713b8cb13a22d5 /drivers/base
parent30b1a7a32ca48fd8758f8ca44d60deebc0aa3d72 (diff)
PM / Runtime: Don't run callbacks under lock for power.irq_safe set
The rpm_suspend() and rpm_resume() routines execute subsystem or PM domain callbacks under power.lock if power.irq_safe is set for the given device. This is inconsistent with that rpm_idle() does after commit 02b2677 (PM / Runtime: Allow _put_sync() from interrupts-disabled context) and is problematic for subsystems and PM domains wanting to use power.lock for synchronization in their runtime PM callbacks. This change requires the code checking if the device's runtime PM status is RPM_SUSPENDING or RPM_RESUMING to be modified too, to take the power.irq_safe set case into account (that code wasn't reachable before with power.irq_safe set, because it's executed with the device's power.lock held). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reviewed-by: Ming Lei <tom.leiming@gmail.com> Reviewed-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/runtime.c68
1 files changed, 46 insertions, 22 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 04e18abb50bb..aecb2a887ed7 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -155,6 +155,31 @@ static int rpm_check_suspend_allowed(struct device *dev)
155} 155}
156 156
157/** 157/**
158 * __rpm_callback - Run a given runtime PM callback for a given device.
159 * @cb: Runtime PM callback to run.
160 * @dev: Device to run the callback for.
161 */
162static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
163 __releases(&dev->power.lock) __acquires(&dev->power.lock)
164{
165 int retval;
166
167 if (dev->power.irq_safe)
168 spin_unlock(&dev->power.lock);
169 else
170 spin_unlock_irq(&dev->power.lock);
171
172 retval = cb(dev);
173
174 if (dev->power.irq_safe)
175 spin_lock(&dev->power.lock);
176 else
177 spin_lock_irq(&dev->power.lock);
178
179 return retval;
180}
181
182/**
158 * rpm_idle - Notify device bus type if the device can be suspended. 183 * rpm_idle - Notify device bus type if the device can be suspended.
159 * @dev: Device to notify the bus type about. 184 * @dev: Device to notify the bus type about.
160 * @rpmflags: Flag bits. 185 * @rpmflags: Flag bits.
@@ -225,19 +250,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
225 else 250 else
226 callback = NULL; 251 callback = NULL;
227 252
228 if (callback) { 253 if (callback)
229 if (dev->power.irq_safe) 254 __rpm_callback(callback, dev);
230 spin_unlock(&dev->power.lock);
231 else
232 spin_unlock_irq(&dev->power.lock);
233
234 callback(dev);
235
236 if (dev->power.irq_safe)
237 spin_lock(&dev->power.lock);
238 else
239 spin_lock_irq(&dev->power.lock);
240 }
241 255
242 dev->power.idle_notification = false; 256 dev->power.idle_notification = false;
243 wake_up_all(&dev->power.wait_queue); 257 wake_up_all(&dev->power.wait_queue);
@@ -252,22 +266,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
252 * @dev: Device to run the callback for. 266 * @dev: Device to run the callback for.
253 */ 267 */
254static int rpm_callback(int (*cb)(struct device *), struct device *dev) 268static int rpm_callback(int (*cb)(struct device *), struct device *dev)
255 __releases(&dev->power.lock) __acquires(&dev->power.lock)
256{ 269{
257 int retval; 270 int retval;
258 271
259 if (!cb) 272 if (!cb)
260 return -ENOSYS; 273 return -ENOSYS;
261 274
262 if (dev->power.irq_safe) { 275 retval = __rpm_callback(cb, dev);
263 retval = cb(dev);
264 } else {
265 spin_unlock_irq(&dev->power.lock);
266
267 retval = cb(dev);
268 276
269 spin_lock_irq(&dev->power.lock);
270 }
271 dev->power.runtime_error = retval; 277 dev->power.runtime_error = retval;
272 return retval != -EACCES ? retval : -EIO; 278 return retval != -EACCES ? retval : -EIO;
273} 279}
@@ -347,6 +353,15 @@ static int rpm_suspend(struct device *dev, int rpmflags)
347 goto out; 353 goto out;
348 } 354 }
349 355
356 if (dev->power.irq_safe) {
357 spin_unlock(&dev->power.lock);
358
359 cpu_relax();
360
361 spin_lock(&dev->power.lock);
362 goto repeat;
363 }
364
350 /* Wait for the other suspend running in parallel with us. */ 365 /* Wait for the other suspend running in parallel with us. */
351 for (;;) { 366 for (;;) {
352 prepare_to_wait(&dev->power.wait_queue, &wait, 367 prepare_to_wait(&dev->power.wait_queue, &wait,
@@ -496,6 +511,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
496 goto out; 511 goto out;
497 } 512 }
498 513
514 if (dev->power.irq_safe) {
515 spin_unlock(&dev->power.lock);
516
517 cpu_relax();
518
519 spin_lock(&dev->power.lock);
520 goto repeat;
521 }
522
499 /* Wait for the operation carried out in parallel with us. */ 523 /* Wait for the operation carried out in parallel with us. */
500 for (;;) { 524 for (;;) {
501 prepare_to_wait(&dev->power.wait_queue, &wait, 525 prepare_to_wait(&dev->power.wait_queue, &wait,