aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,