summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2011-05-12 17:11:39 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-05-21 12:17:12 -0700
commitb9d320fcb6259baffaeaf93a5fce252cd09333d6 (patch)
treec5372d704719ff2c6f7b8d2b6bb3c04901cde242 /drivers/pci
parentda7822e5ad71ec9b745b412639f1e5e0ba795a20 (diff)
PCI: add rescan to /sys/.../pci_bus/.../
After remove the device from /sys, we have to rescan all or find out the bridge and access /sys../device/rescan there. this patch add /sys/.../pci_bus/.../rescan. So user can rescan more easy. that is more clean and easy to understand. like after remove 0000:c4:00.0, you can rescan 0000:c4 directly. -v2: According to Jesse, use function instead of exposing attr, so could hide #ifdef in header file. also add code to remove rescan file in remove path. -v3: GregKH pointed out that we should use dev_attrs to avoid racing. So add pcibus_attrs and make it to be member of pcibus_attrs. -v4: Change name to pcibus_dev_attrs according to GregKH Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-sysfs.c26
-rw-r--r--drivers/pci/pci.h1
-rw-r--r--drivers/pci/probe.c1
3 files changed, 28 insertions, 0 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index f8deb3e380a2..c690abc0e5b8 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -318,6 +318,25 @@ remove_store(struct device *dev, struct device_attribute *dummy,
count = ret;
return count;
}
+
+static ssize_t
+dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct pci_bus *bus = to_pci_bus(dev);
+
+ if (strict_strtoul(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val) {
+ mutex_lock(&pci_remove_rescan_mutex);
+ pci_rescan_bus(bus);
+ mutex_unlock(&pci_remove_rescan_mutex);
+ }
+ return count;
+}
+
#endif
struct device_attribute pci_dev_attrs[] = {
@@ -347,6 +366,13 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR_NULL,
};
+struct device_attribute pcibus_dev_attrs[] = {
+#ifdef CONFIG_HOTPLUG
+ __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
+#endif
+ __ATTR_NULL,
+};
+
static ssize_t
boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
{
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a6ec200fe5ee..dcf640ad8df6 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -156,6 +156,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
}
extern struct device_attribute pci_dev_attrs[];
+extern struct device_attribute pcibus_dev_attrs[];
extern struct device_attribute dev_attr_cpuaffinity;
extern struct device_attribute dev_attr_cpulistaffinity;
#ifdef CONFIG_HOTPLUG
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 44cbbbaa499d..c471295cd4b9 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -95,6 +95,7 @@ static void release_pcibus_dev(struct device *dev)
static struct class pcibus_class = {
.name = "pci_bus",
.dev_release = &release_pcibus_dev,
+ .dev_attrs = pcibus_dev_attrs,
};
static int __init pcibus_class_init(void)