diff options
Diffstat (limited to 'drivers/pci')
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 36 |
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 | |||
| 247 | static 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 | |||
| 256 | static ssize_t | ||
| 257 | remove_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 | ||
| 248 | struct device_attribute pci_dev_attrs[] = { | 281 | struct 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 | ||
