Re: Runtime PM for PCI-based USB host controllers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 1 Jun 2010, Matthew Garrett wrote:

> On Tue, Jun 01, 2010 at 10:59:17AM -0400, Alan Stern wrote:
> 
> > Can we rely on the forbid/allow mechanism?  If userspace never allows 
> > runtime suspend for devices like the video controller then there's no 
> > problem.  Conversely, if a PCI device really doesn't have a driver and 
> > isn't used for anything, then by default it should go into a lower 
> > power state if userspace allows this.
> 
> I think that's safe, yes. Other fringe concerns include things like 
> smbus controllers - we typically won't allow a driver to bind to them 
> because they're used by ACPI, so putting the in D3 is also an error. So 
> I think Rafael's right in that we should default to forbid unless a 
> driver knows that it's safe, and let userspace override us.

Therefore the default state for unbound PCI devices should be
runtime-PM-enabled.  Devices will be put in a low-power state if
userspace allows.  Also, the PCI core should make sure that devices are
active when drivers' probe and release methods are called.

If a driver doesn't want to use runtime PM then not doing anything at 
all should leave the device with a positive usage count.  If it does 
want to use runtime PM then a pm_runtime_put_sync() during probe and 
pm_runtime_get_sync() during release will take care of everything.

Something like the patch below, awkward though it is.  Does this look 
reasonable?

Alan Stern



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.

_______________________________________________
linux-pm mailing list
linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/linux-pm


[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux