aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-12-07 13:01:37 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:25 -0500
commit8e4ceb38eb5bbaef22fc00abe9bc11e26bea2ab5 (patch)
tree7cb5fee6c50add1094aed430d46afeb2c7689b51 /drivers/usb
parent9af23624ae2c7978313b46e58fdc4ca5d8b799f5 (diff)
USB: prepare for changover to Runtime PM framework
This patch (as1303) revises the USB Power Management infrastructure to make it compatible with the new driver-model Runtime PM framework: Drivers are no longer allowed to access intf->pm_usage_cnt directly; the PM framework manages its own usage counters. usb_autopm_set_interface() is eliminated, because it directly sets intf->pm_usage_cnt. usb_autopm_enable() and usb_autopm_disable() are eliminated, because they call usb_autopm_set_interface(). usb_autopm_get_interface_no_resume() and usb_autopm_put_interface_no_suspend() are added. They correspond to pm_runtime_get_noresume() and pm_runtime_put_noidle() in the PM framework. The power/level attribute no longer accepts "suspend", only "on" and "auto". The PM framework doesn't allow devices to be forced into a suspended mode. The hub driver contains the only code that violates the new guidelines. It is updated to use the new interface routines instead. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/driver.c31
-rw-r--r--drivers/usb/core/hub.c45
-rw-r--r--drivers/usb/core/sysfs.c25
3 files changed, 36 insertions, 65 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 8016a296010e..7a05bab73960 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -948,8 +948,6 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
948 948
949 done: 949 done:
950 dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); 950 dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
951 if (status == 0)
952 udev->autoresume_disabled = 0;
953 return status; 951 return status;
954} 952}
955 953
@@ -1280,11 +1278,6 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
1280 1278
1281 /* Propagate the resume up the tree, if necessary */ 1279 /* Propagate the resume up the tree, if necessary */
1282 if (udev->state == USB_STATE_SUSPENDED) { 1280 if (udev->state == USB_STATE_SUSPENDED) {
1283 if ((msg.event & PM_EVENT_AUTO) &&
1284 udev->autoresume_disabled) {
1285 status = -EPERM;
1286 goto done;
1287 }
1288 if (parent) { 1281 if (parent) {
1289 status = usb_autoresume_device(parent); 1282 status = usb_autoresume_device(parent);
1290 if (status == 0) { 1283 if (status == 0) {
@@ -1638,8 +1631,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
1638 1631
1639 if (intf->condition == USB_INTERFACE_UNBOUND) 1632 if (intf->condition == USB_INTERFACE_UNBOUND)
1640 status = -ENODEV; 1633 status = -ENODEV;
1641 else if (udev->autoresume_disabled)
1642 status = -EPERM;
1643 else { 1634 else {
1644 atomic_inc(&intf->pm_usage_cnt); 1635 atomic_inc(&intf->pm_usage_cnt);
1645 if (atomic_read(&intf->pm_usage_cnt) > 0 && 1636 if (atomic_read(&intf->pm_usage_cnt) > 0 &&
@@ -1652,28 +1643,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
1652} 1643}
1653EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); 1644EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
1654 1645
1655/**
1656 * usb_autopm_set_interface - set a USB interface's autosuspend state
1657 * @intf: the usb_interface whose state should be set
1658 *
1659 * This routine sets the autosuspend state of @intf's device according
1660 * to @intf's usage counter, which the caller must have set previously.
1661 * If the counter is <= 0, the device is autosuspended (if it isn't
1662 * already suspended and if nothing else prevents the autosuspend). If
1663 * the counter is > 0, the device is autoresumed (if it isn't already
1664 * awake).
1665 */
1666int usb_autopm_set_interface(struct usb_interface *intf)
1667{
1668 int status;
1669
1670 status = usb_autopm_do_interface(intf, 0);
1671 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1672 __func__, status, atomic_read(&intf->pm_usage_cnt));
1673 return status;
1674}
1675EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
1676
1677#else 1646#else
1678 1647
1679void usb_autosuspend_work(struct work_struct *work) 1648void usb_autosuspend_work(struct work_struct *work)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5413d712cae0..b38fd6730e2a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -71,6 +71,7 @@ struct usb_hub {
71 71
72 unsigned mA_per_port; /* current for each child */ 72 unsigned mA_per_port; /* current for each child */
73 73
74 unsigned init_done:1;
74 unsigned limited_power:1; 75 unsigned limited_power:1;
75 unsigned quiescing:1; 76 unsigned quiescing:1;
76 unsigned disconnected:1; 77 unsigned disconnected:1;
@@ -375,12 +376,13 @@ static void kick_khubd(struct usb_hub *hub)
375{ 376{
376 unsigned long flags; 377 unsigned long flags;
377 378
378 /* Suppress autosuspend until khubd runs */
379 atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1);
380
381 spin_lock_irqsave(&hub_event_lock, flags); 379 spin_lock_irqsave(&hub_event_lock, flags);
382 if (!hub->disconnected && list_empty(&hub->event_list)) { 380 if (!hub->disconnected && list_empty(&hub->event_list)) {
383 list_add_tail(&hub->event_list, &hub_event_list); 381 list_add_tail(&hub->event_list, &hub_event_list);
382
383 /* Suppress autosuspend until khubd runs */
384 usb_autopm_get_interface_no_resume(
385 to_usb_interface(hub->intfdev));
384 wake_up(&khubd_wait); 386 wake_up(&khubd_wait);
385 } 387 }
386 spin_unlock_irqrestore(&hub_event_lock, flags); 388 spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -665,7 +667,7 @@ int usb_remove_device(struct usb_device *udev)
665} 667}
666 668
667enum hub_activation_type { 669enum hub_activation_type {
668 HUB_INIT, HUB_INIT2, HUB_INIT3, 670 HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */
669 HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, 671 HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
670}; 672};
671 673
@@ -710,8 +712,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
710 msecs_to_jiffies(delay)); 712 msecs_to_jiffies(delay));
711 713
712 /* Suppress autosuspend until init is done */ 714 /* Suppress autosuspend until init is done */
713 atomic_set(&to_usb_interface(hub->intfdev)-> 715 usb_autopm_get_interface_no_resume(
714 pm_usage_cnt, 1); 716 to_usb_interface(hub->intfdev));
715 return; /* Continues at init2: below */ 717 return; /* Continues at init2: below */
716 } else { 718 } else {
717 hub_power_on(hub, true); 719 hub_power_on(hub, true);
@@ -818,6 +820,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
818 } 820 }
819 init3: 821 init3:
820 hub->quiescing = 0; 822 hub->quiescing = 0;
823 hub->init_done = 1;
821 824
822 status = usb_submit_urb(hub->urb, GFP_NOIO); 825 status = usb_submit_urb(hub->urb, GFP_NOIO);
823 if (status < 0) 826 if (status < 0)
@@ -827,6 +830,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
827 830
828 /* Scan all ports that need attention */ 831 /* Scan all ports that need attention */
829 kick_khubd(hub); 832 kick_khubd(hub);
833
834 /* Allow autosuspend if it was suppressed */
835 if (type <= HUB_INIT3)
836 usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
830} 837}
831 838
832/* Implement the continuations for the delays above */ 839/* Implement the continuations for the delays above */
@@ -854,6 +861,11 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
854 int i; 861 int i;
855 862
856 cancel_delayed_work_sync(&hub->init_work); 863 cancel_delayed_work_sync(&hub->init_work);
864 if (!hub->init_done) {
865 hub->init_done = 1;
866 usb_autopm_put_interface_no_suspend(
867 to_usb_interface(hub->intfdev));
868 }
857 869
858 /* khubd and related activity won't re-trigger */ 870 /* khubd and related activity won't re-trigger */
859 hub->quiescing = 1; 871 hub->quiescing = 1;
@@ -1176,7 +1188,10 @@ static void hub_disconnect(struct usb_interface *intf)
1176 1188
1177 /* Take the hub off the event list and don't let it be added again */ 1189 /* Take the hub off the event list and don't let it be added again */
1178 spin_lock_irq(&hub_event_lock); 1190 spin_lock_irq(&hub_event_lock);
1179 list_del_init(&hub->event_list); 1191 if (!list_empty(&hub->event_list)) {
1192 list_del_init(&hub->event_list);
1193 usb_autopm_put_interface_no_suspend(intf);
1194 }
1180 hub->disconnected = 1; 1195 hub->disconnected = 1;
1181 spin_unlock_irq(&hub_event_lock); 1196 spin_unlock_irq(&hub_event_lock);
1182 1197
@@ -3235,7 +3250,7 @@ static void hub_events(void)
3235 * disconnected while waiting for the lock to succeed. */ 3250 * disconnected while waiting for the lock to succeed. */
3236 usb_lock_device(hdev); 3251 usb_lock_device(hdev);
3237 if (unlikely(hub->disconnected)) 3252 if (unlikely(hub->disconnected))
3238 goto loop; 3253 goto loop2;
3239 3254
3240 /* If the hub has died, clean up after it */ 3255 /* If the hub has died, clean up after it */
3241 if (hdev->state == USB_STATE_NOTATTACHED) { 3256 if (hdev->state == USB_STATE_NOTATTACHED) {
@@ -3384,11 +3399,15 @@ static void hub_events(void)
3384 } 3399 }
3385 } 3400 }
3386 3401
3387loop_autopm: 3402 loop_autopm:
3388 /* Allow autosuspend if we're not going to run again */ 3403 /* Balance the usb_autopm_get_interface() above */
3389 if (list_empty(&hub->event_list)) 3404 usb_autopm_put_interface_no_suspend(intf);
3390 usb_autopm_enable(intf); 3405 loop:
3391loop: 3406 /* Balance the usb_autopm_get_interface_no_resume() in
3407 * kick_khubd() and allow autosuspend.
3408 */
3409 usb_autopm_put_interface(intf);
3410 loop2:
3392 usb_unlock_device(hdev); 3411 usb_unlock_device(hdev);
3393 kref_put(&hub->kref, hub_release); 3412 kref_put(&hub->kref, hub_release);
3394 3413
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index ae763974be25..15477008b631 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -327,7 +327,6 @@ static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
327 327
328static const char on_string[] = "on"; 328static const char on_string[] = "on";
329static const char auto_string[] = "auto"; 329static const char auto_string[] = "auto";
330static const char suspend_string[] = "suspend";
331 330
332static ssize_t 331static ssize_t
333show_level(struct device *dev, struct device_attribute *attr, char *buf) 332show_level(struct device *dev, struct device_attribute *attr, char *buf)
@@ -335,13 +334,8 @@ show_level(struct device *dev, struct device_attribute *attr, char *buf)
335 struct usb_device *udev = to_usb_device(dev); 334 struct usb_device *udev = to_usb_device(dev);
336 const char *p = auto_string; 335 const char *p = auto_string;
337 336
338 if (udev->state == USB_STATE_SUSPENDED) { 337 if (udev->state != USB_STATE_SUSPENDED && udev->autosuspend_disabled)
339 if (udev->autoresume_disabled) 338 p = on_string;
340 p = suspend_string;
341 } else {
342 if (udev->autosuspend_disabled)
343 p = on_string;
344 }
345 return sprintf(buf, "%s\n", p); 339 return sprintf(buf, "%s\n", p);
346} 340}
347 341
@@ -353,7 +347,7 @@ set_level(struct device *dev, struct device_attribute *attr,
353 int len = count; 347 int len = count;
354 char *cp; 348 char *cp;
355 int rc = 0; 349 int rc = 0;
356 int old_autosuspend_disabled, old_autoresume_disabled; 350 int old_autosuspend_disabled;
357 351
358 cp = memchr(buf, '\n', count); 352 cp = memchr(buf, '\n', count);
359 if (cp) 353 if (cp)
@@ -361,7 +355,6 @@ set_level(struct device *dev, struct device_attribute *attr,
361 355
362 usb_lock_device(udev); 356 usb_lock_device(udev);
363 old_autosuspend_disabled = udev->autosuspend_disabled; 357 old_autosuspend_disabled = udev->autosuspend_disabled;
364 old_autoresume_disabled = udev->autoresume_disabled;
365 358
366 /* Setting the flags without calling usb_pm_lock is a subject to 359 /* Setting the flags without calling usb_pm_lock is a subject to
367 * races, but who cares... 360 * races, but who cares...
@@ -369,28 +362,18 @@ set_level(struct device *dev, struct device_attribute *attr,
369 if (len == sizeof on_string - 1 && 362 if (len == sizeof on_string - 1 &&
370 strncmp(buf, on_string, len) == 0) { 363 strncmp(buf, on_string, len) == 0) {
371 udev->autosuspend_disabled = 1; 364 udev->autosuspend_disabled = 1;
372 udev->autoresume_disabled = 0;
373 rc = usb_external_resume_device(udev, PMSG_USER_RESUME); 365 rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
374 366
375 } else if (len == sizeof auto_string - 1 && 367 } else if (len == sizeof auto_string - 1 &&
376 strncmp(buf, auto_string, len) == 0) { 368 strncmp(buf, auto_string, len) == 0) {
377 udev->autosuspend_disabled = 0; 369 udev->autosuspend_disabled = 0;
378 udev->autoresume_disabled = 0;
379 rc = usb_external_resume_device(udev, PMSG_USER_RESUME); 370 rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
380 371
381 } else if (len == sizeof suspend_string - 1 &&
382 strncmp(buf, suspend_string, len) == 0) {
383 udev->autosuspend_disabled = 0;
384 udev->autoresume_disabled = 1;
385 rc = usb_external_suspend_device(udev, PMSG_USER_SUSPEND);
386
387 } else 372 } else
388 rc = -EINVAL; 373 rc = -EINVAL;
389 374
390 if (rc) { 375 if (rc)
391 udev->autosuspend_disabled = old_autosuspend_disabled; 376 udev->autosuspend_disabled = old_autosuspend_disabled;
392 udev->autoresume_disabled = old_autoresume_disabled;
393 }
394 usb_unlock_device(udev); 377 usb_unlock_device(udev);
395 return (rc < 0 ? rc : count); 378 return (rc < 0 ? rc : count);
396} 379}