ChangeSet 1.1123.18.16, 2003/08/13 14:39:23-07:00, david-b@pacbell.net [PATCH] usb hc cleanup-after-death, oops fix Recently we've seen some oopses reported in code that cleaned up HCs after they died ... like pci-pm not letting ohci-hcd suspend until after the hardware was partly disabled, or users removing a Cardbus adapter with ehci-hcd. One root cause was that the cleanup called hcd->stop() too many times. This patch just does the cleanup that's reasonable to do before the (dead) root hub is cleaned up: it disconnects the other devices. And based on a suggestion from Pavel, a diagnostic always appears -- avoiding mystery. drivers/usb/core/hcd.c | 36 ++++++++++++------------------------ 1 files changed, 12 insertions(+), 24 deletions(-) diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Fri Aug 15 10:45:23 2003 +++ b/drivers/usb/core/hcd.c Fri Aug 15 10:45:23 2003 @@ -1494,8 +1494,16 @@ static void hcd_panic (void *_hcd) { - struct usb_hcd *hcd = _hcd; - hcd->driver->stop (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() */ + hub->state = USB_STATE_NOTATTACHED; + for (i = 0; i < hub->maxchild; i++) { + if (hub->children [i]) + usb_disconnect (&hub->children [i]); + } } /** @@ -1508,29 +1516,9 @@ */ void usb_hc_died (struct usb_hcd *hcd) { - struct list_head *devlist, *urblist; - struct hcd_dev *dev; - struct urb *urb; - unsigned long flags; - - /* flag every pending urb as done */ - spin_lock_irqsave (&hcd_data_lock, flags); - list_for_each (devlist, &hcd->dev_list) { - dev = list_entry (devlist, struct hcd_dev, dev_list); - list_for_each (urblist, &dev->urb_list) { - urb = list_entry (urblist, struct urb, urb_list); - dev_dbg (hcd->controller, "shutdown %s urb %p pipe %x, current status %d\n", - hcd->self.bus_name, urb, urb->pipe, urb->status); - if (urb->status == -EINPROGRESS) - urb->status = -ESHUTDOWN; - } - } - urb = (struct urb *) hcd->rh_timer.data; - if (urb) - urb->status = -ESHUTDOWN; - spin_unlock_irqrestore (&hcd_data_lock, flags); + dev_err (hcd->controller, "HC died; cleaning up\n"); - /* hcd->stop() needs a task context */ + /* clean up old urbs and devices; needs a task context */ INIT_WORK (&hcd->work, hcd_panic, hcd); (void) schedule_work (&hcd->work); }