Skip to content

Commit

Permalink
PCI: change device runtime PM settings for probe and remove
Browse files Browse the repository at this point in the history
This patch (as1388) changes the way the PCI core handles runtime PM
settings when probing or unbinding drivers.  Now the core will make
sure the device is enabled for runtime PM, with a usage count >= 1,
when a driver is probed.  It does the same when calling a driver's
remove method.

If the driver wants to use runtime PM, all it has to do is call
pm_runtime_pu_noidle() near the end of its probe routine (to cancel
the core's usage increment) and pm_runtime_get_noresume() near the
start of its remove routine (to restore the usage count).  It does not
need to mess around with setting the runtime state to enabled,
disabled, active, or suspended.

The patch updates e1000e and r8169, the only PCI drivers that already
use the existing runtime PM interface.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Alan Stern authored and Jesse Barnes committed Jul 30, 2010
1 parent a2dccdb commit f3ec4f8
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 27 deletions.
16 changes: 4 additions & 12 deletions drivers/net/e1000e/netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5721,11 +5721,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,

e1000_print_device_info(adapter);

if (pci_dev_run_wake(pdev)) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
pm_schedule_suspend(&pdev->dev, MSEC_PER_SEC);
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);

return 0;

Expand Down Expand Up @@ -5771,8 +5768,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
bool down = test_bit(__E1000_DOWN, &adapter->state);

pm_runtime_get_sync(&pdev->dev);

/*
* flush_scheduled work may reschedule our watchdog task, so
* explicitly disable watchdog tasks from being rescheduled
Expand All @@ -5797,11 +5792,8 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
clear_bit(__E1000_DOWN, &adapter->state);
unregister_netdev(netdev);

if (pci_dev_run_wake(pdev)) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
}
pm_runtime_put_noidle(&pdev->dev);
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);

/*
* Release control of h/w to f/w. If f/w is AMT enabled, this
Expand Down
16 changes: 4 additions & 12 deletions drivers/net/r8169.c
Original file line number Diff line number Diff line change
Expand Up @@ -3219,11 +3219,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)

device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);

if (pci_dev_run_wake(pdev)) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
pm_runtime_idle(&pdev->dev);
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);

out:
return rc;
Expand All @@ -3246,17 +3243,12 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);

pm_runtime_get_sync(&pdev->dev);

flush_scheduled_work();

unregister_netdev(dev);

if (pci_dev_run_wake(pdev)) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
}
pm_runtime_put_noidle(&pdev->dev);
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);

/* restore original MAC address */
rtl_rar_set(tp, dev->perm_addr);
Expand Down
32 changes: 29 additions & 3 deletions drivers/pci/pci-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,26 @@ 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;
int rc;

/* 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.
*/
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);

rc = ddi->drv->probe(ddi->dev, ddi->id);
if (rc) {
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
}
return rc;
}

static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
Expand Down Expand Up @@ -369,11 +387,19 @@ static int pci_device_remove(struct device * 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 runtime PM settings in local_pci_probe() */
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);

/*
* If the device is still on, set the power state as "unknown",
* since it might change by the next time we load the driver.
Expand Down

0 comments on commit f3ec4f8

Please sign in to comment.