diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 112 |
1 files changed, 73 insertions, 39 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 010e01c4bd43..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,8 +127,10 @@ 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 | ||
@@ -426,15 +429,38 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
426 | } | 429 | } |
427 | 430 | ||
428 | /** | 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 | */ | ||
438 | static void | ||
439 | pci_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 | /** | ||
429 | * pci_create_resource_files - create resource files in sysfs for @dev | 455 | * pci_create_resource_files - create resource files in sysfs for @dev |
430 | * @dev: dev in question | 456 | * @dev: dev in question |
431 | * | 457 | * |
432 | * Walk the resources in @dev creating files for each resource available. | 458 | * Walk the resources in @dev creating files for each resource available. |
433 | */ | 459 | */ |
434 | static void | 460 | static int pci_create_resource_files(struct pci_dev *pdev) |
435 | pci_create_resource_files(struct pci_dev *pdev) | ||
436 | { | 461 | { |
437 | int i; | 462 | int i; |
463 | int retval; | ||
438 | 464 | ||
439 | /* Expose the PCI resources from this device as files */ | 465 | /* Expose the PCI resources from this device as files */ |
440 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | 466 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { |
@@ -457,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev) | |||
457 | res_attr->size = pci_resource_len(pdev, i); | 483 | res_attr->size = pci_resource_len(pdev, i); |
458 | res_attr->mmap = pci_mmap_resource; | 484 | res_attr->mmap = pci_mmap_resource; |
459 | res_attr->private = &pdev->resource[i]; | 485 | res_attr->private = &pdev->resource[i]; |
460 | sysfs_create_bin_file(&pdev->dev.kobj, res_attr); | 486 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); |
461 | } | 487 | if (retval) { |
462 | } | 488 | pci_remove_resource_files(pdev); |
463 | } | 489 | return retval; |
464 | 490 | } | |
465 | /** | 491 | } else { |
466 | * pci_remove_resource_files - cleanup resource files | 492 | return -ENOMEM; |
467 | * @dev: dev to cleanup | ||
468 | * | ||
469 | * If we created resource files for @dev, remove them from sysfs and | ||
470 | * free their resources. | ||
471 | */ | ||
472 | static void | ||
473 | pci_remove_resource_files(struct pci_dev *pdev) | ||
474 | { | ||
475 | int i; | ||
476 | |||
477 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | ||
478 | struct bin_attribute *res_attr; | ||
479 | |||
480 | res_attr = pdev->res_attr[i]; | ||
481 | if (res_attr) { | ||
482 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | ||
483 | kfree(res_attr); | ||
484 | } | 493 | } |
485 | } | 494 | } |
495 | return 0; | ||
486 | } | 496 | } |
487 | #else /* !HAVE_PCI_MMAP */ | 497 | #else /* !HAVE_PCI_MMAP */ |
488 | static inline void pci_create_resource_files(struct pci_dev *dev) { return; } | 498 | static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; } |
489 | static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } | 499 | static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } |
490 | #endif /* HAVE_PCI_MMAP */ | 500 | #endif /* HAVE_PCI_MMAP */ |
491 | 501 | ||
@@ -570,22 +580,27 @@ static struct bin_attribute pcie_config_attr = { | |||
570 | .write = pci_write_config, | 580 | .write = pci_write_config, |
571 | }; | 581 | }; |
572 | 582 | ||
573 | int pci_create_sysfs_dev_files (struct pci_dev *pdev) | 583 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) |
574 | { | 584 | { |
585 | struct bin_attribute *rom_attr = NULL; | ||
586 | int retval; | ||
587 | |||
575 | if (!sysfs_initialized) | 588 | if (!sysfs_initialized) |
576 | return -EACCES; | 589 | return -EACCES; |
577 | 590 | ||
578 | if (pdev->cfg_size < 4096) | 591 | if (pdev->cfg_size < 4096) |
579 | sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); | 592 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); |
580 | else | 593 | else |
581 | 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; | ||
582 | 597 | ||
583 | pci_create_resource_files(pdev); | 598 | retval = pci_create_resource_files(pdev); |
599 | if (retval) | ||
600 | goto err_bin_file; | ||
584 | 601 | ||
585 | /* 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. */ |
586 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { | 603 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { |
587 | struct bin_attribute *rom_attr; | ||
588 | |||
589 | rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); | 604 | rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); |
590 | if (rom_attr) { | 605 | if (rom_attr) { |
591 | pdev->rom_attr = rom_attr; | 606 | pdev->rom_attr = rom_attr; |
@@ -595,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
595 | rom_attr->attr.owner = THIS_MODULE; | 610 | rom_attr->attr.owner = THIS_MODULE; |
596 | rom_attr->read = pci_read_rom; | 611 | rom_attr->read = pci_read_rom; |
597 | rom_attr->write = pci_write_rom; | 612 | rom_attr->write = pci_write_rom; |
598 | 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; | ||
599 | } | 619 | } |
600 | } | 620 | } |
601 | /* add platform-specific attributes */ | 621 | /* add platform-specific attributes */ |
602 | pcibios_add_platform_entries(pdev); | 622 | pcibios_add_platform_entries(pdev); |
603 | 623 | ||
604 | return 0; | 624 | return 0; |
625 | |||
626 | err_rom: | ||
627 | kfree(rom_attr); | ||
628 | err_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); | ||
633 | err: | ||
634 | return retval; | ||
605 | } | 635 | } |
606 | 636 | ||
607 | /** | 637 | /** |
@@ -630,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) | |||
630 | static int __init pci_sysfs_init(void) | 660 | static int __init pci_sysfs_init(void) |
631 | { | 661 | { |
632 | struct pci_dev *pdev = NULL; | 662 | struct pci_dev *pdev = NULL; |
633 | 663 | int retval; | |
664 | |||
634 | sysfs_initialized = 1; | 665 | sysfs_initialized = 1; |
635 | for_each_pci_dev(pdev) | 666 | for_each_pci_dev(pdev) { |
636 | pci_create_sysfs_dev_files(pdev); | 667 | retval = pci_create_sysfs_dev_files(pdev); |
668 | if (retval) | ||
669 | return retval; | ||
670 | } | ||
637 | 671 | ||
638 | return 0; | 672 | return 0; |
639 | } | 673 | } |