diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 114 |
1 files changed, 100 insertions, 14 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8d9d648daeba..271d41cc05ab 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/topology.h> | 21 | #include <linux/topology.h> |
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/capability.h> | 23 | #include <linux/capability.h> |
24 | #include <linux/pci-aspm.h> | ||
24 | #include "pci.h" | 25 | #include "pci.h" |
25 | 26 | ||
26 | static int sysfs_initialized; /* = 0 */ | 27 | static int sysfs_initialized; /* = 0 */ |
@@ -358,6 +359,58 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
358 | return count; | 359 | return count; |
359 | } | 360 | } |
360 | 361 | ||
362 | static ssize_t | ||
363 | pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, | ||
364 | char *buf, loff_t off, size_t count) | ||
365 | { | ||
366 | struct pci_dev *dev = | ||
367 | to_pci_dev(container_of(kobj, struct device, kobj)); | ||
368 | int end; | ||
369 | int ret; | ||
370 | |||
371 | if (off > bin_attr->size) | ||
372 | count = 0; | ||
373 | else if (count > bin_attr->size - off) | ||
374 | count = bin_attr->size - off; | ||
375 | end = off + count; | ||
376 | |||
377 | while (off < end) { | ||
378 | ret = dev->vpd->ops->read(dev, off, end - off, buf); | ||
379 | if (ret < 0) | ||
380 | return ret; | ||
381 | buf += ret; | ||
382 | off += ret; | ||
383 | } | ||
384 | |||
385 | return count; | ||
386 | } | ||
387 | |||
388 | static ssize_t | ||
389 | pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, | ||
390 | char *buf, loff_t off, size_t count) | ||
391 | { | ||
392 | struct pci_dev *dev = | ||
393 | to_pci_dev(container_of(kobj, struct device, kobj)); | ||
394 | int end; | ||
395 | int ret; | ||
396 | |||
397 | if (off > bin_attr->size) | ||
398 | count = 0; | ||
399 | else if (count > bin_attr->size - off) | ||
400 | count = bin_attr->size - off; | ||
401 | end = off + count; | ||
402 | |||
403 | while (off < end) { | ||
404 | ret = dev->vpd->ops->write(dev, off, end - off, buf); | ||
405 | if (ret < 0) | ||
406 | return ret; | ||
407 | buf += ret; | ||
408 | off += ret; | ||
409 | } | ||
410 | |||
411 | return count; | ||
412 | } | ||
413 | |||
361 | #ifdef HAVE_PCI_LEGACY | 414 | #ifdef HAVE_PCI_LEGACY |
362 | /** | 415 | /** |
363 | * pci_read_legacy_io - read byte(s) from legacy I/O port space | 416 | * pci_read_legacy_io - read byte(s) from legacy I/O port space |
@@ -626,7 +679,7 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev) | |||
626 | 679 | ||
627 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | 680 | int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) |
628 | { | 681 | { |
629 | struct bin_attribute *rom_attr = NULL; | 682 | struct bin_attribute *attr = NULL; |
630 | int retval; | 683 | int retval; |
631 | 684 | ||
632 | if (!sysfs_initialized) | 685 | if (!sysfs_initialized) |
@@ -639,22 +692,41 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
639 | if (retval) | 692 | if (retval) |
640 | goto err; | 693 | goto err; |
641 | 694 | ||
695 | /* If the device has VPD, try to expose it in sysfs. */ | ||
696 | if (pdev->vpd) { | ||
697 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); | ||
698 | if (attr) { | ||
699 | pdev->vpd->attr = attr; | ||
700 | attr->size = pdev->vpd->ops->get_size(pdev); | ||
701 | attr->attr.name = "vpd"; | ||
702 | attr->attr.mode = S_IRUGO | S_IWUSR; | ||
703 | attr->read = pci_read_vpd; | ||
704 | attr->write = pci_write_vpd; | ||
705 | retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); | ||
706 | if (retval) | ||
707 | goto err_vpd; | ||
708 | } else { | ||
709 | retval = -ENOMEM; | ||
710 | goto err_config_file; | ||
711 | } | ||
712 | } | ||
713 | |||
642 | retval = pci_create_resource_files(pdev); | 714 | retval = pci_create_resource_files(pdev); |
643 | if (retval) | 715 | if (retval) |
644 | goto err_bin_file; | 716 | goto err_vpd_file; |
645 | 717 | ||
646 | /* If the device has a ROM, try to expose it in sysfs. */ | 718 | /* If the device has a ROM, try to expose it in sysfs. */ |
647 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || | 719 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || |
648 | (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) { | 720 | (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) { |
649 | rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); | 721 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); |
650 | if (rom_attr) { | 722 | if (attr) { |
651 | pdev->rom_attr = rom_attr; | 723 | pdev->rom_attr = attr; |
652 | rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE); | 724 | attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE); |
653 | rom_attr->attr.name = "rom"; | 725 | attr->attr.name = "rom"; |
654 | rom_attr->attr.mode = S_IRUSR; | 726 | attr->attr.mode = S_IRUSR; |
655 | rom_attr->read = pci_read_rom; | 727 | attr->read = pci_read_rom; |
656 | rom_attr->write = pci_write_rom; | 728 | attr->write = pci_write_rom; |
657 | retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); | 729 | retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); |
658 | if (retval) | 730 | if (retval) |
659 | goto err_rom; | 731 | goto err_rom; |
660 | } else { | 732 | } else { |
@@ -666,16 +738,24 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
666 | if (pcibios_add_platform_entries(pdev)) | 738 | if (pcibios_add_platform_entries(pdev)) |
667 | goto err_rom_file; | 739 | goto err_rom_file; |
668 | 740 | ||
741 | pcie_aspm_create_sysfs_dev_files(pdev); | ||
742 | |||
669 | return 0; | 743 | return 0; |
670 | 744 | ||
671 | err_rom_file: | 745 | err_rom_file: |
672 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) | 746 | if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) |
673 | sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr); | 747 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); |
674 | err_rom: | 748 | err_rom: |
675 | kfree(rom_attr); | 749 | kfree(pdev->rom_attr); |
676 | err_resource_files: | 750 | err_resource_files: |
677 | pci_remove_resource_files(pdev); | 751 | pci_remove_resource_files(pdev); |
678 | err_bin_file: | 752 | err_vpd_file: |
753 | if (pdev->vpd) { | ||
754 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr); | ||
755 | err_vpd: | ||
756 | kfree(pdev->vpd->attr); | ||
757 | } | ||
758 | err_config_file: | ||
679 | if (pdev->cfg_size < 4096) | 759 | if (pdev->cfg_size < 4096) |
680 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); | 760 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); |
681 | else | 761 | else |
@@ -695,6 +775,12 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) | |||
695 | if (!sysfs_initialized) | 775 | if (!sysfs_initialized) |
696 | return; | 776 | return; |
697 | 777 | ||
778 | pcie_aspm_remove_sysfs_dev_files(pdev); | ||
779 | |||
780 | if (pdev->vpd) { | ||
781 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr); | ||
782 | kfree(pdev->vpd->attr); | ||
783 | } | ||
698 | if (pdev->cfg_size < 4096) | 784 | if (pdev->cfg_size < 4096) |
699 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); | 785 | sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); |
700 | else | 786 | else |