diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 124 |
1 files changed, 120 insertions, 4 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index dfc4e0ddf241..e9a8706a6401 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -219,6 +219,83 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, | |||
219 | return count; | 219 | return count; |
220 | } | 220 | } |
221 | 221 | ||
222 | #ifdef CONFIG_HOTPLUG | ||
223 | static DEFINE_MUTEX(pci_remove_rescan_mutex); | ||
224 | static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, | ||
225 | size_t count) | ||
226 | { | ||
227 | unsigned long val; | ||
228 | struct pci_bus *b = NULL; | ||
229 | |||
230 | if (strict_strtoul(buf, 0, &val) < 0) | ||
231 | return -EINVAL; | ||
232 | |||
233 | if (val) { | ||
234 | mutex_lock(&pci_remove_rescan_mutex); | ||
235 | while ((b = pci_find_next_bus(b)) != NULL) | ||
236 | pci_rescan_bus(b); | ||
237 | mutex_unlock(&pci_remove_rescan_mutex); | ||
238 | } | ||
239 | return count; | ||
240 | } | ||
241 | |||
242 | struct bus_attribute pci_bus_attrs[] = { | ||
243 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store), | ||
244 | __ATTR_NULL | ||
245 | }; | ||
246 | |||
247 | static ssize_t | ||
248 | dev_rescan_store(struct device *dev, struct device_attribute *attr, | ||
249 | const char *buf, size_t count) | ||
250 | { | ||
251 | unsigned long val; | ||
252 | struct pci_dev *pdev = to_pci_dev(dev); | ||
253 | |||
254 | if (strict_strtoul(buf, 0, &val) < 0) | ||
255 | return -EINVAL; | ||
256 | |||
257 | if (val) { | ||
258 | mutex_lock(&pci_remove_rescan_mutex); | ||
259 | pci_rescan_bus(pdev->bus); | ||
260 | mutex_unlock(&pci_remove_rescan_mutex); | ||
261 | } | ||
262 | return count; | ||
263 | } | ||
264 | |||
265 | static void remove_callback(struct device *dev) | ||
266 | { | ||
267 | struct pci_dev *pdev = to_pci_dev(dev); | ||
268 | |||
269 | mutex_lock(&pci_remove_rescan_mutex); | ||
270 | pci_remove_bus_device(pdev); | ||
271 | mutex_unlock(&pci_remove_rescan_mutex); | ||
272 | } | ||
273 | |||
274 | static ssize_t | ||
275 | remove_store(struct device *dev, struct device_attribute *dummy, | ||
276 | const char *buf, size_t count) | ||
277 | { | ||
278 | int ret = 0; | ||
279 | unsigned long val; | ||
280 | struct pci_dev *pdev = to_pci_dev(dev); | ||
281 | |||
282 | if (strict_strtoul(buf, 0, &val) < 0) | ||
283 | return -EINVAL; | ||
284 | |||
285 | if (pci_is_root_bus(pdev->bus)) | ||
286 | return -EBUSY; | ||
287 | |||
288 | /* An attribute cannot be unregistered by one of its own methods, | ||
289 | * so we have to use this roundabout approach. | ||
290 | */ | ||
291 | if (val) | ||
292 | ret = device_schedule_callback(dev, remove_callback); | ||
293 | if (ret) | ||
294 | count = ret; | ||
295 | return count; | ||
296 | } | ||
297 | #endif | ||
298 | |||
222 | struct device_attribute pci_dev_attrs[] = { | 299 | struct device_attribute pci_dev_attrs[] = { |
223 | __ATTR_RO(resource), | 300 | __ATTR_RO(resource), |
224 | __ATTR_RO(vendor), | 301 | __ATTR_RO(vendor), |
@@ -237,10 +314,25 @@ struct device_attribute pci_dev_attrs[] = { | |||
237 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), | 314 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), |
238 | broken_parity_status_show,broken_parity_status_store), | 315 | broken_parity_status_show,broken_parity_status_store), |
239 | __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), | 316 | __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), |
317 | #ifdef CONFIG_HOTPLUG | ||
318 | __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), | ||
319 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), | ||
320 | #endif | ||
240 | __ATTR_NULL, | 321 | __ATTR_NULL, |
241 | }; | 322 | }; |
242 | 323 | ||
243 | static ssize_t | 324 | static ssize_t |
325 | boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
326 | { | ||
327 | struct pci_dev *pdev = to_pci_dev(dev); | ||
328 | |||
329 | return sprintf(buf, "%u\n", | ||
330 | !!(pdev->resource[PCI_ROM_RESOURCE].flags & | ||
331 | IORESOURCE_ROM_SHADOW)); | ||
332 | } | ||
333 | struct device_attribute vga_attr = __ATTR_RO(boot_vga); | ||
334 | |||
335 | static ssize_t | ||
244 | pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr, | 336 | pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr, |
245 | char *buf, loff_t off, size_t count) | 337 | char *buf, loff_t off, size_t count) |
246 | { | 338 | { |
@@ -493,6 +585,19 @@ pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr, | |||
493 | } | 585 | } |
494 | 586 | ||
495 | /** | 587 | /** |
588 | * pci_adjust_legacy_attr - adjustment of legacy file attributes | ||
589 | * @b: bus to create files under | ||
590 | * @mmap_type: I/O port or memory | ||
591 | * | ||
592 | * Stub implementation. Can be overridden by arch if necessary. | ||
593 | */ | ||
594 | void __weak | ||
595 | pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) | ||
596 | { | ||
597 | return; | ||
598 | } | ||
599 | |||
600 | /** | ||
496 | * pci_create_legacy_files - create legacy I/O port and memory files | 601 | * pci_create_legacy_files - create legacy I/O port and memory files |
497 | * @b: bus to create files under | 602 | * @b: bus to create files under |
498 | * | 603 | * |
@@ -518,6 +623,7 @@ void pci_create_legacy_files(struct pci_bus *b) | |||
518 | b->legacy_io->read = pci_read_legacy_io; | 623 | b->legacy_io->read = pci_read_legacy_io; |
519 | b->legacy_io->write = pci_write_legacy_io; | 624 | b->legacy_io->write = pci_write_legacy_io; |
520 | b->legacy_io->mmap = pci_mmap_legacy_io; | 625 | b->legacy_io->mmap = pci_mmap_legacy_io; |
626 | pci_adjust_legacy_attr(b, pci_mmap_io); | ||
521 | error = device_create_bin_file(&b->dev, b->legacy_io); | 627 | error = device_create_bin_file(&b->dev, b->legacy_io); |
522 | if (error) | 628 | if (error) |
523 | goto legacy_io_err; | 629 | goto legacy_io_err; |
@@ -528,6 +634,7 @@ void pci_create_legacy_files(struct pci_bus *b) | |||
528 | b->legacy_mem->size = 1024*1024; | 634 | b->legacy_mem->size = 1024*1024; |
529 | b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; | 635 | b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; |
530 | b->legacy_mem->mmap = pci_mmap_legacy_mem; | 636 | b->legacy_mem->mmap = pci_mmap_legacy_mem; |
637 | pci_adjust_legacy_attr(b, pci_mmap_mem); | ||
531 | error = device_create_bin_file(&b->dev, b->legacy_mem); | 638 | error = device_create_bin_file(&b->dev, b->legacy_mem); |
532 | if (error) | 639 | if (error) |
533 | goto legacy_mem_err; | 640 | goto legacy_mem_err; |
@@ -719,8 +826,8 @@ static int pci_create_resource_files(struct pci_dev *pdev) | |||
719 | return 0; | 826 | return 0; |
720 | } | 827 | } |
721 | #else /* !HAVE_PCI_MMAP */ | 828 | #else /* !HAVE_PCI_MMAP */ |
722 | static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; } | 829 | int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; } |
723 | static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } | 830 | void __weak pci_remove_resource_files(struct pci_dev *dev) { return; } |
724 | #endif /* HAVE_PCI_MMAP */ | 831 | #endif /* HAVE_PCI_MMAP */ |
725 | 832 | ||
726 | /** | 833 | /** |
@@ -884,18 +991,27 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
884 | pdev->rom_attr = attr; | 991 | pdev->rom_attr = attr; |
885 | } | 992 | } |
886 | 993 | ||
994 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { | ||
995 | retval = device_create_file(&pdev->dev, &vga_attr); | ||
996 | if (retval) | ||
997 | goto err_rom_file; | ||
998 | } | ||
999 | |||
887 | /* add platform-specific attributes */ | 1000 | /* add platform-specific attributes */ |
888 | retval = pcibios_add_platform_entries(pdev); | 1001 | retval = pcibios_add_platform_entries(pdev); |
889 | if (retval) | 1002 | if (retval) |
890 | goto err_rom_file; | 1003 | goto err_vga_file; |
891 | 1004 | ||
892 | /* add sysfs entries for various capabilities */ | 1005 | /* add sysfs entries for various capabilities */ |
893 | retval = pci_create_capabilities_sysfs(pdev); | 1006 | retval = pci_create_capabilities_sysfs(pdev); |
894 | if (retval) | 1007 | if (retval) |
895 | goto err_rom_file; | 1008 | goto err_vga_file; |
896 | 1009 | ||
897 | return 0; | 1010 | return 0; |
898 | 1011 | ||
1012 | err_vga_file: | ||
1013 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) | ||
1014 | device_remove_file(&pdev->dev, &vga_attr); | ||
899 | err_rom_file: | 1015 | err_rom_file: |
900 | if (rom_size) { | 1016 | if (rom_size) { |
901 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); | 1017 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); |