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

USB: separate root and non-root suspend/resume

This patch (as916) completes the separation of code paths for suspend
and resume of root hubs as opposed to non-root devices. Root hubs
will be power-managed through their bus_suspend and bus_resume
methods, whereas normal devices will use usb_port_suspend() and
usb_port_resume().

Changes to the hcd_bus_{suspend,resume} routines mostly represent
motion of code that was already present elsewhere. They include:

Adding debugging log messages,

Setting the device state appropriately, and

Adding a resume recovery time delay.

Changes to the port-suspend and port-resume routines in hub.c include:

Removal of checks for root devices (since they will never
be triggered), and

Removal of checks for NULL or invalid device pointers (these
were left over from earlier kernel versions and aren't needed
at all).

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
686314cf 4956eccd

+59 -94
+16 -29
drivers/usb/core/generic.c
··· 196 196 { 197 197 int rc; 198 198 199 - rc = usb_port_suspend(udev); 200 - 201 - /* Root hubs don't have upstream ports to suspend, 202 - * so the line above won't do much for them. We have to 203 - * shut down their downstream HC-to-USB interfaces manually, 204 - * by doing a bus (or "global") suspend. 199 + /* Normal USB devices suspend through their upstream port. 200 + * Root hubs don't have upstream ports to suspend, 201 + * so we have to shut down their downstream HC-to-USB 202 + * interfaces manually by doing a bus (or "global") suspend. 205 203 */ 206 - if (rc == 0 && !udev->parent) { 207 - rc = hcd_bus_suspend(udev->bus); 208 - if (rc) { 209 - dev_dbg(&udev->dev, "'global' suspend %d\n", rc); 210 - usb_port_resume(udev); 211 - } 212 - } 204 + if (!udev->parent) 205 + rc = hcd_bus_suspend(udev); 206 + else 207 + rc = usb_port_suspend(udev); 213 208 return rc; 214 209 } 215 210 ··· 212 217 { 213 218 int rc; 214 219 215 - if (udev->reset_resume) 220 + /* Normal USB devices resume/reset through their upstream port. 221 + * Root hubs don't have upstream ports to resume or reset, 222 + * so we have to start up their downstream HC-to-USB 223 + * interfaces manually by doing a bus (or "global") resume. 224 + */ 225 + if (!udev->parent) 226 + rc = hcd_bus_resume(udev); 227 + else if (udev->reset_resume) 216 228 rc = usb_reset_suspended_device(udev); 217 229 else 218 230 rc = usb_port_resume(udev); 219 - 220 - /* Root hubs don't have upstream ports to resume or reset, 221 - * so the line above won't do much for them. We have to 222 - * start up their downstream HC-to-USB interfaces manually, 223 - * by doing a bus (or "global") resume. 224 - */ 225 - if (rc == 0 && !udev->parent) { 226 - rc = hcd_bus_resume(udev->bus); 227 - if (rc) 228 - dev_dbg(&udev->dev, "'global' resume %d\n", rc); 229 - else { 230 - /* TRSMRCY = 10 msec */ 231 - msleep(10); 232 - } 233 - } 234 231 return rc; 235 232 } 236 233
+33 -19
drivers/usb/core/hcd.c
··· 1257 1257 1258 1258 #ifdef CONFIG_PM 1259 1259 1260 - int hcd_bus_suspend (struct usb_bus *bus) 1260 + int hcd_bus_suspend(struct usb_device *rhdev) 1261 1261 { 1262 - struct usb_hcd *hcd; 1263 - int status; 1262 + struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); 1263 + int status; 1264 + int old_state = hcd->state; 1264 1265 1265 - hcd = container_of (bus, struct usb_hcd, self); 1266 - if (!hcd->driver->bus_suspend) 1267 - return -ENOENT; 1268 - hcd->state = HC_STATE_QUIESCING; 1269 - status = hcd->driver->bus_suspend (hcd); 1270 - if (status == 0) 1266 + dev_dbg(&rhdev->dev, "bus %s%s\n", 1267 + rhdev->auto_pm ? "auto-" : "", "suspend"); 1268 + if (!hcd->driver->bus_suspend) { 1269 + status = -ENOENT; 1270 + } else { 1271 + hcd->state = HC_STATE_QUIESCING; 1272 + status = hcd->driver->bus_suspend(hcd); 1273 + } 1274 + if (status == 0) { 1275 + usb_set_device_state(rhdev, USB_STATE_SUSPENDED); 1271 1276 hcd->state = HC_STATE_SUSPENDED; 1272 - else 1273 - dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", 1277 + } else { 1278 + hcd->state = old_state; 1279 + dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", 1274 1280 "suspend", status); 1281 + } 1275 1282 return status; 1276 1283 } 1277 1284 1278 - int hcd_bus_resume (struct usb_bus *bus) 1285 + int hcd_bus_resume(struct usb_device *rhdev) 1279 1286 { 1280 - struct usb_hcd *hcd; 1281 - int status; 1287 + struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); 1288 + int status; 1282 1289 1283 - hcd = container_of (bus, struct usb_hcd, self); 1290 + dev_dbg(&rhdev->dev, "usb %s%s\n", 1291 + rhdev->auto_pm ? "auto-" : "", "resume"); 1284 1292 if (!hcd->driver->bus_resume) 1285 1293 return -ENOENT; 1286 1294 if (hcd->state == HC_STATE_RUNNING) 1287 1295 return 0; 1296 + 1288 1297 hcd->state = HC_STATE_RESUMING; 1289 - status = hcd->driver->bus_resume (hcd); 1290 - if (status == 0) 1298 + status = hcd->driver->bus_resume(hcd); 1299 + if (status == 0) { 1300 + /* TRSMRCY = 10 msec */ 1301 + msleep(10); 1302 + usb_set_device_state(rhdev, rhdev->actconfig 1303 + ? USB_STATE_CONFIGURED 1304 + : USB_STATE_ADDRESS); 1291 1305 hcd->state = HC_STATE_RUNNING; 1292 - else { 1293 - dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", 1306 + } else { 1307 + dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", 1294 1308 "resume", status); 1295 1309 usb_hc_died(hcd); 1296 1310 }
+2 -12
drivers/usb/core/hcd.h
··· 364 364 #ifdef CONFIG_PM 365 365 extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); 366 366 extern void usb_root_hub_lost_power (struct usb_device *rhdev); 367 - extern int hcd_bus_suspend (struct usb_bus *bus); 368 - extern int hcd_bus_resume (struct usb_bus *bus); 367 + extern int hcd_bus_suspend(struct usb_device *rhdev); 368 + extern int hcd_bus_resume(struct usb_device *rhdev); 369 369 #else 370 370 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) 371 371 { 372 372 return; 373 - } 374 - 375 - static inline int hcd_bus_suspend(struct usb_bus *bus) 376 - { 377 - return 0; 378 - } 379 - 380 - static inline int hcd_bus_resume (struct usb_bus *bus) 381 - { 382 - return 0; 383 373 } 384 374 #endif /* CONFIG_PM */ 385 375
+8 -34
drivers/usb/core/hub.c
··· 1722 1722 { 1723 1723 int status = 0; 1724 1724 1725 - /* we change the device's upstream USB link, 1726 - * but root hubs have no upstream USB link. 1727 - */ 1728 - if (udev->parent) 1729 - status = hub_port_suspend(hdev_to_hub(udev->parent), 1730 - udev->portnum, udev); 1731 - else { 1732 - dev_dbg(&udev->dev, "usb %ssuspend\n", 1733 - udev->auto_pm ? "auto-" : ""); 1734 - usb_set_device_state(udev, USB_STATE_SUSPENDED); 1735 - } 1725 + status = hub_port_suspend(hdev_to_hub(udev->parent), 1726 + udev->portnum, udev); 1736 1727 return status; 1737 1728 } 1738 1729 ··· 1766 1775 status); 1767 1776 else if (udev->actconfig) { 1768 1777 le16_to_cpus(&devstatus); 1769 - if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) 1770 - && udev->parent) { 1778 + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { 1771 1779 status = usb_control_msg(udev, 1772 1780 usb_sndctrlpipe(udev, 0), 1773 1781 USB_REQ_CLEAR_FEATURE, ··· 1779 1789 "wakeup, status %d\n", status); 1780 1790 } 1781 1791 status = 0; 1782 - 1783 - } else if (udev->devnum <= 0) { 1784 - dev_dbg(&udev->dev, "bogus resume!\n"); 1785 - status = -EINVAL; 1786 1792 } 1787 1793 return status; 1788 1794 } ··· 1807 1821 port1, status); 1808 1822 } else { 1809 1823 /* drive resume for at least 20 msec */ 1810 - if (udev) 1811 - dev_dbg(&udev->dev, "usb %sresume\n", 1812 - udev->auto_pm ? "auto-" : ""); 1824 + dev_dbg(&udev->dev, "usb %sresume\n", 1825 + udev->auto_pm ? "auto-" : ""); 1813 1826 msleep(25); 1814 1827 1815 1828 #define LIVE_FLAGS ( USB_PORT_STAT_POWER \ ··· 1836 1851 USB_PORT_FEAT_C_SUSPEND); 1837 1852 /* TRSMRCY = 10 msec */ 1838 1853 msleep(10); 1839 - if (udev) 1840 - status = finish_port_resume(udev); 1854 + status = finish_port_resume(udev); 1841 1855 } 1842 1856 } 1843 1857 if (status < 0) ··· 1866 1882 { 1867 1883 int status; 1868 1884 1869 - /* we change the device's upstream USB link, 1870 - * but root hubs have no upstream USB link. 1871 - */ 1872 - if (udev->parent) { 1873 - // NOTE this fails if parent is also suspended... 1874 - status = hub_port_resume(hdev_to_hub(udev->parent), 1875 - udev->portnum, udev); 1876 - } else { 1877 - dev_dbg(&udev->dev, "usb %sresume\n", 1878 - udev->auto_pm ? "auto-" : ""); 1879 - status = finish_port_resume(udev); 1880 - } 1885 + status = hub_port_resume(hdev_to_hub(udev->parent), 1886 + udev->portnum, udev); 1881 1887 if (status < 0) 1882 1888 dev_dbg(&udev->dev, "can't resume, status %d\n", status); 1883 1889 return status;