aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-23 01:32:24 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:40 -0400
commit979d5199fee9e80290ddeb532e5993bd15506712 (patch)
tree6987772d41ec540b7e32beaa50c1493a95e3e2c8
parent9293677af3dace2645dec0d0808efa02d36bf47b (diff)
[PATCH] root hub changes (lesser half)
This patch collects various small updates related to root hubs, to shrink later patches which build on them. - For root hub suspend/resume support: * Make the existing usb_hcd_resume_root_hub() routine respect pmcore locking, exporting and using the dpm_runtime_resume() method. * Add a new usb_hcd_suspend_root_hub() to pair with that routine. (Essential to make OHCI autosuspend behave again...) * HC_SUSPENDED by itself only refers to the root hub's downstream ports. So let HCDs see root hub URBs unless the parent device is suspended. - Remove an assertion we no longer need (and now, also don't want). - Generic suspend/resume updates to work better with swsusp. * Ignore the FREEZE vs SUSPEND distinction for hardware; trying to use it breaks the swsusp snapshots it's supposed to help (sigh). * On resume, mark devices as resumed right away, but then do nothing else if the device is marked NOTATTACHED. These changes shouldn't be very noticable by themselves. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/base/power/runtime.c | 1 drivers/usb/core/hcd.c | 64 ++++++++++++++++++++++++++++++++++++++----- drivers/usb/core/hcd.h | 1 drivers/usb/core/hub.c | 45 ++++++++++++++++++++++++------ drivers/usb/core/usb.c | 20 +++++++++---- drivers/usb/core/usb.h | 1 6 files changed, 111 insertions(+), 21 deletions(-)
-rw-r--r--drivers/base/power/runtime.c1
-rw-r--r--drivers/usb/core/hcd.c64
-rw-r--r--drivers/usb/core/hcd.h1
-rw-r--r--drivers/usb/core/hub.c45
-rw-r--r--drivers/usb/core/usb.c20
-rw-r--r--drivers/usb/core/usb.h1
6 files changed, 111 insertions, 21 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index e8f0519f5dfa..adbc3148c039 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev)
36 runtime_resume(dev); 36 runtime_resume(dev);
37 up(&dpm_sem); 37 up(&dpm_sem);
38} 38}
39EXPORT_SYMBOL(dpm_runtime_resume);
39 40
40 41
41/** 42/**
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 375382f9d671..de59bb515315 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1143,10 +1143,20 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
1143 else switch (hcd->state) { 1143 else switch (hcd->state) {
1144 case HC_STATE_RUNNING: 1144 case HC_STATE_RUNNING:
1145 case HC_STATE_RESUMING: 1145 case HC_STATE_RESUMING:
1146doit:
1146 usb_get_dev (urb->dev); 1147 usb_get_dev (urb->dev);
1147 list_add_tail (&urb->urb_list, &ep->urb_list); 1148 list_add_tail (&urb->urb_list, &ep->urb_list);
1148 status = 0; 1149 status = 0;
1149 break; 1150 break;
1151 case HC_STATE_SUSPENDED:
1152 /* HC upstream links (register access, wakeup signaling) can work
1153 * even when the downstream links (and DMA etc) are quiesced; let
1154 * usbcore talk to the root hub.
1155 */
1156 if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
1157 && urb->dev->parent == NULL)
1158 goto doit;
1159 /* FALL THROUGH */
1150 default: 1160 default:
1151 status = -ESHUTDOWN; 1161 status = -ESHUTDOWN;
1152 break; 1162 break;
@@ -1294,12 +1304,6 @@ static int hcd_unlink_urb (struct urb *urb, int status)
1294 goto done; 1304 goto done;
1295 } 1305 }
1296 1306
1297 /* running ~= hc unlink handshake works (irq, timer, etc)
1298 * halted ~= no unlink handshake is needed
1299 * suspended, resuming == should never happen
1300 */
1301 WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
1302
1303 /* insist the urb is still queued */ 1307 /* insist the urb is still queued */
1304 list_for_each(tmp, &ep->urb_list) { 1308 list_for_each(tmp, &ep->urb_list) {
1305 if (tmp == &urb->urb_list) 1309 if (tmp == &urb->urb_list)
@@ -1459,6 +1463,8 @@ static int hcd_hub_resume (struct usb_bus *bus)
1459 hcd = container_of (bus, struct usb_hcd, self); 1463 hcd = container_of (bus, struct usb_hcd, self);
1460 if (!hcd->driver->hub_resume) 1464 if (!hcd->driver->hub_resume)
1461 return -ENOENT; 1465 return -ENOENT;
1466 if (hcd->state == HC_STATE_RUNNING)
1467 return 0;
1462 hcd->state = HC_STATE_RESUMING; 1468 hcd->state = HC_STATE_RESUMING;
1463 status = hcd->driver->hub_resume (hcd); 1469 status = hcd->driver->hub_resume (hcd);
1464 if (status == 0) 1470 if (status == 0)
@@ -1471,6 +1477,50 @@ static int hcd_hub_resume (struct usb_bus *bus)
1471 return status; 1477 return status;
1472} 1478}
1473 1479
1480/*
1481 * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
1482 * @hcd: host controller for this root hub
1483 *
1484 * This call arranges that usb_hcd_resume_root_hub() is safe to call later;
1485 * that the HCD's root hub polling is deactivated; and that the root's hub
1486 * driver is suspended. HCDs may call this to autosuspend when their root
1487 * hub's downstream ports are all inactive: unpowered, disconnected,
1488 * disabled, or suspended.
1489 *
1490 * The HCD will autoresume on device connect change detection (using SRP
1491 * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
1492 * from any ports that are suspended (if that is enabled). In most cases,
1493 * overcurrent signaling (on powered ports) will also start autoresume.
1494 *
1495 * Always called with IRQs blocked.
1496 */
1497void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
1498{
1499 struct urb *urb;
1500
1501 spin_lock (&hcd_root_hub_lock);
1502 usb_suspend_root_hub (hcd->self.root_hub);
1503
1504 /* force status urb to complete/unlink while suspended */
1505 if (hcd->status_urb) {
1506 urb = hcd->status_urb;
1507 urb->status = -ECONNRESET;
1508 urb->hcpriv = NULL;
1509 urb->actual_length = 0;
1510
1511 del_timer (&hcd->rh_timer);
1512 hcd->poll_pending = 0;
1513 hcd->status_urb = NULL;
1514 } else
1515 urb = NULL;
1516 spin_unlock (&hcd_root_hub_lock);
1517 hcd->state = HC_STATE_SUSPENDED;
1518
1519 if (urb)
1520 usb_hcd_giveback_urb (hcd, urb, NULL);
1521}
1522EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
1523
1474/** 1524/**
1475 * usb_hcd_resume_root_hub - called by HCD to resume its root hub 1525 * usb_hcd_resume_root_hub - called by HCD to resume its root hub
1476 * @hcd: host controller for this root hub 1526 * @hcd: host controller for this root hub
@@ -1478,7 +1528,7 @@ static int hcd_hub_resume (struct usb_bus *bus)
1478 * The USB host controller calls this function when its root hub is 1528 * The USB host controller calls this function when its root hub is
1479 * suspended (with the remote wakeup feature enabled) and a remote 1529 * suspended (with the remote wakeup feature enabled) and a remote
1480 * wakeup request is received. It queues a request for khubd to 1530 * wakeup request is received. It queues a request for khubd to
1481 * resume the root hub. 1531 * resume the root hub (that is, manage its downstream ports again).
1482 */ 1532 */
1483void usb_hcd_resume_root_hub (struct usb_hcd *hcd) 1533void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
1484{ 1534{
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 1f1ed6211af8..eb21f13c5c74 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -355,6 +355,7 @@ extern long usb_calc_bus_time (int speed, int is_input,
355 355
356extern struct usb_bus *usb_alloc_bus (struct usb_operations *); 356extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
357 357
358extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
358extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); 359extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
359 360
360extern void usb_set_device_state(struct usb_device *udev, 361extern void usb_set_device_state(struct usb_device *udev,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 660064466791..3c8d8d1f993c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -449,11 +449,18 @@ static void hub_power_on(struct usb_hub *hub)
449 msleep(max(pgood_delay, (unsigned) 100)); 449 msleep(max(pgood_delay, (unsigned) 100));
450} 450}
451 451
452static void hub_quiesce(struct usb_hub *hub) 452static inline void __hub_quiesce(struct usb_hub *hub)
453{ 453{
454 /* stop khubd and related activity */ 454 /* (nonblocking) khubd and related activity won't re-trigger */
455 hub->quiescing = 1; 455 hub->quiescing = 1;
456 hub->activating = 0; 456 hub->activating = 0;
457 hub->resume_root_hub = 0;
458}
459
460static void hub_quiesce(struct usb_hub *hub)
461{
462 /* (blocking) stop khubd and related activity */
463 __hub_quiesce(hub);
457 usb_kill_urb(hub->urb); 464 usb_kill_urb(hub->urb);
458 if (hub->has_indicators) 465 if (hub->has_indicators)
459 cancel_delayed_work(&hub->leds); 466 cancel_delayed_work(&hub->leds);
@@ -467,6 +474,7 @@ static void hub_activate(struct usb_hub *hub)
467 474
468 hub->quiescing = 0; 475 hub->quiescing = 0;
469 hub->activating = 1; 476 hub->activating = 1;
477 hub->resume_root_hub = 0;
470 status = usb_submit_urb(hub->urb, GFP_NOIO); 478 status = usb_submit_urb(hub->urb, GFP_NOIO);
471 if (status < 0) 479 if (status < 0)
472 dev_err(hub->intfdev, "activate --> %d\n", status); 480 dev_err(hub->intfdev, "activate --> %d\n", status);
@@ -1959,6 +1967,18 @@ static int hub_resume(struct usb_interface *intf)
1959 return 0; 1967 return 0;
1960} 1968}
1961 1969
1970void usb_suspend_root_hub(struct usb_device *hdev)
1971{
1972 struct usb_hub *hub = hdev_to_hub(hdev);
1973
1974 /* This also makes any led blinker stop retriggering. We're called
1975 * from irq, so the blinker might still be scheduled. Caller promises
1976 * that the root hub status URB will be canceled.
1977 */
1978 __hub_quiesce(hub);
1979 mark_quiesced(to_usb_interface(hub->intfdev));
1980}
1981
1962void usb_resume_root_hub(struct usb_device *hdev) 1982void usb_resume_root_hub(struct usb_device *hdev)
1963{ 1983{
1964 struct usb_hub *hub = hdev_to_hub(hdev); 1984 struct usb_hub *hub = hdev_to_hub(hdev);
@@ -2616,21 +2636,30 @@ static void hub_events(void)
2616 intf = to_usb_interface(hub->intfdev); 2636 intf = to_usb_interface(hub->intfdev);
2617 hub_dev = &intf->dev; 2637 hub_dev = &intf->dev;
2618 2638
2619 dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", 2639 i = hub->resume_root_hub;
2640
2641 dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n",
2620 hdev->state, hub->descriptor 2642 hdev->state, hub->descriptor
2621 ? hub->descriptor->bNbrPorts 2643 ? hub->descriptor->bNbrPorts
2622 : 0, 2644 : 0,
2623 /* NOTE: expects max 15 ports... */ 2645 /* NOTE: expects max 15 ports... */
2624 (u16) hub->change_bits[0], 2646 (u16) hub->change_bits[0],
2625 (u16) hub->event_bits[0]); 2647 (u16) hub->event_bits[0],
2648 i ? ", resume root" : "");
2626 2649
2627 usb_get_intf(intf); 2650 usb_get_intf(intf);
2628 i = hub->resume_root_hub;
2629 spin_unlock_irq(&hub_event_lock); 2651 spin_unlock_irq(&hub_event_lock);
2630 2652
2631 /* Is this is a root hub wanting to be resumed? */ 2653 /* Is this is a root hub wanting to reactivate the downstream
2632 if (i) 2654 * ports? If so, be sure the interface resumes even if its
2633 usb_resume_device(hdev); 2655 * stub "device" node was never suspended.
2656 */
2657 if (i) {
2658 extern void dpm_runtime_resume(struct device *);
2659
2660 dpm_runtime_resume(&hdev->dev);
2661 dpm_runtime_resume(&intf->dev);
2662 }
2634 2663
2635 /* Lock the device, then check to see if we were 2664 /* Lock the device, then check to see if we were
2636 * disconnected while waiting for the lock to succeed. */ 2665 * disconnected while waiting for the lock to succeed. */
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index e89dbd43e952..2493e7d9f5b3 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1427,6 +1427,7 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
1427 1427
1428 /* USB devices enter SUSPEND state through their hubs, but can be 1428 /* USB devices enter SUSPEND state through their hubs, but can be
1429 * marked for FREEZE as soon as their children are already idled. 1429 * marked for FREEZE as soon as their children are already idled.
1430 * But those semantics are useless, so we equate the two (sigh).
1430 */ 1431 */
1431 if (dev->driver == &usb_generic_driver) { 1432 if (dev->driver == &usb_generic_driver) {
1432 if (dev->power.power_state.event == message.event) 1433 if (dev->power.power_state.event == message.event)
@@ -1435,10 +1436,6 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
1435 status = device_for_each_child(dev, NULL, verify_suspended); 1436 status = device_for_each_child(dev, NULL, verify_suspended);
1436 if (status) 1437 if (status)
1437 return status; 1438 return status;
1438 if (message.event == PM_EVENT_FREEZE) {
1439 dev->power.power_state = message;
1440 return 0;
1441 }
1442 return usb_suspend_device (to_usb_device(dev)); 1439 return usb_suspend_device (to_usb_device(dev));
1443 } 1440 }
1444 1441
@@ -1471,14 +1468,22 @@ static int usb_generic_resume(struct device *dev)
1471{ 1468{
1472 struct usb_interface *intf; 1469 struct usb_interface *intf;
1473 struct usb_driver *driver; 1470 struct usb_driver *driver;
1471 struct usb_device *udev;
1474 int status; 1472 int status;
1475 1473
1476 if (dev->power.power_state.event == PM_EVENT_ON) 1474 if (dev->power.power_state.event == PM_EVENT_ON)
1477 return 0; 1475 return 0;
1478 1476
1477 /* mark things as "on" immediately, no matter what errors crop up */
1478 dev->power.power_state.event = PM_EVENT_ON;
1479
1479 /* devices resume through their hubs */ 1480 /* devices resume through their hubs */
1480 if (dev->driver == &usb_generic_driver) 1481 if (dev->driver == &usb_generic_driver) {
1482 udev = to_usb_device(dev);
1483 if (udev->state == USB_STATE_NOTATTACHED)
1484 return 0;
1481 return usb_resume_device (to_usb_device(dev)); 1485 return usb_resume_device (to_usb_device(dev));
1486 }
1482 1487
1483 if ((dev->driver == NULL) || 1488 if ((dev->driver == NULL) ||
1484 (dev->driver_data == &usb_generic_driver_data)) 1489 (dev->driver_data == &usb_generic_driver_data))
@@ -1487,11 +1492,14 @@ static int usb_generic_resume(struct device *dev)
1487 intf = to_usb_interface(dev); 1492 intf = to_usb_interface(dev);
1488 driver = to_usb_driver(dev->driver); 1493 driver = to_usb_driver(dev->driver);
1489 1494
1495 udev = interface_to_usbdev(intf);
1496 if (udev->state == USB_STATE_NOTATTACHED)
1497 return 0;
1498
1490 /* if driver was suspended, it has a resume method; 1499 /* if driver was suspended, it has a resume method;
1491 * however, sysfs can wrongly mark things as suspended 1500 * however, sysfs can wrongly mark things as suspended
1492 * (on the "no suspend method" FIXME path above) 1501 * (on the "no suspend method" FIXME path above)
1493 */ 1502 */
1494 mark_active(intf);
1495 if (driver->resume) { 1503 if (driver->resume) {
1496 status = driver->resume(intf); 1504 status = driver->resume(intf);
1497 if (status) { 1505 if (status) {
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 3741a990403e..7add46ecc6a2 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -19,6 +19,7 @@ extern void usb_lock_all_devices(void);
19extern void usb_unlock_all_devices(void); 19extern void usb_unlock_all_devices(void);
20 20
21extern void usb_kick_khubd(struct usb_device *dev); 21extern void usb_kick_khubd(struct usb_device *dev);
22extern void usb_suspend_root_hub(struct usb_device *hdev);
22extern void usb_resume_root_hub(struct usb_device *dev); 23extern void usb_resume_root_hub(struct usb_device *dev);
23 24
24extern int usb_hub_init(void); 25extern int usb_hub_init(void);