aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-sysfs.c
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2009-03-20 16:56:36 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-03-20 17:58:48 -0400
commit77c27c7b49d69d45ccb94e481653f024f1ac6650 (patch)
tree8f2e7a6f3971e3630ad1d219bee1c673597158fe /drivers/pci/pci-sysfs.c
parent705b1aaa823e800490f157cd9366ad8cff385f5f (diff)
PCI: Introduce /sys/bus/pci/devices/.../remove
This patch adds an attribute named "remove" to a PCI device's sysfs directory. Writing a non-zero value to this attribute will remove the PCI device and any children of it. Trent Piepho wrote the original implementation and documentation. Thanks to Vegard Nossum for testing under kmemcheck and finding locking issues with the sysfs interface. Cc: Trent Piepho <xyzzy@speakeasy.org> Tested-by: Vegard Nossum <vegard.nossum@gmail.com> Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r--drivers/pci/pci-sysfs.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index be7468a5eb72..e16990ecc024 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -243,6 +243,39 @@ struct bus_attribute pci_bus_attrs[] = {
243 __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store), 243 __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
244 __ATTR_NULL 244 __ATTR_NULL
245}; 245};
246
247static void remove_callback(struct device *dev)
248{
249 struct pci_dev *pdev = to_pci_dev(dev);
250
251 mutex_lock(&pci_remove_rescan_mutex);
252 pci_remove_bus_device(pdev);
253 mutex_unlock(&pci_remove_rescan_mutex);
254}
255
256static ssize_t
257remove_store(struct device *dev, struct device_attribute *dummy,
258 const char *buf, size_t count)
259{
260 int ret = 0;
261 unsigned long val;
262 struct pci_dev *pdev = to_pci_dev(dev);
263
264 if (strict_strtoul(buf, 0, &val) < 0)
265 return -EINVAL;
266
267 if (pci_is_root_bus(pdev->bus))
268 return -EBUSY;
269
270 /* An attribute cannot be unregistered by one of its own methods,
271 * so we have to use this roundabout approach.
272 */
273 if (val)
274 ret = device_schedule_callback(dev, remove_callback);
275 if (ret)
276 count = ret;
277 return count;
278}
246#endif 279#endif
247 280
248struct device_attribute pci_dev_attrs[] = { 281struct device_attribute pci_dev_attrs[] = {
@@ -263,6 +296,9 @@ struct device_attribute pci_dev_attrs[] = {
263 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), 296 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
264 broken_parity_status_show,broken_parity_status_store), 297 broken_parity_status_show,broken_parity_status_store),
265 __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), 298 __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
299#ifdef CONFIG_HOTPLUG
300 __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store),
301#endif
266 __ATTR_NULL, 302 __ATTR_NULL,
267}; 303};
268 304