diff options
| -rw-r--r-- | drivers/pci/pci-driver.c | 67 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 2 | 
2 files changed, 42 insertions, 27 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 24aa44c6ed0..c3088e54fc4 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -256,31 +256,26 @@ struct drv_dev_and_id {  static long local_pci_probe(void *_ddi)  {  	struct drv_dev_and_id *ddi = _ddi; -	struct device *dev = &ddi->dev->dev; -	struct device *parent = dev->parent; +	struct pci_dev *pci_dev = ddi->dev; +	struct pci_driver *pci_drv = ddi->drv; +	struct device *dev = &pci_dev->dev;  	int rc; -	/* The parent bridge must be in active state when probing */ -	if (parent) -		pm_runtime_get_sync(parent); -	/* Unbound PCI devices are always set to disabled and suspended. -	 * During probe, the device is set to enabled and active and the -	 * usage count is incremented.  If the driver supports runtime PM, -	 * it should call pm_runtime_put_noidle() in its probe routine and -	 * pm_runtime_get_noresume() in its remove routine. +	/* +	 * Unbound PCI devices are always put in D0, regardless of +	 * runtime PM status.  During probe, the device is set to +	 * active and the usage count is incremented.  If the driver +	 * supports runtime PM, it should call pm_runtime_put_noidle() +	 * in its probe routine and pm_runtime_get_noresume() in its +	 * remove routine.  	 */ -	pm_runtime_get_noresume(dev); -	pm_runtime_set_active(dev); -	pm_runtime_enable(dev); - -	rc = ddi->drv->probe(ddi->dev, ddi->id); +	pm_runtime_get_sync(dev); +	pci_dev->driver = pci_drv; +	rc = pci_drv->probe(pci_dev, ddi->id);  	if (rc) { -		pm_runtime_disable(dev); -		pm_runtime_set_suspended(dev); -		pm_runtime_put_noidle(dev); +		pci_dev->driver = NULL; +		pm_runtime_put_sync(dev);  	} -	if (parent) -		pm_runtime_put(parent);  	return rc;  } @@ -330,10 +325,8 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)  		id = pci_match_device(drv, pci_dev);  		if (id)  			error = pci_call_probe(drv, pci_dev, id); -		if (error >= 0) { -			pci_dev->driver = drv; +		if (error >= 0)  			error = 0; -		}  	}  	return error;  } @@ -369,9 +362,7 @@ static int pci_device_remove(struct device * dev)  	}  	/* Undo the runtime PM settings in local_pci_probe() */ -	pm_runtime_disable(dev); -	pm_runtime_set_suspended(dev); -	pm_runtime_put_noidle(dev); +	pm_runtime_put_sync(dev);  	/*  	 * If the device is still on, set the power state as "unknown", @@ -994,6 +985,13 @@ static int pci_pm_runtime_suspend(struct device *dev)  	pci_power_t prev = pci_dev->current_state;  	int error; +	/* +	 * If pci_dev->driver is not set (unbound), the device should +	 * always remain in D0 regardless of the runtime PM status +	 */ +	if (!pci_dev->driver) +		return 0; +  	if (!pm || !pm->runtime_suspend)  		return -ENOSYS; @@ -1029,6 +1027,13 @@ static int pci_pm_runtime_resume(struct device *dev)  	struct pci_dev *pci_dev = to_pci_dev(dev);  	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; +	/* +	 * If pci_dev->driver is not set (unbound), the device should +	 * always remain in D0 regardless of the runtime PM status +	 */ +	if (!pci_dev->driver) +		return 0; +  	if (!pm || !pm->runtime_resume)  		return -ENOSYS; @@ -1046,8 +1051,16 @@ static int pci_pm_runtime_resume(struct device *dev)  static int pci_pm_runtime_idle(struct device *dev)  { +	struct pci_dev *pci_dev = to_pci_dev(dev);  	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; +	/* +	 * If pci_dev->driver is not set (unbound), the device should +	 * always remain in D0 regardless of the runtime PM status +	 */ +	if (!pci_dev->driver) +		goto out; +  	if (!pm)  		return -ENOSYS; @@ -1057,8 +1070,8 @@ static int pci_pm_runtime_idle(struct device *dev)  			return ret;  	} +out:  	pm_runtime_suspend(dev); -  	return 0;  } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index adffc6f621e..5b862b1c93c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1910,6 +1910,8 @@ void pci_pm_init(struct pci_dev *dev)  	u16 pmc;  	pm_runtime_forbid(&dev->dev); +	pm_runtime_set_active(&dev->dev); +	pm_runtime_enable(&dev->dev);  	device_enable_async_suspend(&dev->dev);  	dev->wakeup_prepared = false;  |