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.c153
1 files changed, 114 insertions, 39 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index fdefa7dcd156..a1d2e979b17f 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -117,6 +117,7 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
117 const char *buf, size_t count) 117 const char *buf, size_t count)
118{ 118{
119 struct pci_dev *pdev = to_pci_dev(dev); 119 struct pci_dev *pdev = to_pci_dev(dev);
120 int retval = 0;
120 121
121 /* this can crash the machine when done on the "wrong" device */ 122 /* this can crash the machine when done on the "wrong" device */
122 if (!capable(CAP_SYS_ADMIN)) 123 if (!capable(CAP_SYS_ADMIN))
@@ -126,11 +127,53 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
126 pci_disable_device(pdev); 127 pci_disable_device(pdev);
127 128
128 if (*buf == '1') 129 if (*buf == '1')
129 pci_enable_device(pdev); 130 retval = pci_enable_device(pdev);
130 131
132 if (retval)
133 return retval;
131 return count; 134 return count;
132} 135}
133 136
137static ssize_t
138msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
139{
140 struct pci_dev *pdev = to_pci_dev(dev);
141
142 if (!pdev->subordinate)
143 return 0;
144
145 return sprintf (buf, "%u\n",
146 !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
147}
148
149static ssize_t
150msi_bus_store(struct device *dev, struct device_attribute *attr,
151 const char *buf, size_t count)
152{
153 struct pci_dev *pdev = to_pci_dev(dev);
154
155 /* bad things may happen if the no_msi flag is changed
156 * while some drivers are loaded */
157 if (!capable(CAP_SYS_ADMIN))
158 return count;
159
160 if (!pdev->subordinate)
161 return count;
162
163 if (*buf == '0') {
164 pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
165 dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"
166 " bad things could happen.\n");
167 }
168
169 if (*buf == '1') {
170 pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
171 dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
172 " bad things could happen.\n");
173 }
174
175 return count;
176}
134 177
135struct device_attribute pci_dev_attrs[] = { 178struct device_attribute pci_dev_attrs[] = {
136 __ATTR_RO(resource), 179 __ATTR_RO(resource),
@@ -145,6 +188,7 @@ struct device_attribute pci_dev_attrs[] = {
145 __ATTR(enable, 0600, is_enabled_show, is_enabled_store), 188 __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
146 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), 189 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
147 broken_parity_status_show,broken_parity_status_store), 190 broken_parity_status_show,broken_parity_status_store),
191 __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
148 __ATTR_NULL, 192 __ATTR_NULL,
149}; 193};
150 194
@@ -385,15 +429,38 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
385} 429}
386 430
387/** 431/**
432 * pci_remove_resource_files - cleanup resource files
433 * @dev: dev to cleanup
434 *
435 * If we created resource files for @dev, remove them from sysfs and
436 * free their resources.
437 */
438static void
439pci_remove_resource_files(struct pci_dev *pdev)
440{
441 int i;
442
443 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
444 struct bin_attribute *res_attr;
445
446 res_attr = pdev->res_attr[i];
447 if (res_attr) {
448 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
449 kfree(res_attr);
450 }
451 }
452}
453
454/**
388 * pci_create_resource_files - create resource files in sysfs for @dev 455 * pci_create_resource_files - create resource files in sysfs for @dev
389 * @dev: dev in question 456 * @dev: dev in question
390 * 457 *
391 * Walk the resources in @dev creating files for each resource available. 458 * Walk the resources in @dev creating files for each resource available.
392 */ 459 */
393static void 460static int pci_create_resource_files(struct pci_dev *pdev)
394pci_create_resource_files(struct pci_dev *pdev)
395{ 461{
396 int i; 462 int i;
463 int retval;
397 464
398 /* Expose the PCI resources from this device as files */ 465 /* Expose the PCI resources from this device as files */
399 for (i = 0; i < PCI_ROM_RESOURCE; i++) { 466 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
@@ -416,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev)
416 res_attr->size = pci_resource_len(pdev, i); 483 res_attr->size = pci_resource_len(pdev, i);
417 res_attr->mmap = pci_mmap_resource; 484 res_attr->mmap = pci_mmap_resource;
418 res_attr->private = &pdev->resource[i]; 485 res_attr->private = &pdev->resource[i];
419 sysfs_create_bin_file(&pdev->dev.kobj, res_attr); 486 retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
420 } 487 if (retval) {
421 } 488 pci_remove_resource_files(pdev);
422} 489 return retval;
423 490 }
424/** 491 } else {
425 * pci_remove_resource_files - cleanup resource files 492 return -ENOMEM;
426 * @dev: dev to cleanup
427 *
428 * If we created resource files for @dev, remove them from sysfs and
429 * free their resources.
430 */
431static void
432pci_remove_resource_files(struct pci_dev *pdev)
433{
434 int i;
435
436 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
437 struct bin_attribute *res_attr;
438
439 res_attr = pdev->res_attr[i];
440 if (res_attr) {
441 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
442 kfree(res_attr);
443 } 493 }
444 } 494 }
495 return 0;
445} 496}
446#else /* !HAVE_PCI_MMAP */ 497#else /* !HAVE_PCI_MMAP */
447static inline void pci_create_resource_files(struct pci_dev *dev) { return; } 498static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
448static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } 499static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
449#endif /* HAVE_PCI_MMAP */ 500#endif /* HAVE_PCI_MMAP */
450 501
@@ -529,22 +580,27 @@ static struct bin_attribute pcie_config_attr = {
529 .write = pci_write_config, 580 .write = pci_write_config,
530}; 581};
531 582
532int pci_create_sysfs_dev_files (struct pci_dev *pdev) 583int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
533{ 584{
585 struct bin_attribute *rom_attr = NULL;
586 int retval;
587
534 if (!sysfs_initialized) 588 if (!sysfs_initialized)
535 return -EACCES; 589 return -EACCES;
536 590
537 if (pdev->cfg_size < 4096) 591 if (pdev->cfg_size < 4096)
538 sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); 592 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
539 else 593 else
540 sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); 594 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
595 if (retval)
596 goto err;
541 597
542 pci_create_resource_files(pdev); 598 retval = pci_create_resource_files(pdev);
599 if (retval)
600 goto err_bin_file;
543 601
544 /* If the device has a ROM, try to expose it in sysfs. */ 602 /* If the device has a ROM, try to expose it in sysfs. */
545 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { 603 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
546 struct bin_attribute *rom_attr;
547
548 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); 604 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
549 if (rom_attr) { 605 if (rom_attr) {
550 pdev->rom_attr = rom_attr; 606 pdev->rom_attr = rom_attr;
@@ -554,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev)
554 rom_attr->attr.owner = THIS_MODULE; 610 rom_attr->attr.owner = THIS_MODULE;
555 rom_attr->read = pci_read_rom; 611 rom_attr->read = pci_read_rom;
556 rom_attr->write = pci_write_rom; 612 rom_attr->write = pci_write_rom;
557 sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); 613 retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
614 if (retval)
615 goto err_rom;
616 } else {
617 retval = -ENOMEM;
618 goto err_bin_file;
558 } 619 }
559 } 620 }
560 /* add platform-specific attributes */ 621 /* add platform-specific attributes */
561 pcibios_add_platform_entries(pdev); 622 pcibios_add_platform_entries(pdev);
562 623
563 return 0; 624 return 0;
625
626err_rom:
627 kfree(rom_attr);
628err_bin_file:
629 if (pdev->cfg_size < 4096)
630 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
631 else
632 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
633err:
634 return retval;
564} 635}
565 636
566/** 637/**
@@ -589,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
589static int __init pci_sysfs_init(void) 660static int __init pci_sysfs_init(void)
590{ 661{
591 struct pci_dev *pdev = NULL; 662 struct pci_dev *pdev = NULL;
592 663 int retval;
664
593 sysfs_initialized = 1; 665 sysfs_initialized = 1;
594 for_each_pci_dev(pdev) 666 for_each_pci_dev(pdev) {
595 pci_create_sysfs_dev_files(pdev); 667 retval = pci_create_sysfs_dev_files(pdev);
668 if (retval)
669 return retval;
670 }
596 671
597 return 0; 672 return 0;
598} 673}