This patch is mostly cleanup, but it all helps make PM_SUSPEND_DISK
start to behave better.
Please merge.
- Dave
This exports the new usb_set_device_state() routine for the virtual root
hubs, and uses it in OHCI during resume after power-off to replace some
HC-private code doing almost the same thing.
Note that all HCDs will likely need the same kind of suspend-to-disk
support (though it's different when BIOS kicks in). Some systems
even power-off during suspend-to-ram (to save extra power), which is
why OHCI already has this logic!
Related updates:
- Use usb_set_device_state() immediately when an HC dies, making khubd
handle disconnect processing instead of a workqueue. So now drivers
won't self-deadlock in this should-be-rare path, when disconnect()
calls flush_scheduled_work().
- Don't warn about "Unlink after no-IRQ" for the the root hub's status
URB ... like when suspending an HCD that never enumerated a device.
- Minor IRQ handler cleanup, including more accurate tracking of whether
this driver ever returned IRQ_HANDLED (shared IRQs don't count).
Signed-off-by: David Brownell <[EMAIL PROTECTED]>
--- 1.95/drivers/usb/core/hcd.c Mon Jul 12 08:55:12 2004
+++ edited/drivers/usb/core/hcd.c Thu Sep 9 10:59:25 2004
@@ -1263,7 +1263,7 @@
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address().
*/
- if (!hcd->saw_irq) {
+ if (!hcd->saw_irq && hcd->rh_timer.data != (unsigned long) urb) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Different ACPI or APIC settings may help."
"\n");
@@ -1572,13 +1572,12 @@
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
- if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ if (start == USB_STATE_HALT)
return IRQ_NONE;
-
- hcd->saw_irq = 1;
if (hcd->driver->irq (hcd, r) == IRQ_NONE)
return IRQ_NONE;
+ hcd->saw_irq = 1;
if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd);
return IRQ_HANDLED;
@@ -1587,22 +1586,6 @@
/*-------------------------------------------------------------------------*/
-static void hcd_panic (void *_hcd)
-{
- struct usb_hcd *hcd = _hcd;
- struct usb_device *hub = hcd->self.root_hub;
- unsigned i;
-
- /* hc's root hub is removed later removed in hcd->stop() */
- down (&hub->serialize);
- usb_set_device_state(hub, USB_STATE_NOTATTACHED);
- for (i = 0; i < hub->maxchild; i++) {
- if (hub->children [i])
- usb_disconnect (&hub->children [i]);
- }
- up (&hub->serialize);
-}
-
/**
* usb_hc_died - report abnormal shutdown of a host controller (bus glue)
* @hcd: pointer to the HCD representing the controller
@@ -1615,9 +1598,9 @@
{
dev_err (hcd->self.controller, "HC died; cleaning up\n");
- /* clean up old urbs and devices; needs a task context */
- INIT_WORK (&hcd->work, hcd_panic, hcd);
- (void) schedule_work (&hcd->work);
+ /* make khubd clean up old urbs and devices */
+ usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED);
+ mod_timer(&hcd->rh_timer, jiffies);
}
EXPORT_SYMBOL (usb_hc_died);
--- 1.48/drivers/usb/core/hcd.h Sat Aug 21 16:33:26 2004
+++ edited/drivers/usb/core/hcd.h Thu Sep 9 11:09:29 2004
@@ -67,7 +67,6 @@
struct timer_list rh_timer; /* drives root hub */
struct list_head dev_list; /* devices on this bus */
- struct work_struct work;
/*
* hardware info/state
@@ -362,6 +361,9 @@
return usb_register_root_hub (usb_dev, hcd->self.controller);
}
+
+extern void usb_set_device_state(struct usb_device *udev,
+ enum usb_device_state new_state);
/*-------------------------------------------------------------------------*/
--- 1.132/drivers/usb/core/hub.c Wed Sep 8 09:41:15 2004
+++ edited/drivers/usb/core/hub.c Thu Sep 9 11:10:54 2004
@@ -910,7 +910,7 @@
}
/**
- * usb_set_device_state - change a device's current state (usbcore-internal)
+ * usb_set_device_state - change a device's current state (usbcore, hcds)
* @udev: pointer to device whose state should be changed
* @new_state: new state value to be stored
*
@@ -941,6 +941,7 @@
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
}
+EXPORT_SYMBOL(usb_set_device_state);
static void choose_address(struct usb_device *udev)
--- 1.11/drivers/usb/core/usb.h Sat Sep 4 19:52:09 2004
+++ edited/drivers/usb/core/usb.h Thu Sep 9 11:00:10 2004
@@ -22,8 +22,6 @@
unsigned int size);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
-extern void usb_set_device_state(struct usb_device *udev,
- enum usb_device_state new_state);
/* for labeling diagnostics */
extern const char *usbcore_name;
--- 1.68/drivers/usb/host/ohci-hcd.c Thu Sep 2 09:39:09 2004
+++ edited/drivers/usb/host/ohci-hcd.c Thu Sep 9 10:59:25 2004
@@ -726,18 +726,6 @@
#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
-static void mark_children_gone (struct usb_device *dev)
-{
- unsigned i;
-
- for (i = 0; i < dev->maxchild; i++) {
- if (dev->children [i] == 0)
- continue;
- dev->children [i]->state = USB_STATE_NOTATTACHED;
- mark_children_gone (dev->children [i]);
- }
-}
-
static int hc_restart (struct ohci_hcd *ohci)
{
int temp;
@@ -751,7 +739,7 @@
*/
spin_lock_irq(&ohci->lock);
disable (ohci);
- mark_children_gone (ohci->hcd.self.root_hub);
+ usb_set_device_state (ohci->hcd.self.root_hub, USB_STATE_NOTATTACHED);
if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) {