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

Reply via email to