diff mbox

Runtime PM for PCI-based USB host controllers

Message ID Pine.LNX.4.44L0.1006011157400.2949-100000@iolanthe.rowland.org (mailing list archive)
State Accepted, archived
Headers show

Commit Message

stern@rowland.harvard.edu June 1, 2010, 5:25 p.m. UTC
None
diff mbox

Patch

Index: usb-2.6/drivers/pci/bus.c
===================================================================
--- usb-2.6.orig/drivers/pci/bus.c
+++ usb-2.6/drivers/pci/bus.c
@@ -15,6 +15,7 @@ 
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include "pci.h"
 
@@ -134,6 +135,9 @@  pci_bus_alloc_resource(struct pci_bus *b
 int pci_bus_add_device(struct pci_dev *dev)
 {
 	int retval;
+
+	pm_runtime_set_active(&dev->dev);
+	pm_runtime_enable(&dev->dev);
 	retval = device_add(&dev->dev);
 	if (retval)
 		return retval;
Index: usb-2.6/drivers/pci/pci-driver.c
===================================================================
--- usb-2.6.orig/drivers/pci/pci-driver.c
+++ usb-2.6/drivers/pci/pci-driver.c
@@ -289,8 +289,23 @@  struct drv_dev_and_id {
 static long local_pci_probe(void *_ddi)
 {
 	struct drv_dev_and_id *ddi = _ddi;
-
-	return ddi->drv->probe(ddi->dev, ddi->id);
+	struct device *dev = &ddi->dev->dev;
+	struct device_driver *driver = dev->driver;
+	int rc;
+
+	dev->driver = NULL;
+	rc = pm_runtime_get_sync(dev);
+	dev->driver = driver;
+	if (rc < 0)
+		return rc;
+
+	rc = ddi->drv->probe(ddi->dev, ddi->id);
+	if (rc) {
+		dev->driver = NULL;
+		pm_runtime_put_sync(dev);
+		dev->driver = driver;
+	}
+	return rc;
 }
 
 static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
@@ -365,15 +380,24 @@  static int pci_device_probe(struct devic
 
 static int pci_device_remove(struct device * dev)
 {
+	struct device_driver *driver = dev->driver;
 	struct pci_dev * pci_dev = to_pci_dev(dev);
 	struct pci_driver * drv = pci_dev->driver;
 
 	if (drv) {
-		if (drv->remove)
+		if (drv->remove) {
+			pm_runtime_get_sync(dev);
 			drv->remove(pci_dev);
+			pm_runtime_put_noidle(dev);
+		}
 		pci_dev->driver = NULL;
 	}
 
+	/* Undo the pm_runtime_get_sync() in local_pci_probe() */
+	dev->driver = NULL;
+	pm_runtime_put_sync(dev);
+	dev->driver = driver;
+
 	/*
 	 * If the device is still on, set the power state as "unknown",
 	 * since it might change by the next time we load the driver.