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) {