Skip to content

Commit

Permalink
Merge branch 'pm-runtime' into pm-for-linus
Browse files Browse the repository at this point in the history
* pm-runtime:
  PM / Tracing: build rpm-traces.c only if CONFIG_PM_RUNTIME is set
  PM / Runtime: Replace dev_dbg() with trace_rpm_*()
  PM / Runtime: Introduce trace points for tracing rpm_* functions
  PM / Runtime: Don't run callbacks under lock for power.irq_safe set
  USB: Add wakeup info to debugging messages
  PM / Runtime: pm_runtime_idle() can be called in atomic context
  PM / Runtime: Add macro to test for runtime PM events
  PM / Runtime: Add might_sleep() to runtime PM functions
  • Loading branch information
Rafael J. Wysocki committed Oct 7, 2011
2 parents 3ee72ca + 2a5306c commit d727b60
Show file tree
Hide file tree
Showing 20 changed files with 226 additions and 66 deletions.
2 changes: 2 additions & 0 deletions Documentation/power/runtime_pm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,14 @@ pm_runtime_autosuspend_expiration()
If pm_runtime_irq_safe() has been called for a device then the following helper
functions may also be used in interrupt context:

pm_runtime_idle()
pm_runtime_suspend()
pm_runtime_autosuspend()
pm_runtime_resume()
pm_runtime_get_sync()
pm_runtime_put_sync()
pm_runtime_put_sync_suspend()
pm_runtime_put_sync_autosuspend()

5. Runtime PM Initialization, Device Probing and Removal

Expand Down
8 changes: 4 additions & 4 deletions Documentation/usb/power-management.txt
Original file line number Diff line number Diff line change
Expand Up @@ -439,10 +439,10 @@ cause autosuspends to fail with -EBUSY if the driver needs to use the
device.

External suspend calls should never be allowed to fail in this way,
only autosuspend calls. The driver can tell them apart by checking
the PM_EVENT_AUTO bit in the message.event argument to the suspend
method; this bit will be set for internal PM events (autosuspend) and
clear for external PM events.
only autosuspend calls. The driver can tell them apart by applying
the PMSG_IS_AUTO() macro to the message argument to the suspend
method; it will return True for internal PM events (autosuspend) and
False for external PM events.


Mutual exclusion
Expand Down
94 changes: 65 additions & 29 deletions drivers/base/power/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <linux/sched.h>
#include <linux/pm_runtime.h>
#include <trace/events/rpm.h>
#include "power.h"

static int rpm_resume(struct device *dev, int rpmflags);
Expand Down Expand Up @@ -154,6 +155,31 @@ static int rpm_check_suspend_allowed(struct device *dev)
return retval;
}

/**
* __rpm_callback - Run a given runtime PM callback for a given device.
* @cb: Runtime PM callback to run.
* @dev: Device to run the callback for.
*/
static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
int retval;

if (dev->power.irq_safe)
spin_unlock(&dev->power.lock);
else
spin_unlock_irq(&dev->power.lock);

retval = cb(dev);

if (dev->power.irq_safe)
spin_lock(&dev->power.lock);
else
spin_lock_irq(&dev->power.lock);

return retval;
}

/**
* rpm_idle - Notify device bus type if the device can be suspended.
* @dev: Device to notify the bus type about.
Expand All @@ -171,6 +197,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
int (*callback)(struct device *);
int retval;

trace_rpm_idle(dev, rpmflags);
retval = rpm_check_suspend_allowed(dev);
if (retval < 0)
; /* Conditions are wrong. */
Expand Down Expand Up @@ -225,24 +252,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
else
callback = NULL;

if (callback) {
if (dev->power.irq_safe)
spin_unlock(&dev->power.lock);
else
spin_unlock_irq(&dev->power.lock);

callback(dev);

if (dev->power.irq_safe)
spin_lock(&dev->power.lock);
else
spin_lock_irq(&dev->power.lock);
}
if (callback)
__rpm_callback(callback, dev);

dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);

out:
trace_rpm_return_int(dev, _THIS_IP_, retval);
return retval;
}

Expand All @@ -252,22 +269,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
* @dev: Device to run the callback for.
*/
static int rpm_callback(int (*cb)(struct device *), struct device *dev)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
int retval;

if (!cb)
return -ENOSYS;

