PCI: Introduce /sys/bus/pci/rescan
authorAlex Chiang <achiang@hp.com>
Fri, 20 Mar 2009 20:56:31 +0000 (14:56 -0600)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 20 Mar 2009 21:57:58 +0000 (14:57 -0700)
This interface allows the user to force a rescan of all PCI buses
in system, and rediscover devices that have been removed earlier.

pci_bus_attrs implementation from Trent Piepho.

Thanks to Vegard Nossum for discovering locking issues with the
sysfs interface.

Cc: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Documentation/ABI/testing/sysfs-bus-pci
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.h
drivers/pci/probe.c

index d175a2a..e6ad047 100644 (file)
@@ -57,6 +57,15 @@ Description:
                match the driver to the device.  For example:
                # echo "8086 10f5" > /sys/bus/pci/drivers/foo/remove_id
 
+What:          /sys/bus/pci/rescan
+Date:          January 2009
+Contact:       Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+               Writing a non-zero value to this attribute will
+               force a rescan of all PCI buses in the system, and
+               re-discover previously removed devices.
+               Depends on CONFIG_HOTPLUG.
+
 What:          /sys/bus/pci/devices/.../vpd
 Date:          February 2008
 Contact:       Ben Hutchings <bhutchings@solarflare.com>
index 87a5ddb..95d1985 100644 (file)
@@ -1049,6 +1049,7 @@ struct bus_type pci_bus_type = {
        .remove         = pci_device_remove,
        .shutdown       = pci_device_shutdown,
        .dev_attrs      = pci_dev_attrs,
+       .bus_attrs      = pci_bus_attrs,
        .pm             = PCI_PM_OPS_PTR,
 };
 
index ec7a175..be7468a 100644 (file)
@@ -219,6 +219,32 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+#ifdef CONFIG_HOTPLUG
+static DEFINE_MUTEX(pci_remove_rescan_mutex);
+static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
+                               size_t count)
+{
+       unsigned long val;
+       struct pci_bus *b = NULL;
+
+       if (strict_strtoul(buf, 0, &val) < 0)
+               return -EINVAL;
+
+       if (val) {
+               mutex_lock(&pci_remove_rescan_mutex);
+               while ((b = pci_find_next_bus(b)) != NULL)
+                       pci_rescan_bus(b);
+               mutex_unlock(&pci_remove_rescan_mutex);
+       }
+       return count;
+}
+
+struct bus_attribute pci_bus_attrs[] = {
+       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
+       __ATTR_NULL
+};
+#endif
+
 struct device_attribute pci_dev_attrs[] = {
        __ATTR_RO(resource),
        __ATTR_RO(vendor),
index 22dcfdb..45833a5 100644 (file)
@@ -138,6 +138,12 @@ extern int pcie_mch_quirk;
 extern struct device_attribute pci_dev_attrs[];
 extern struct device_attribute dev_attr_cpuaffinity;
 extern struct device_attribute dev_attr_cpulistaffinity;
+#ifdef CONFIG_HOTPLUG
+extern struct bus_attribute pci_bus_attrs[];
+#else
+#define pci_bus_attrs  NULL
+#endif
+
 
 /**
  * pci_match_one_device - Tell if a PCI device structure has a matching
index 60a8e5f..56c71e5 100644 (file)
@@ -1228,13 +1228,13 @@ unsigned int __devinit pci_rescan_bus(struct pci_bus *bus)
 
        max = pci_scan_child_bus(bus);
 
-       up_read(&pci_bus_sem);
+       down_read(&pci_bus_sem);
        list_for_each_entry(dev, &bus->devices, bus_list)
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
                        if (dev->subordinate)
                                pci_bus_size_bridges(dev->subordinate);
-       down_read(&pci_bus_sem);
+       up_read(&pci_bus_sem);
 
        pci_bus_assign_resources(bus);
        pci_enable_bridges(bus);