ChangeSet 1.1123.18.15, 2003/08/13 14:39:09-07:00, david-b@pacbell.net

[PATCH] USB: usb hcd-pci suspend/resume updates

This patch has some updates to the hcd pci power management glue:

  - removes now-obsolete comments (driver model now exists)

  - better state transitions:
      * suspending "dead" controllers needn't oops
      * multi-resume case (pm bug) simplified
      * multi-suspend case likewise (not always a bug)
      * should handle transitions other than D0->D3{hot,cold}

  - prepares for usb remote wake up support, which will be
    wanting the driver model suspend/resume code to be ready.


 drivers/usb/core/hcd-pci.c |   83 +++++++++++++--------------------------------
 drivers/usb/core/hcd.h     |    4 --
 2 files changed, 25 insertions(+), 62 deletions(-)


diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Fri Aug 15 10:45:38 2003
+++ b/drivers/usb/core/hcd-pci.c	Fri Aug 15 10:45:38 2003
@@ -257,33 +257,6 @@
 
 #ifdef	CONFIG_PM
 
-/*
- * Some "sleep" power levels imply updating struct usb_driver
- * to include a callback asking hcds to do their bit by checking
- * if all the drivers can suspend.  Gets involved with remote wakeup.
- *
- * If there are pending urbs, then HCs will need to access memory,
- * causing extra power drain.  New sleep()/wakeup() PM calls might
- * be needed, beyond PCI suspend()/resume().  The root hub timer
- * still be accessing memory though ...
- *
- * FIXME:  USB should have some power budgeting support working with
- * all kinds of hubs.
- *
- * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
- * D1 and D2 states should do something, yes?
- *
- * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
- * for all supported states, so that USB remote wakeup can work for any
- * devices that support it (and are connected via powered hubs).
- *
- * FIXME:  resume doesn't seem to work right any more...
- */
-
-
-// 2.4 kernels have issued concurrent resumes (w/APM)
-// we defend against that error; PCI doesn't yet.
-
 /**
  * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
  * @dev: USB Host Controller being suspended
@@ -294,20 +267,29 @@
 int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
 {
 	struct usb_hcd		*hcd;
-	int			retval;
+	int			retval = 0;
 
 	hcd = pci_get_drvdata(dev);
-	dev_info (hcd->controller, "suspend to state %d\n", state);
-
-	pci_save_state (dev, hcd->pci_state);
-
-	// FIXME for all connected devices, leaf-to-root:
-	// driver->suspend()
-	// proposed "new 2.5 driver model" will automate that
-
-	/* driver may want to disable DMA etc */
-	retval = hcd->driver->suspend (hcd, state);
-	hcd->state = USB_STATE_SUSPENDED;
+	switch (hcd->state) {
+	case USB_STATE_HALT:
+		dev_dbg (hcd->controller, "halted; hcd not suspended\n");
+		break;
+	case USB_STATE_SUSPENDED:
+		dev_dbg (hcd->controller, "suspend D%d --> D%d\n",
+				dev->current_state, state);
+		break;
+	default:
+		dev_dbg (hcd->controller, "suspend to state %d\n", state);
+
+		/* remote wakeup needs hub->suspend() cooperation */
+		// pci_enable_wake (dev, 3, 1);
+
+		pci_save_state (dev, hcd->pci_state);
+
+		/* driver may want to disable DMA etc */
+		retval = hcd->driver->suspend (hcd, state);
+		hcd->state = USB_STATE_SUSPENDED;
+	}
 
  	pci_set_power_state (dev, state);
 	return retval;
@@ -326,39 +308,24 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	dev_info (hcd->controller, "resume\n");
-
-	/* guard against multiple resumes (APM bug?) */
-	atomic_inc (&hcd->resume_count);
-	if (atomic_read (&hcd->resume_count) != 1) {
-		dev_err (hcd->controller, "concurrent PCI resumes\n");
-		retval = 0;
-		goto done;
-	}
-
-	retval = -EBUSY;
 	if (hcd->state != USB_STATE_SUSPENDED) {
 		dev_dbg (hcd->controller, "can't resume, not suspended!\n");
-		goto done;
+		return -EL3HLT;
 	}
 	hcd->state = USB_STATE_RESUMING;
 
 	pci_set_power_state (dev, 0);
 	pci_restore_state (dev, hcd->pci_state);
 
+	/* remote wakeup needs hub->suspend() cooperation */
+	// pci_enable_wake (dev, 3, 0);
+
 	retval = hcd->driver->resume (hcd);
 	if (!HCD_IS_RUNNING (hcd->state)) {
 		dev_dbg (hcd->controller, "resume fail, retval %d\n", retval);
 		usb_hc_died (hcd);
-// FIXME:  recover, reset etc.
-	} else {
-		// FIXME for all connected devices, root-to-leaf:
-		// driver->resume ();
-		// proposed "new 2.5 driver model" will automate that
 	}
 
-done:
-	atomic_dec (&hcd->resume_count);
 	return retval;
 }
 EXPORT_SYMBOL (usb_hcd_pci_resume);
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Fri Aug 15 10:45:38 2003
+++ b/drivers/usb/core/hcd.h	Fri Aug 15 10:45:38 2003
@@ -82,7 +82,6 @@
 #ifdef	CONFIG_PCI
 	int			region;		/* pci region for regs */
 	u32			pci_state [16];	/* for PM state save */
-	atomic_t		resume_count;	/* multiple resumes issue */
 #endif
 
 #define HCD_BUFFER_POOLS	4
@@ -220,11 +219,8 @@
 extern void usb_hcd_pci_remove (struct pci_dev *dev);
 
 #ifdef CONFIG_PM
-// FIXME:  see Documentation/power/pci.txt (2.4.6 and later?)
-// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);
 extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
 extern int usb_hcd_pci_resume (struct pci_dev *dev);
-// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);
 #endif /* CONFIG_PM */
 
 #endif /* CONFIG_PCI */