if (dev->power.irq_safe) {
retval = cb(dev);
} else {
spin_unlock_irq(&dev->power.lock);

retval = cb(dev);
retval = __rpm_callback(cb, dev);

spin_lock_irq(&dev->power.lock);
}
dev->power.runtime_error = retval;
return retval != -EACCES ? retval : -EIO;
}
Expand Down Expand Up @@ -295,7 +304,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
struct device *parent = NULL;
int retval;

dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
trace_rpm_suspend(dev, rpmflags);

repeat:
retval = rpm_check_suspend_allowed(dev);
Expand Down Expand Up @@ -347,6 +356,15 @@ static int rpm_suspend(struct device *dev, int rpmflags)
goto out;
}

if (dev->power.irq_safe) {
spin_unlock(&dev->power.lock);

cpu_relax();

spin_lock(&dev->power.lock);
goto repeat;
}

/* Wait for the other suspend running in parallel with us. */
for (;;) {
prepare_to_wait(&dev->power.wait_queue, &wait,
Expand Down Expand Up @@ -430,7 +448,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
}

out:
dev_dbg(dev, "%s returns %d\n", __func__, retval);
trace_rpm_return_int(dev, _THIS_IP_, retval);

return retval;
}
Expand Down Expand Up @@ -459,7 +477,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
struct device *parent = NULL;
int retval = 0;

dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
trace_rpm_resume(dev, rpmflags);

repeat:
if (dev->power.runtime_error)
Expand Down Expand Up @@ -496,6 +514,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
goto out;
}

if (dev->power.irq_safe) {
spin_unlock(&dev->power.lock);

cpu_relax();

spin_lock(&dev->power.lock);
goto repeat;
}

/* Wait for the operation carried out in parallel with us. */
for (;;) {
prepare_to_wait(&dev->power.wait_queue, &wait,
Expand Down Expand Up @@ -615,7 +642,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
spin_lock_irq(&dev->power.lock);
}

dev_dbg(dev, "%s returns %d\n", __func__, retval);
trace_rpm_return_int(dev, _THIS_IP_, retval);

return retval;
}
Expand Down Expand Up @@ -732,13 +759,16 @@ EXPORT_SYMBOL_GPL(pm_schedule_suspend);
* return immediately if it is larger than zero. Then carry out an idle
* notification, either synchronous or asynchronous.
*
* This routine may be called in atomic context if the RPM_ASYNC flag is set.
* This routine may be called in atomic context if the RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_idle(struct device *dev, int rpmflags)
{
unsigned long flags;
int retval;

might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);

if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
return 0;
Expand All @@ -761,13 +791,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle);
* return immediately if it is larger than zero. Then carry out a suspend,
* either synchronous or asynchronous.
*
* This routine may be called in atomic context if the RPM_ASYNC flag is set.
* This routine may be called in atomic context if the RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_suspend(struct device *dev, int rpmflags)
{
unsigned long flags;
int retval;

might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);

if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
return 0;
Expand All @@ -789,13 +822,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
* If the RPM_GET_PUT flag is set, increment the device's usage count. Then
* carry out a resume, either synchronous or asynchronous.
*
* This routine may be called in atomic context if the RPM_ASYNC flag is set.
* This routine may be called in atomic context if the RPM_ASYNC flag is set,
* or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_resume(struct device *dev, int rpmflags)
{
unsigned long flags;
int retval;

might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);

if (rpmflags & RPM_GET_PUT)
atomic_inc(&dev->power.usage_count);

Expand Down
2 changes: 1 addition & 1 deletion drivers/bluetooth/btusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,7 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
return 0;

