aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-03-27 13:33:59 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 16:28:39 -0400
commit1941044aa9632aa8debbb94a3c8a5ed0ebddade8 (patch)
treeea885677876b793a26cf684eca6f8639478eb222
parent38c3cb5b677cf551cd93a494dc5c551271d90ac1 (diff)
USB: add "last_busy" field for use in autosuspend
This patch (as877) adds a "last_busy" field to struct usb_device, for use by the autosuspend framework. Now if an autosuspend call comes at a time when the device isn't busy but hasn't yet been idle for long enough, the timer can be set to exactly the desired value. And we will be ready to handle things like HID drivers, which can't maintain a useful usage count and must rely on the time-of-last-use to decide when to autosuspend. The patch also makes some related minor improvements: Move the calls to the autosuspend condition-checking routine into usb_suspend_both(), which is the only place where it really matters. If the autosuspend timer is already running, don't stop and restart it. Replace immediate returns with gotos so that the optional debugging ouput won't be bypassed. If autoresume is disabled but the device is already awake, don't return an error for an autoresume call. Don't try to autoresume a device if it isn't suspended. (Yes, this undercuts the previous change -- so sue me.) Don't duplicate existing code in the autosuspend work routine. Fix the kerneldoc in usb_autopm_put_interface(): If an autoresume call fails, the usage counter is left unchanged. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/driver.c102
-rw-r--r--drivers/usb/core/hcd.c1
-rw-r--r--drivers/usb/core/hub.c1
-rw-r--r--include/linux/usb.h8
4 files changed, 75 insertions, 37 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 593386eb974d..631f30582481 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -932,6 +932,7 @@ static int autosuspend_check(struct usb_device *udev)
932{ 932{
933 int i; 933 int i;
934 struct usb_interface *intf; 934 struct usb_interface *intf;
935 long suspend_time;
935 936
936 /* For autosuspend, fail fast if anything is in use or autosuspend 937 /* For autosuspend, fail fast if anything is in use or autosuspend
937 * is disabled. Also fail if any interfaces require remote wakeup 938 * is disabled. Also fail if any interfaces require remote wakeup
@@ -943,6 +944,7 @@ static int autosuspend_check(struct usb_device *udev)
943 if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) 944 if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
944 return -EPERM; 945 return -EPERM;
945 946
947 suspend_time = udev->last_busy + udev->autosuspend_delay;
946 if (udev->actconfig) { 948 if (udev->actconfig) {
947 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { 949 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
948 intf = udev->actconfig->interface[i]; 950 intf = udev->actconfig->interface[i];
@@ -958,6 +960,17 @@ static int autosuspend_check(struct usb_device *udev)
958 } 960 }
959 } 961 }
960 } 962 }
963
964 /* If everything is okay but the device hasn't been idle for long
965 * enough, queue a delayed autosuspend request.
966 */
967 suspend_time -= jiffies;
968 if (suspend_time > 0) {
969 if (!timer_pending(&udev->autosuspend.timer))
970 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
971 suspend_time);
972 return -EAGAIN;
973 }
961 return 0; 974 return 0;
962} 975}
963 976
@@ -1010,19 +1023,18 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
1010 struct usb_interface *intf; 1023 struct usb_interface *intf;
1011 struct usb_device *parent = udev->parent; 1024 struct usb_device *parent = udev->parent;
1012 1025
1013 cancel_delayed_work(&udev->autosuspend); 1026 if (udev->state == USB_STATE_NOTATTACHED ||
1014 if (udev->state == USB_STATE_NOTATTACHED) 1027 udev->state == USB_STATE_SUSPENDED)
1015 return 0; 1028 goto done;
1016 if (udev->state == USB_STATE_SUSPENDED)
1017 return 0;
1018 1029
1019 udev->do_remote_wakeup = device_may_wakeup(&udev->dev); 1030 udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
1020 1031
1021 if (udev->auto_pm) { 1032 if (udev->auto_pm) {
1022 status = autosuspend_check(udev); 1033 status = autosuspend_check(udev);
1023 if (status < 0) 1034 if (status < 0)
1024 return status; 1035 goto done;
1025 } 1036 }
1037 cancel_delayed_work(&udev->autosuspend);
1026 1038
1027 /* Suspend all the interfaces and then udev itself */ 1039 /* Suspend all the interfaces and then udev itself */
1028 if (udev->actconfig) { 1040 if (udev->actconfig) {
@@ -1047,6 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
1047 } else if (parent) 1059 } else if (parent)
1048 usb_autosuspend_device(parent); 1060 usb_autosuspend_device(parent);
1049 1061
1062 done:
1050 // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); 1063 // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
1051 return status; 1064 return status;
1052} 1065}
@@ -1086,14 +1099,18 @@ static int usb_resume_both(struct usb_device *udev)
1086 struct usb_interface *intf; 1099 struct usb_interface *intf;
1087 struct usb_device *parent = udev->parent; 1100 struct usb_device *parent = udev->parent;
1088 1101
1089 if (udev->auto_pm && udev->autoresume_disabled)
1090 return -EPERM;
1091 cancel_delayed_work(&udev->autosuspend); 1102 cancel_delayed_work(&udev->autosuspend);
1092 if (udev->state == USB_STATE_NOTATTACHED) 1103 if (udev->state == USB_STATE_NOTATTACHED) {
1093 return -ENODEV; 1104 status = -ENODEV;
1105 goto done;
1106 }
1094 1107
1095 /* Propagate the resume up the tree, if necessary */ 1108 /* Propagate the resume up the tree, if necessary */
1096 if (udev->state == USB_STATE_SUSPENDED) { 1109 if (udev->state == USB_STATE_SUSPENDED) {
1110 if (udev->auto_pm && udev->autoresume_disabled) {
1111 status = -EPERM;
1112 goto done;
1113 }
1097 if (parent) { 1114 if (parent) {
1098 status = usb_autoresume_device(parent); 1115 status = usb_autoresume_device(parent);
1099 if (status == 0) { 1116 if (status == 0) {
@@ -1139,24 +1156,13 @@ static int usb_resume_both(struct usb_device *udev)
1139 } 1156 }
1140 } 1157 }
1141 1158
1159 done:
1142 // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); 1160 // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
1143 return status; 1161 return status;
1144} 1162}
1145 1163
1146#ifdef CONFIG_USB_SUSPEND 1164#ifdef CONFIG_USB_SUSPEND
1147 1165
1148/* usb_autosuspend_work - callback routine to autosuspend a USB device */
1149void usb_autosuspend_work(struct work_struct *work)
1150{
1151 struct usb_device *udev =
1152 container_of(work, struct usb_device, autosuspend.work);
1153
1154 usb_pm_lock(udev);
1155 udev->auto_pm = 1;
1156 usb_suspend_both(udev, PMSG_SUSPEND);
1157 usb_pm_unlock(udev);
1158}
1159
1160/* Internal routine to adjust a device's usage counter and change 1166/* Internal routine to adjust a device's usage counter and change
1161 * its autosuspend state. 1167 * its autosuspend state.
1162 */ 1168 */
@@ -1165,20 +1171,34 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
1165 int status = 0; 1171 int status = 0;
1166 1172
1167 usb_pm_lock(udev); 1173 usb_pm_lock(udev);
1174 udev->auto_pm = 1;
1168 udev->pm_usage_cnt += inc_usage_cnt; 1175 udev->pm_usage_cnt += inc_usage_cnt;
1169 WARN_ON(udev->pm_usage_cnt < 0); 1176 WARN_ON(udev->pm_usage_cnt < 0);
1170 if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { 1177 if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
1171 udev->auto_pm = 1; 1178 if (udev->state == USB_STATE_SUSPENDED)
1172 status = usb_resume_both(udev); 1179 status = usb_resume_both(udev);
1173 if (status != 0) 1180 if (status != 0)
1174 udev->pm_usage_cnt -= inc_usage_cnt; 1181 udev->pm_usage_cnt -= inc_usage_cnt;
1175 } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) 1182 else if (inc_usage_cnt)
1176 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, 1183 udev->last_busy = jiffies;
1177 udev->autosuspend_delay); 1184 } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
1185 if (inc_usage_cnt)
1186 udev->last_busy = jiffies;
1187 status = usb_suspend_both(udev, PMSG_SUSPEND);
1188 }
1178 usb_pm_unlock(udev); 1189 usb_pm_unlock(udev);
1179 return status; 1190 return status;
1180} 1191}
1181 1192
1193/* usb_autosuspend_work - callback routine to autosuspend a USB device */
1194void usb_autosuspend_work(struct work_struct *work)
1195{
1196 struct usb_device *udev =
1197 container_of(work, struct usb_device, autosuspend.work);
1198
1199 usb_autopm_do_device(udev, 0);
1200}
1201
1182/** 1202/**
1183 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces 1203 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
1184 * @udev: the usb_device to autosuspend 1204 * @udev: the usb_device to autosuspend
@@ -1270,15 +1290,20 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
1270 if (intf->condition == USB_INTERFACE_UNBOUND) 1290 if (intf->condition == USB_INTERFACE_UNBOUND)
1271 status = -ENODEV; 1291 status = -ENODEV;
1272 else { 1292 else {
1293 udev->auto_pm = 1;
1273 intf->pm_usage_cnt += inc_usage_cnt; 1294 intf->pm_usage_cnt += inc_usage_cnt;
1274 if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { 1295 if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
1275 udev->auto_pm = 1; 1296 if (udev->state == USB_STATE_SUSPENDED)
1276 status = usb_resume_both(udev); 1297 status = usb_resume_both(udev);
1277 if (status != 0) 1298 if (status != 0)
1278 intf->pm_usage_cnt -= inc_usage_cnt; 1299 intf->pm_usage_cnt -= inc_usage_cnt;
1279 } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) 1300 else if (inc_usage_cnt)
1280 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, 1301 udev->last_busy = jiffies;
1281 udev->autosuspend_delay); 1302 } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
1303 if (inc_usage_cnt)
1304 udev->last_busy = jiffies;
1305 status = usb_suspend_both(udev, PMSG_SUSPEND);
1306 }
1282 } 1307 }
1283 usb_pm_unlock(udev); 1308 usb_pm_unlock(udev);
1284 return status; 1309 return status;
@@ -1337,11 +1362,14 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
1337 * or @intf is unbound. A typical example would be a character-device 1362 * or @intf is unbound. A typical example would be a character-device
1338 * driver when its device file is opened. 1363 * driver when its device file is opened.
1339 * 1364 *
1340 * The routine increments @intf's usage counter. So long as the counter 1365 *
1341 * is greater than 0, autosuspend will not be allowed for @intf or its 1366 * The routine increments @intf's usage counter. (However if the
1342 * usb_device. When the driver is finished using @intf it should call 1367 * autoresume fails then the counter is re-decremented.) So long as the
1343 * usb_autopm_put_interface() to decrement the usage counter and queue 1368 * counter is greater than 0, autosuspend will not be allowed for @intf
1344 * a delayed autosuspend request (if the counter is <= 0). 1369 * or its usb_device. When the driver is finished using @intf it should
1370 * call usb_autopm_put_interface() to decrement the usage counter and
1371 * queue a delayed autosuspend request (if the counter is <= 0).
1372 *
1345 * 1373 *
1346 * Note that @intf->pm_usage_cnt is owned by the interface driver. The 1374 * Note that @intf->pm_usage_cnt is owned by the interface driver. The
1347 * core will not change its value other than the increment and decrement 1375 * core will not change its value other than the increment and decrement
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8bc3ce6d9666..40cf882293e6 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1306,6 +1306,7 @@ static void hcd_resume_work(struct work_struct *work)
1306 struct usb_device *udev = hcd->self.root_hub; 1306 struct usb_device *udev = hcd->self.root_hub;
1307 1307
1308 usb_lock_device(udev); 1308 usb_lock_device(udev);
1309 usb_mark_last_busy(udev);
1309 usb_external_resume_device(udev); 1310 usb_external_resume_device(udev);
1310 usb_unlock_device(udev); 1311 usb_unlock_device(udev);
1311} 1312}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 2a0b15e42bc7..bde29ab2b504 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1859,6 +1859,7 @@ static int remote_wakeup(struct usb_device *udev)
1859 usb_lock_device(udev); 1859 usb_lock_device(udev);
1860 if (udev->state == USB_STATE_SUSPENDED) { 1860 if (udev->state == USB_STATE_SUSPENDED) {
1861 dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); 1861 dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
1862 usb_mark_last_busy(udev);
1862 status = usb_external_resume_device(udev); 1863 status = usb_external_resume_device(udev);
1863 } 1864 }
1864 usb_unlock_device(udev); 1865 usb_unlock_device(udev);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index f9e4445d5b53..cfbd2bb8fa2c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -398,6 +398,7 @@ struct usb_device {
398 struct delayed_work autosuspend; /* for delayed autosuspends */ 398 struct delayed_work autosuspend; /* for delayed autosuspends */
399 struct mutex pm_mutex; /* protects PM operations */ 399 struct mutex pm_mutex; /* protects PM operations */
400 400
401 unsigned long last_busy; /* time of last use */
401 int autosuspend_delay; /* in jiffies */ 402 int autosuspend_delay; /* in jiffies */
402 403
403 unsigned auto_pm:1; /* autosuspend/resume in progress */ 404 unsigned auto_pm:1; /* autosuspend/resume in progress */
@@ -443,6 +444,11 @@ static inline void usb_autopm_disable(struct usb_interface *intf)
443 usb_autopm_set_interface(intf); 444 usb_autopm_set_interface(intf);
444} 445}
445 446
447static inline void usb_mark_last_busy(struct usb_device *udev)
448{
449 udev->last_busy = jiffies;
450}
451
446#else 452#else
447 453
448static inline int usb_autopm_set_interface(struct usb_interface *intf) 454static inline int usb_autopm_set_interface(struct usb_interface *intf)
@@ -457,6 +463,8 @@ static inline void usb_autopm_enable(struct usb_interface *intf)
457{ } 463{ }
458static inline void usb_autopm_disable(struct usb_interface *intf) 464static inline void usb_autopm_disable(struct usb_interface *intf)
459{ } 465{ }
466static inline void usb_mark_last_busy(struct usb_device *udev)
467{ }
460#endif 468#endif
461 469
462/*-------------------------------------------------------------------------*/ 470/*-------------------------------------------------------------------------*/