From patchwork Mon Nov 9 22:43:30 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 58867 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nA9MhomI005503 for ; Mon, 9 Nov 2009 22:43:50 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751185AbZKIWnn (ORCPT ); Mon, 9 Nov 2009 17:43:43 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753844AbZKIWnn (ORCPT ); Mon, 9 Nov 2009 17:43:43 -0500 Received: from cavan.codon.org.uk ([93.93.128.6]:49348 "EHLO cavan.codon.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751185AbZKIWnm (ORCPT ); Mon, 9 Nov 2009 17:43:42 -0500 Received: from lan-nat-pool-bos.redhat.com ([66.187.234.200] helo=localhost.localdomain) by cavan.codon.org.uk with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1N7cxa-00013m-Dd; Mon, 09 Nov 2009 22:43:42 +0000 From: Matthew Garrett To: linux-acpi@vger.kernel.org Cc: linux-usb@vger.kernel.org, rjw@sisk.pl, stern@rowland.harvard.edu, Matthew Garrett Subject: [PATCH] usb: Add support for runtime power management of the hcd Date: Mon, 9 Nov 2009 17:43:30 -0500 Message-Id: <1257806610-6570-1-git-send-email-mjg@redhat.com> X-Mailer: git-send-email 1.6.5.2 X-SA-Do-Not-Run: Yes X-SA-Exim-Connect-IP: 66.187.234.200 X-SA-Exim-Mail-From: mjg@redhat.com X-SA-Exim-Scanned: No (on cavan.codon.org.uk); SAEximRunCond expanded to false Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 91f2885..f32e954 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -232,7 +232,7 @@ static int hcd_pci_suspend(struct device *dev) if (retval) return retval; - /* We might already be suspended (runtime PM -- not yet written) */ + /* We might already be suspended */ if (pci_dev->current_state != PCI_D0) return retval; @@ -363,6 +363,32 @@ static int hcd_pci_restore(struct device *dev) return resume_common(dev, true); } +static int hcd_pci_runtime_suspend(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + int retval; + + if (!(hcd->driver->flags & HCD_RUNTIME_PM)) + return -EINVAL; + + retval = hcd_pci_suspend(dev); + if (retval) + return retval; + + retval = hcd_pci_suspend_noirq(dev); + if (retval) + hcd_pci_resume(dev); + + return retval; +} + +static int hcd_pci_runtime_resume(struct device *dev) +{ + hcd_pci_resume_noirq(dev); + return resume_common(dev, false); +} + struct dev_pm_ops usb_hcd_pci_pm_ops = { .suspend = hcd_pci_suspend, .suspend_noirq = hcd_pci_suspend_noirq, @@ -376,6 +402,8 @@ struct dev_pm_ops usb_hcd_pci_pm_ops = { .poweroff_noirq = hcd_pci_suspend_noirq, .restore_noirq = hcd_pci_resume_noirq, .restore = hcd_pci_restore, + .runtime_suspend = hcd_pci_runtime_suspend, + .runtime_resume = hcd_pci_runtime_resume, }; EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 34de475..abd75c0 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -1764,6 +1765,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) if (status == 0) { usb_set_device_state(rhdev, USB_STATE_SUSPENDED); hcd->state = HC_STATE_SUSPENDED; + pm_runtime_put(hcd->self.controller); } else { hcd->state = old_state; dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", @@ -1785,6 +1787,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) if (hcd->state == HC_STATE_RUNNING) return 0; + pm_runtime_get_sync(hcd->self.controller); hcd->state = HC_STATE_RESUMING; status = hcd->driver->bus_resume(hcd); if (status == 0) { @@ -1798,6 +1801,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) hcd->state = old_state; dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", "resume", status); + pm_runtime_put(hcd->self.controller); if (status != -ESHUTDOWN) usb_hc_died(hcd); } @@ -1985,6 +1989,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif + pm_runtime_enable(dev); + pm_runtime_get(dev); + hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; @@ -1996,6 +2003,8 @@ static void hcd_release (struct kref *kref) { struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); + pm_runtime_put_sync(hcd->self.controller); + kfree(hcd); } diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 79782a1..182a8b7 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -171,6 +171,7 @@ struct hc_driver { int flags; #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ #define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */ +#define HCD_RUNTIME_PM 0x0004 /* HC supports handling runtime PM */ #define HCD_USB11 0x0010 /* USB 1.1 */ #define HCD_USB2 0x0020 /* USB 2.0 */ #define HCD_USB3 0x0040 /* USB 3.0 */ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 378861b..5602101 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -370,7 +370,7 @@ static const struct hc_driver ehci_pci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_RUNTIME_PM, /* * basic lifecycle operations diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 5cd0e48..c6e50aa 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -900,7 +900,7 @@ static const struct hc_driver uhci_driver = { /* Generic hardware linkage */ .irq = uhci_irq, - .flags = HCD_USB11, + .flags = HCD_USB11 | HCD_RUNTIME_PM, /* Basic lifecycle operations */ .reset = uhci_init,