ChangeSet 1.1587.3.48, 2004/05/11 15:41:37-07:00, [EMAIL PROTECTED]
[PATCH] USB: more functional HCD PCI PM glue
This patch makes the usbcore PCI suspend/resume logic behave
much better. In particular:
- Even HCs without PCI PM support will normally be able
to support global suspend, saving power ... and will
need to resume later. Let them try to suspend; lots
of not-that-old USB controllers don't have PM caps.
- Saner order for the boilerplate PCI stuff. It also
explicitly disables the IRQ and DMA, which aren't
available in D1/D2/D3 states anyway.
- Uses pci_enable_wake() when the root hub supports
remote wakeup. Didn't fully work in one test setup;
that controller's PME# was evidently ignored. (Not
enabled unless CONFIG_USB_SUSPEND.)
It worked for me with brief tests with the current 2.6.6-rc
uhci-hcd with one old UHCI; more extensive ones with various
OHCIs (using patches which I'll post soonish); and not at all
with EHCI (where PM hasn't ever worked).
Those of you who've been having PM problems might find
this helpful as-is, though I think that unless you're
using UHCI you'll also need an HCD patch.
- Dave
drivers/usb/core/hcd-pci.c | 69 ++++++++++++++++++++++++++++++---------------
1 files changed, 47 insertions(+), 22 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 May 14 15:28:52 2004
+++ b/drivers/usb/core/hcd-pci.c Fri May 14 15:28:52 2004
@@ -279,15 +279,18 @@
{
struct usb_hcd *hcd;
int retval = 0;
+ int has_pci_pm;
hcd = pci_get_drvdata(dev);
- dev_dbg (hcd->self.controller, "suspend D%d --> D%d\n",
- dev->current_state, state);
- if (pci_find_capability(dev, PCI_CAP_ID_PM)) {
- dev_dbg(hcd->self.controller, "No PM capability\n");
- return 0;
- }
+ /* even when the PCI layer rejects some of the PCI calls
+ * below, HCs can try global suspend and reduce DMA traffic.
+ * PM-sensitive HCDs may already have done this.
+ */
+ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (has_pci_pm)
+ dev_dbg(hcd->self.controller, "suspend D%d --> D%d\n",
+ dev->current_state, state);
switch (hcd->state) {
case USB_STATE_HALT:
@@ -297,23 +300,32 @@
dev_dbg (hcd->self.controller, "hcd already suspended\n");
break;
default:
- /* 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 */
- hcd->state = USB_STATE_QUIESCING;
retval = hcd->driver->suspend (hcd, state);
if (retval)
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval);
- else
+ else {
hcd->state = HCD_STATE_SUSPENDED;
+ pci_save_state (dev, hcd->pci_state);
+#ifdef CONFIG_USB_SUSPEND
+ pci_enable_wake (dev, state, hcd->remote_wakeup);
+ pci_enable_wake (dev, 4, hcd->remote_wakeup);
+#endif
+ /* no DMA or IRQs except in D0 */
+ pci_disable_device (dev);
+ free_irq (hcd->irq, hcd);
+
+ if (has_pci_pm)
+ retval = pci_set_power_state (dev, state);
+ if (retval < 0) {
+ dev_dbg (&dev->dev,
+ "PCI suspend fail, %d\n",
+ retval);
+ (void) usb_hcd_pci_resume (dev);
+ }
+ }
}
-
- pci_set_power_state (dev, state);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -328,10 +340,13 @@
{
struct usb_hcd *hcd;
int retval;
+ int has_pci_pm;
hcd = pci_get_drvdata(dev);
- dev_dbg (hcd->self.controller, "resume from state D%d\n",
- dev->current_state);
+ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (has_pci_pm)
+ dev_dbg(hcd->self.controller, "resume from state D%d\n",
+ dev->current_state);
if (hcd->state != HCD_STATE_SUSPENDED) {
dev_dbg (hcd->self.controller,
@@ -340,11 +355,21 @@
}
hcd->state = USB_STATE_RESUMING;
- pci_set_power_state (dev, 0);
+ if (has_pci_pm)
+ pci_set_power_state (dev, 0);
+ retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
+ hcd->description, hcd);
+ if (retval < 0) {
+ dev_err (hcd->self.controller,
+ "can't restore IRQ after resume!\n");
+ return retval;
+ }
+ pci_set_master (dev);
pci_restore_state (dev, hcd->pci_state);
-
- /* remote wakeup needs hub->suspend() cooperation */
- // pci_enable_wake (dev, 3, 0);
+#ifdef CONFIG_USB_SUSPEND
+ pci_enable_wake (dev, dev->current_state, 0);
+ pci_enable_wake (dev, 4, 0);
+#endif
retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) {
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id%62&alloc_ida84&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel