aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r--drivers/pci/pci-sysfs.c124
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
223static DEFINE_MUTEX(pci_remove_rescan_mutex);
224static 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
242struct bus_attribute pci_bus_attrs[] = {
243 __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
244 __ATTR_NULL
245};
246
247static ssize_t
248dev_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
265static 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
274static ssize_t
275remove_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
222struct device_attribute pci_dev_attrs[] = { 299struct 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
243static ssize_t 324static ssize_t
325boot_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}
333struct device_attribute vga_attr = __ATTR_RO(boot_vga);
334
335static ssize_t
244pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr, 336pci_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 */
594void __weak
595pci_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 */
722static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; } 829int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
723static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } 830void __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
1012err_vga_file:
1013 if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
1014 device_remove_file(&pdev->dev, &vga_attr);
899err_rom_file: 1015err_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);