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.c158
1 files changed, 116 insertions, 42 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index bc405c035ce..a1d2e979b17 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -15,7 +15,6 @@
15 */ 15 */
16 16
17 17
18#include <linux/config.h>
19#include <linux/kernel.h> 18#include <linux/kernel.h>
20#include <linux/pci.h> 19#include <linux/pci.h>
21#include <linux/stat.h> 20#include <linux/stat.h>
@@ -87,7 +86,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
87 char * str = buf; 86 char * str = buf;
88 int i; 87 int i;
89 int max = 7; 88 int max = 7;
90 u64 start, end; 89 resource_size_t start, end;
91 90
92 if (pci_dev->subordinate) 91 if (pci_dev->subordinate)
93 max = DEVICE_COUNT_RESOURCE; 92 max = DEVICE_COUNT_RESOURCE;
@@ -118,6 +117,7 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
118 const char *buf, size_t count) 117 const char *buf, size_t count)
119{ 118{
120 struct pci_dev *pdev = to_pci_dev(dev); 119 struct pci_dev *pdev = to_pci_dev(dev);
120 int retval = 0;
121 121
122 /* this can crash the machine when done on the "wrong" device */ 122 /* this can crash the machine when done on the "wrong" device */
123 if (!capable(CAP_SYS_ADMIN)) 123 if (!capable(CAP_SYS_ADMIN))
@@ -127,11 +127,53 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
127 pci_disable_device(pdev); 127 pci_disable_device(pdev);
128 128
129 if (*buf == '1') 129 if (*buf == '1')
130 pci_enable_device(pdev); 130 retval = pci_enable_device(pdev);
131 131
132 if (retval)
133 return retval;
132 return count; 134 return count;
133} 135}
134 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}
135 177
136struct device_attribute pci_dev_attrs[] = { 178struct device_attribute pci_dev_attrs[] = {
137 __ATTR_RO(resource), 179 __ATTR_RO(resource),
@@ -146,6 +188,7 @@ struct device_attribute pci_dev_attrs[] = {
146 __ATTR(enable, 0600, is_enabled_show, is_enabled_store), 188 __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
147 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), 189 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
148 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),
149 __ATTR_NULL, 192 __ATTR_NULL,
150}; 193};
151 194
@@ -365,7 +408,7 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
365 struct device, kobj)); 408 struct device, kobj));
366 struct resource *res = (struct resource *)attr->private; 409 struct resource *res = (struct resource *)attr->private;
367 enum pci_mmap_state mmap_type; 410 enum pci_mmap_state mmap_type;
368 u64 start, end; 411 resource_size_t start, end;
369 int i; 412 int i;
370 413
371 for (i = 0; i < PCI_ROM_RESOURCE; i++) 414 for (i = 0; i < PCI_ROM_RESOURCE; i++)
@@ -386,15 +429,38 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
386} 429}
387 430
388/** 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/**
389 * pci_create_resource_files - create resource files in sysfs for @dev 455 * pci_create_resource_files - create resource files in sysfs for @dev
390 * @dev: dev in question 456 * @dev: dev in question
391 * 457 *
392 * Walk the resources in @dev creating files for each resource available. 458 * Walk the resources in @dev creating files for each resource available.
393 */ 459 */
394static void 460static int pci_create_resource_files(struct pci_dev *pdev)
395pci_create_resource_files(struct pci_dev *pdev)
396{ 461{
397 int i; 462 int i;
463 int retval;
398 464
399 /* Expose the PCI resources from this device as files */ 465 /* Expose the PCI resources from this device as files */
400 for (i = 0; i < PCI_ROM_RESOURCE; i++) { 466 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
@@ -417,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev)
417 res_attr->size = pci_resource_len(pdev, i); 483 res_attr->size = pci_resource_len(pdev, i);
418 res_attr->mmap = pci_mmap_resource; 484 res_attr->mmap = pci_mmap_resource;
419 res_attr->private = &pdev->resource[i]; 485 res_attr->private = &pdev->resource[i];
420 sysfs_create_bin_file(&pdev->dev.kobj, res_attr); 486 retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
421 } 487 if (retval) {
422 } 488 pci_remove_resource_files(pdev);
423} 489 return retval;
424 490 }
425/** 491 } else {
426 * pci_remove_resource_files - cleanup resource files 492 return -ENOMEM;
427 * @dev: dev to cleanup
428 *
429 * If we created resource files for @dev, remove them from sysfs and
430 * free their resources.
431 */
432static void
433pci_remove_resource_files(struct pci_dev *pdev)
434{
435 int i;
436
437 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
438 struct bin_attribute *res_attr;
439
440 res_attr = pdev->res_attr[i];
441 if (res_attr) {
442 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
443 kfree(res_attr);
444 } 493 }
445 } 494 }
495 return 0;
446} 496}
447#else /* !HAVE_PCI_MMAP */ 497#else /* !HAVE_PCI_MMAP */
448static inline void pci_create_resource_files(struct pci_dev *dev) { return; } 498static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
449static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } 499static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
450#endif /* HAVE_PCI_MMAP */ 500#endif /* HAVE_PCI_MMAP */
451 501
@@ -530,22 +580,27 @@ static struct bin_attribute pcie_config_attr = {
530 .write = pci_write_config, 580 .write = pci_write_config,
531}; 581};
532 582
533int pci_create_sysfs_dev_files (struct pci_dev *pdev) 583int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
534{ 584{
585 struct bin_attribute *rom_attr = NULL;
586 int retval;
587
535 if (!sysfs_initialized) 588 if (!sysfs_initialized)
536 return -EACCES; 589 return -EACCES;
537 590
538 if (pdev->cfg_size < 4096) 591 if (pdev->cfg_size < 4096)
539 sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); 592 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
540 else 593 else
541 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;
542 597
543 pci_create_resource_files(pdev); 598 retval = pci_create_resource_files(pdev);
599 if (retval)
600 goto err_bin_file;
544 601
545 /* 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. */
546 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { 603 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
547 struct bin_attribute *rom_attr;
548
549 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); 604 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
550 if (rom_attr) { 605 if (rom_attr) {
551 pdev->rom_attr = rom_attr; 606 pdev->rom_attr = rom_attr;
@@ -555,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev)
555 rom_attr->attr.owner = THIS_MODULE; 610 rom_attr->attr.owner = THIS_MODULE;
556 rom_attr->read = pci_read_rom; 611 rom_attr->read = pci_read_rom;
557 rom_attr->write = pci_write_rom; 612 rom_attr->write = pci_write_rom;
558 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;
559 } 619 }
560 } 620 }
561 /* add platform-specific attributes */ 621 /* add platform-specific attributes */
562 pcibios_add_platform_entries(pdev); 622 pcibios_add_platform_entries(pdev);
563 623
564 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;
565} 635}
566 636
567/** 637/**
@@ -590,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
590static int __init pci_sysfs_init(void) 660static int __init pci_sysfs_init(void)
591{ 661{
592 struct pci_dev *pdev = NULL; 662 struct pci_dev *pdev = NULL;
593 663 int retval;
664
594 sysfs_initialized = 1; 665 sysfs_initialized = 1;
595 for_each_pci_dev(pdev) 666 for_each_pci_dev(pdev) {
596 pci_create_sysfs_dev_files(pdev); 667 retval = pci_create_sysfs_dev_files(pdev);
668 if (retval)
669 return retval;
670 }
597 671
598 return 0; 672 return 0;
599} 673}