spin_lock_irq(&data->txlock);
if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
if (!(PMSG_IS_AUTO(message) && data->tx_in_flight)) {
set_bit(BTUSB_SUSPENDING, &data->flags);
spin_unlock_irq(&data->txlock);
} else {
Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/hid-picolcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2409,7 +2409,7 @@ static int picolcd_raw_event(struct hid_device *hdev,
#ifdef CONFIG_PM
static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
{
if (message.event & PM_EVENT_AUTO)
if (PMSG_IS_AUTO(message))
return 0;

picolcd_suspend_backlight(hid_get_drvdata(hdev));
Expand Down
7 changes: 3 additions & 4 deletions drivers/hid/usbhid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
struct usbhid_device *usbhid = hid->driver_data;
int status;

if (message.event & PM_EVENT_AUTO) {
if (PMSG_IS_AUTO(message)) {
spin_lock_irq(&usbhid->lock); /* Sync with error handler */
if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
&& !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
Expand Down Expand Up @@ -1367,7 +1367,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
return -EIO;
}

if (!ignoreled && (message.event & PM_EVENT_AUTO)) {
if (!ignoreled && PMSG_IS_AUTO(message)) {
spin_lock_irq(&usbhid->lock);
if (test_bit(HID_LED_ON, &usbhid->iofl)) {
spin_unlock_irq(&usbhid->lock);
Expand All @@ -1380,8 +1380,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
hid_cancel_delayed_stuff(usbhid);
hid_cease_io(usbhid);

if ((message.event & PM_EVENT_AUTO) &&
test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
/* lost race against keypresses */
status = hid_start_in(hid);
if (status < 0)
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/usb/usbnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
if (!dev->suspend_count++) {
spin_lock_irq(&dev->txq.lock);
/* don't autosuspend while transmitting */
if (dev->txq.qlen && (message.event & PM_EVENT_AUTO)) {
if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
spin_unlock_irq(&dev->txq.lock);
return -EBUSY;
} else {
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wimax/i2400m/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ void i2400mu_disconnect(struct usb_interface *iface)
*
* As well, the device might refuse going to sleep for whichever
* reason. In this case we just fail. For system suspend/hibernate,
* we *can't* fail. We check PM_EVENT_AUTO to see if the
* we *can't* fail. We check PMSG_IS_AUTO to see if the
* suspend call comes from the USB stack or from the system and act
* in consequence.
*
Expand All @@ -615,7 +615,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
struct i2400m *i2400m = &i2400mu->i2400m;

#ifdef CONFIG_PM
if (pm_msg.event & PM_EVENT_AUTO)
if (PMSG_IS_AUTO(pm_msg))
is_autosuspend = 1;
#endif

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/class/cdc-acm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
struct acm *acm = usb_get_intfdata(intf);
int cnt;

if (message.event & PM_EVENT_AUTO) {
if (PMSG_IS_AUTO(message)) {
int b;

spin_lock_irq(&acm->write_lock);
Expand Down
6 changes: 3 additions & 3 deletions drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -798,11 +798,11 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);

/* if this is an autosuspend the caller does the locking */
if (!(message.event & PM_EVENT_AUTO))
if (!PMSG_IS_AUTO(message))
mutex_lock(&desc->lock);
spin_lock_irq(&desc->iuspin);

if ((message.event & PM_EVENT_AUTO) &&
if (PMSG_IS_AUTO(message) &&
(test_bit(WDM_IN_USE, &desc->flags)
|| test_bit(WDM_RESPONDING, &desc->flags))) {
spin_unlock_irq(&desc->iuspin);
Expand All @@ -815,7 +815,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
}
if (!(message.event & PM_EVENT_AUTO))
if (!PMSG_IS_AUTO(message))
mutex_unlock(&desc->lock);

return rv;
Expand Down
9 changes: 4 additions & 5 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1046,8 +1046,7 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
/* Non-root devices on a full/low-speed bus must wait for their
* companion high-speed root hub, in case a handoff is needed.
*/
if (!(msg.event & PM_EVENT_AUTO) && udev->parent &&
udev->bus->hs_companion)
if (!PMSG_IS_AUTO(msg) && udev->parent && udev->bus->hs_companion)
device_pm_wait_for_dev(&udev->dev,
&udev->bus->hs_companion->root_hub->dev);

Expand Down Expand Up @@ -1075,7 +1074,7 @@ static int usb_suspend_interface(struct usb_device *udev,

if (driver->suspend) {
status = driver->suspend(intf, msg);
if (status && !(msg.event & PM_EVENT_AUTO))
if (status && !PMSG_IS_AUTO(msg))
dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
} else {
Expand Down Expand Up @@ -1189,7 +1188,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
status = usb_suspend_interface(udev, intf, msg);

/* Ignore errors during system sleep transitions */
if (!(msg.event & PM_EVENT_AUTO))
if (!PMSG_IS_AUTO(msg))
status = 0;
if (status != 0)
break;
Expand All @@ -1199,7 +1198,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
status = usb_suspend_device(udev, msg);

/* Again, ignore errors during system sleep transitions */
if (!(msg.event & PM_EVENT_AUTO))
if (!PMSG_IS_AUTO(msg))
status = 0;
}

Expand Down
Loading

0 comments on commit d727b60

Please sign in to comment.