Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: Enhance usage of pm_message_t

This patch (as1177) modifies the USB core suspend and resume
routines. The resume functions now will take a pm_message_t argument,
so they will know what sort of resume is occurring. The new argument
is also passed to the port suspend/resume and bus suspend/resume
routines (although they don't use it for anything but debugging).

In addition, special pm_message_t values are used for user-initiated,
device-initiated (i.e., remote wakeup), and automatic suspend/resume.
By testing these values, drivers can tell whether or not a particular
suspend was an autosuspend. Unfortunately, they can't do the same for
resumes -- not until the pm_message_t argument is also passed to the
drivers' resume methods. That will require a bigger change.

IMO, the whole Power Management framework should have been set up this
way in the first place.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
65bfd296 4ec06d62

+74 -63
+1 -1
drivers/usb/class/cdc-acm.c
··· 1275 1275 struct acm *acm = usb_get_intfdata(intf); 1276 1276 int cnt; 1277 1277 1278 - if (acm->dev->auto_pm) { 1278 + if (message.event & PM_EVENT_AUTO) { 1279 1279 int b; 1280 1280 1281 1281 spin_lock_irq(&acm->read_lock);
+2 -1
drivers/usb/class/cdc-wdm.c
··· 764 764 765 765 mutex_lock(&desc->plock); 766 766 #ifdef CONFIG_PM 767 - if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) { 767 + if ((message.event & PM_EVENT_AUTO) && 768 + test_bit(WDM_IN_USE, &desc->flags)) { 768 769 rv = -EBUSY; 769 770 } else { 770 771 #endif
+34 -27
drivers/usb/core/driver.c
··· 922 922 } 923 923 924 924 /* Caller has locked udev's pm_mutex */ 925 - static int usb_resume_device(struct usb_device *udev) 925 + static int usb_resume_device(struct usb_device *udev, pm_message_t msg) 926 926 { 927 927 struct usb_device_driver *udriver; 928 928 int status = 0; ··· 940 940 udev->reset_resume = 1; 941 941 942 942 udriver = to_usb_device_driver(udev->dev.driver); 943 - status = udriver->resume(udev); 943 + status = udriver->resume(udev, msg); 944 944 945 945 done: 946 946 dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); ··· 969 969 status = driver->suspend(intf, msg); 970 970 if (status == 0) 971 971 mark_quiesced(intf); 972 - else if (!udev->auto_pm) 972 + else if (!(msg.event & PM_EVENT_AUTO)) 973 973 dev_err(&intf->dev, "%s error %d\n", 974 974 "suspend", status); 975 975 } else { ··· 987 987 988 988 /* Caller has locked intf's usb_device's pm_mutex */ 989 989 static int usb_resume_interface(struct usb_device *udev, 990 - struct usb_interface *intf, int reset_resume) 990 + struct usb_interface *intf, pm_message_t msg, int reset_resume) 991 991 { 992 992 struct usb_driver *driver; 993 993 int status = 0; ··· 1138 1138 * all the interfaces which were suspended are resumed so that they remain 1139 1139 * in the same state as the device. 1140 1140 * 1141 - * If an autosuspend is in progress (@udev->auto_pm is set), the routine 1142 - * checks first to make sure that neither the device itself or any of its 1143 - * active interfaces is in use (pm_usage_cnt is greater than 0). If they 1144 - * are, the autosuspend fails. 1141 + * If an autosuspend is in progress the routine checks first to make sure 1142 + * that neither the device itself or any of its active interfaces is in use 1143 + * (pm_usage_cnt is greater than 0). If they are, the autosuspend fails. 1145 1144 * 1146 1145 * If the suspend succeeds, the routine recursively queues an autosuspend 1147 1146 * request for @udev's parent device, thereby propagating the change up ··· 1175 1176 1176 1177 udev->do_remote_wakeup = device_may_wakeup(&udev->dev); 1177 1178 1178 - if (udev->auto_pm) { 1179 + if (msg.event & PM_EVENT_AUTO) { 1179 1180 status = autosuspend_check(udev, 0); 1180 1181 if (status < 0) 1181 1182 goto done; ··· 1195 1196 1196 1197 /* If the suspend failed, resume interfaces that did get suspended */ 1197 1198 if (status != 0) { 1199 + pm_message_t msg2; 1200 + 1201 + msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME); 1198 1202 while (--i >= 0) { 1199 1203 intf = udev->actconfig->interface[i]; 1200 - usb_resume_interface(udev, intf, 0); 1204 + usb_resume_interface(udev, intf, msg2, 0); 1201 1205 } 1202 1206 1203 1207 /* Try another autosuspend when the interfaces aren't busy */ 1204 - if (udev->auto_pm) 1208 + if (msg.event & PM_EVENT_AUTO) 1205 1209 autosuspend_check(udev, status == -EBUSY); 1206 1210 1207 1211 /* If the suspend succeeded then prevent any more URB submissions, ··· 1234 1232 /** 1235 1233 * usb_resume_both - resume a USB device and its interfaces 1236 1234 * @udev: the usb_device to resume 1235 + * @msg: Power Management message describing this state transition 1237 1236 * 1238 1237 * This is the central routine for resuming USB devices. It calls the 1239 1238 * the resume method for @udev and then calls the resume methods for all ··· 1260 1257 * 1261 1258 * This routine can run only in process context. 1262 1259 */ 1263 - static int usb_resume_both(struct usb_device *udev) 1260 + static int usb_resume_both(struct usb_device *udev, pm_message_t msg) 1264 1261 { 1265 1262 int status = 0; 1266 1263 int i; ··· 1276 1273 1277 1274 /* Propagate the resume up the tree, if necessary */ 1278 1275 if (udev->state == USB_STATE_SUSPENDED) { 1279 - if (udev->auto_pm && udev->autoresume_disabled) { 1276 + if ((msg.event & PM_EVENT_AUTO) && 1277 + udev->autoresume_disabled) { 1280 1278 status = -EPERM; 1281 1279 goto done; 1282 1280 } 1283 1281 if (parent) { 1284 1282 status = usb_autoresume_device(parent); 1285 1283 if (status == 0) { 1286 - status = usb_resume_device(udev); 1284 + status = usb_resume_device(udev, msg); 1287 1285 if (status || udev->state == 1288 1286 USB_STATE_NOTATTACHED) { 1289 1287 usb_autosuspend_device(parent); ··· 1307 1303 /* We can't progagate beyond the USB subsystem, 1308 1304 * so if a root hub's controller is suspended 1309 1305 * then we're stuck. */ 1310 - status = usb_resume_device(udev); 1306 + status = usb_resume_device(udev, msg); 1311 1307 } 1312 1308 } else if (udev->reset_resume) 1313 - status = usb_resume_device(udev); 1309 + status = usb_resume_device(udev, msg); 1314 1310 1315 1311 if (status == 0 && udev->actconfig) { 1316 1312 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { 1317 1313 intf = udev->actconfig->interface[i]; 1318 - usb_resume_interface(udev, intf, udev->reset_resume); 1314 + usb_resume_interface(udev, intf, msg, 1315 + udev->reset_resume); 1319 1316 } 1320 1317 } 1321 1318 ··· 1344 1339 udev->last_busy = jiffies; 1345 1340 if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { 1346 1341 if (udev->state == USB_STATE_SUSPENDED) 1347 - status = usb_resume_both(udev); 1342 + status = usb_resume_both(udev, PMSG_AUTO_RESUME); 1348 1343 if (status != 0) 1349 1344 udev->pm_usage_cnt -= inc_usage_cnt; 1350 1345 else if (inc_usage_cnt) 1351 1346 udev->last_busy = jiffies; 1352 1347 } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) { 1353 - status = usb_suspend_both(udev, PMSG_SUSPEND); 1348 + status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); 1354 1349 } 1355 1350 usb_pm_unlock(udev); 1356 1351 return status; ··· 1474 1469 udev->last_busy = jiffies; 1475 1470 if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { 1476 1471 if (udev->state == USB_STATE_SUSPENDED) 1477 - status = usb_resume_both(udev); 1472 + status = usb_resume_both(udev, 1473 + PMSG_AUTO_RESUME); 1478 1474 if (status != 0) 1479 1475 intf->pm_usage_cnt -= inc_usage_cnt; 1480 1476 else 1481 1477 udev->last_busy = jiffies; 1482 1478 } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { 1483 - status = usb_suspend_both(udev, PMSG_SUSPEND); 1479 + status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); 1484 1480 } 1485 1481 } 1486 1482 usb_pm_unlock(udev); ··· 1706 1700 /** 1707 1701 * usb_external_resume_device - external resume of a USB device and its interfaces 1708 1702 * @udev: the usb_device to resume 1703 + * @msg: Power Management message describing this state transition 1709 1704 * 1710 1705 * This routine handles external resume requests: ones not generated 1711 1706 * internally by a USB driver (autoresume) but rather coming from the user ··· 1715 1708 * 1716 1709 * The caller must hold @udev's device lock. 1717 1710 */ 1718 - int usb_external_resume_device(struct usb_device *udev) 1711 + int usb_external_resume_device(struct usb_device *udev, pm_message_t msg) 1719 1712 { 1720 1713 int status; 1721 1714 1722 1715 usb_pm_lock(udev); 1723 1716 udev->auto_pm = 0; 1724 - status = usb_resume_both(udev); 1717 + status = usb_resume_both(udev, msg); 1725 1718 udev->last_busy = jiffies; 1726 1719 usb_pm_unlock(udev); 1727 1720 if (status == 0) ··· 1734 1727 return status; 1735 1728 } 1736 1729 1737 - int usb_suspend(struct device *dev, pm_message_t message) 1730 + int usb_suspend(struct device *dev, pm_message_t msg) 1738 1731 { 1739 1732 struct usb_device *udev; 1740 1733 ··· 1753 1746 } 1754 1747 1755 1748 udev->skip_sys_resume = 0; 1756 - return usb_external_suspend_device(udev, message); 1749 + return usb_external_suspend_device(udev, msg); 1757 1750 } 1758 1751 1759 - int usb_resume(struct device *dev) 1752 + int usb_resume(struct device *dev, pm_message_t msg) 1760 1753 { 1761 1754 struct usb_device *udev; 1762 1755 ··· 1768 1761 */ 1769 1762 if (udev->skip_sys_resume) 1770 1763 return 0; 1771 - return usb_external_resume_device(udev); 1764 + return usb_external_resume_device(udev, msg); 1772 1765 } 1773 1766 1774 1767 #endif /* CONFIG_PM */
+5 -5
drivers/usb/core/generic.c
··· 200 200 * interfaces manually by doing a bus (or "global") suspend. 201 201 */ 202 202 if (!udev->parent) 203 - rc = hcd_bus_suspend(udev); 203 + rc = hcd_bus_suspend(udev, msg); 204 204 205 205 /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ 206 206 else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) 207 207 rc = 0; 208 208 else 209 - rc = usb_port_suspend(udev); 209 + rc = usb_port_suspend(udev, msg); 210 210 211 211 return rc; 212 212 } 213 213 214 - static int generic_resume(struct usb_device *udev) 214 + static int generic_resume(struct usb_device *udev, pm_message_t msg) 215 215 { 216 216 int rc; 217 217 ··· 221 221 * interfaces manually by doing a bus (or "global") resume. 222 222 */ 223 223 if (!udev->parent) 224 - rc = hcd_bus_resume(udev); 224 + rc = hcd_bus_resume(udev, msg); 225 225 else 226 - rc = usb_port_resume(udev); 226 + rc = usb_port_resume(udev, msg); 227 227 return rc; 228 228 } 229 229
+5 -5
drivers/usb/core/hcd.c
··· 1573 1573 1574 1574 #ifdef CONFIG_PM 1575 1575 1576 - int hcd_bus_suspend(struct usb_device *rhdev) 1576 + int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) 1577 1577 { 1578 1578 struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); 1579 1579 int status; 1580 1580 int old_state = hcd->state; 1581 1581 1582 1582 dev_dbg(&rhdev->dev, "bus %s%s\n", 1583 - rhdev->auto_pm ? "auto-" : "", "suspend"); 1583 + (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend"); 1584 1584 if (!hcd->driver->bus_suspend) { 1585 1585 status = -ENOENT; 1586 1586 } else { ··· 1598 1598 return status; 1599 1599 } 1600 1600 1601 - int hcd_bus_resume(struct usb_device *rhdev) 1601 + int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) 1602 1602 { 1603 1603 struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); 1604 1604 int status; 1605 1605 int old_state = hcd->state; 1606 1606 1607 1607 dev_dbg(&rhdev->dev, "usb %s%s\n", 1608 - rhdev->auto_pm ? "auto-" : "", "resume"); 1608 + (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume"); 1609 1609 if (!hcd->driver->bus_resume) 1610 1610 return -ENOENT; 1611 1611 if (hcd->state == HC_STATE_RUNNING) ··· 1638 1638 1639 1639 usb_lock_device(udev); 1640 1640 usb_mark_last_busy(udev); 1641 - usb_external_resume_device(udev); 1641 + usb_external_resume_device(udev, PMSG_REMOTE_RESUME); 1642 1642 usb_unlock_device(udev); 1643 1643 } 1644 1644
+2 -2
drivers/usb/core/hcd.h
··· 388 388 #ifdef CONFIG_PM 389 389 extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd); 390 390 extern void usb_root_hub_lost_power(struct usb_device *rhdev); 391 - extern int hcd_bus_suspend(struct usb_device *rhdev); 392 - extern int hcd_bus_resume(struct usb_device *rhdev); 391 + extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg); 392 + extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg); 393 393 #else 394 394 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) 395 395 {
+8 -8
drivers/usb/core/hub.c
··· 1984 1984 * 1985 1985 * Returns 0 on success, else negative errno. 1986 1986 */ 1987 - int usb_port_suspend(struct usb_device *udev) 1987 + int usb_port_suspend(struct usb_device *udev, pm_message_t msg) 1988 1988 { 1989 1989 struct usb_hub *hub = hdev_to_hub(udev->parent); 1990 1990 int port1 = udev->portnum; ··· 2023 2023 } else { 2024 2024 /* device has up to 10 msec to fully suspend */ 2025 2025 dev_dbg(&udev->dev, "usb %ssuspend\n", 2026 - udev->auto_pm ? "auto-" : ""); 2026 + (msg.event & PM_EVENT_AUTO ? "auto-" : "")); 2027 2027 usb_set_device_state(udev, USB_STATE_SUSPENDED); 2028 2028 msleep(10); 2029 2029 } ··· 2142 2142 * 2143 2143 * Returns 0 on success, else negative errno. 2144 2144 */ 2145 - int usb_port_resume(struct usb_device *udev) 2145 + int usb_port_resume(struct usb_device *udev, pm_message_t msg) 2146 2146 { 2147 2147 struct usb_hub *hub = hdev_to_hub(udev->parent); 2148 2148 int port1 = udev->portnum; ··· 2167 2167 } else { 2168 2168 /* drive resume for at least 20 msec */ 2169 2169 dev_dbg(&udev->dev, "usb %sresume\n", 2170 - udev->auto_pm ? "auto-" : ""); 2170 + (msg.event & PM_EVENT_AUTO ? "auto-" : "")); 2171 2171 msleep(25); 2172 2172 2173 2173 /* Virtual root hubs can trigger on GET_PORT_STATUS to ··· 2208 2208 if (udev->state == USB_STATE_SUSPENDED) { 2209 2209 dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); 2210 2210 usb_mark_last_busy(udev); 2211 - status = usb_external_resume_device(udev); 2211 + status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME); 2212 2212 } 2213 2213 return status; 2214 2214 } ··· 2217 2217 2218 2218 /* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ 2219 2219 2220 - int usb_port_suspend(struct usb_device *udev) 2220 + int usb_port_suspend(struct usb_device *udev, pm_message_t msg) 2221 2221 { 2222 2222 return 0; 2223 2223 } 2224 2224 2225 2225 /* However we may need to do a reset-resume */ 2226 2226 2227 - int usb_port_resume(struct usb_device *udev) 2227 + int usb_port_resume(struct usb_device *udev, pm_message_t msg) 2228 2228 { 2229 2229 struct usb_hub *hub = hdev_to_hub(udev->parent); 2230 2230 int port1 = udev->portnum; ··· 2264 2264 2265 2265 udev = hdev->children [port1-1]; 2266 2266 if (udev && udev->can_submit) { 2267 - if (!hdev->auto_pm) 2267 + if (!(msg.event & PM_EVENT_AUTO)) 2268 2268 dev_dbg(&intf->dev, "port %d nyet suspended\n", 2269 2269 port1); 2270 2270 return -EBUSY;
+3 -3
drivers/usb/core/sysfs.c
··· 359 359 strncmp(buf, on_string, len) == 0) { 360 360 udev->autosuspend_disabled = 1; 361 361 udev->autoresume_disabled = 0; 362 - rc = usb_external_resume_device(udev); 362 + rc = usb_external_resume_device(udev, PMSG_USER_RESUME); 363 363 364 364 } else if (len == sizeof auto_string - 1 && 365 365 strncmp(buf, auto_string, len) == 0) { 366 366 udev->autosuspend_disabled = 0; 367 367 udev->autoresume_disabled = 0; 368 - rc = usb_external_resume_device(udev); 368 + rc = usb_external_resume_device(udev, PMSG_USER_RESUME); 369 369 370 370 } else if (len == sizeof suspend_string - 1 && 371 371 strncmp(buf, suspend_string, len) == 0) { 372 372 udev->autosuspend_disabled = 0; 373 373 udev->autoresume_disabled = 1; 374 - rc = usb_external_suspend_device(udev, PMSG_SUSPEND); 374 + rc = usb_external_suspend_device(udev, PMSG_USER_SUSPEND); 375 375 376 376 } else 377 377 rc = -EINVAL;
+4 -4
drivers/usb/core/usb.c
··· 253 253 static void usb_dev_complete(struct device *dev) 254 254 { 255 255 /* Currently used only for rebinding interfaces */ 256 - usb_resume(dev); /* Implement eventually? */ 256 + usb_resume(dev, PMSG_RESUME); /* Message event is meaningless */ 257 257 } 258 258 259 259 static int usb_dev_suspend(struct device *dev) ··· 263 263 264 264 static int usb_dev_resume(struct device *dev) 265 265 { 266 - return usb_resume(dev); 266 + return usb_resume(dev, PMSG_RESUME); 267 267 } 268 268 269 269 static int usb_dev_freeze(struct device *dev) ··· 273 273 274 274 static int usb_dev_thaw(struct device *dev) 275 275 { 276 - return usb_resume(dev); 276 + return usb_resume(dev, PMSG_THAW); 277 277 } 278 278 279 279 static int usb_dev_poweroff(struct device *dev) ··· 283 283 284 284 static int usb_dev_restore(struct device *dev) 285 285 { 286 - return usb_resume(dev); 286 + return usb_resume(dev, PMSG_RESTORE); 287 287 } 288 288 289 289 static struct dev_pm_ops usb_device_pm_ops = {
+9 -6
drivers/usb/core/usb.h
··· 1 + #include <linux/pm.h> 2 + 1 3 /* Functions local to drivers/usb/core/ */ 2 4 3 5 extern int usb_create_sysfs_dev_files(struct usb_device *dev); ··· 44 42 #ifdef CONFIG_PM 45 43 46 44 extern int usb_suspend(struct device *dev, pm_message_t msg); 47 - extern int usb_resume(struct device *dev); 45 + extern int usb_resume(struct device *dev, pm_message_t msg); 48 46 49 47 extern void usb_autosuspend_work(struct work_struct *work); 50 48 extern void usb_autoresume_work(struct work_struct *work); 51 - extern int usb_port_suspend(struct usb_device *dev); 52 - extern int usb_port_resume(struct usb_device *dev); 49 + extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg); 50 + extern int usb_port_resume(struct usb_device *dev, pm_message_t msg); 53 51 extern int usb_external_suspend_device(struct usb_device *udev, 54 52 pm_message_t msg); 55 - extern int usb_external_resume_device(struct usb_device *udev); 53 + extern int usb_external_resume_device(struct usb_device *udev, 54 + pm_message_t msg); 56 55 57 56 static inline void usb_pm_lock(struct usb_device *udev) 58 57 { ··· 67 64 68 65 #else 69 66 70 - static inline int usb_port_suspend(struct usb_device *udev) 67 + static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg) 71 68 { 72 69 return 0; 73 70 } 74 71 75 - static inline int usb_port_resume(struct usb_device *udev) 72 + static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) 76 73 { 77 74 return 0; 78 75 }
+1 -1
include/linux/usb.h
··· 1067 1067 void (*disconnect) (struct usb_device *udev); 1068 1068 1069 1069 int (*suspend) (struct usb_device *udev, pm_message_t message); 1070 - int (*resume) (struct usb_device *udev); 1070 + int (*resume) (struct usb_device *udev, pm_message_t message); 1071 1071 struct usbdrv_wrap drvwrap; 1072 1072 unsigned int supports_autosuspend:1; 1073 1073 };