Commit d963f651 authored by Mika Westerberg's avatar Mika Westerberg Committed by Bjorn Helgaas

PCI: Power on bridges before scanning new devices

When a PCI device is removed through sysfs interface, the upstream bridge
(PCIe port) can be runtime suspended if it was the last device on that bus.
Now, if the bridge is in D3 we cannot find devices below the bridge
anymore.  For example following fails to find the removed device again:

  # echo 1 > /sys/bus/pci/devices/0000:00:01.0/0000:01:00.0/remove
  # echo 1 > /sys/bus/pci/devices/0000:00:01.0/rescan

Where 0000:00:01.0 is the bridge device.

In order to be able to rescan devices below the bridge add
pm_runtime_get_sync()/pm_runtime_put() calls to pci_scan_bridge().  This
should keep bridges powered on while their children devices are being
scanned.
Reported-by: default avatarPeter Wu <peter@lekensteyn.nl>
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 9d26d3a8
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/pm_runtime.h>
#include "pci.h" #include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
...@@ -832,6 +833,12 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) ...@@ -832,6 +833,12 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
u8 primary, secondary, subordinate; u8 primary, secondary, subordinate;
int broken = 0; int broken = 0;
/*
* Make sure the bridge is powered on to be able to access config
* space of devices below it.
*/
pm_runtime_get_sync(&dev->dev);
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
primary = buses & 0xFF; primary = buses & 0xFF;
secondary = (buses >> 8) & 0xFF; secondary = (buses >> 8) & 0xFF;
...@@ -1012,6 +1019,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) ...@@ -1012,6 +1019,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
out: out:
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
pm_runtime_put(&dev->dev);
return max; return max;
} }
EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL(pci_scan_bridge);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment