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.c241
1 files changed, 176 insertions, 65 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 77baff022f71..110022d78689 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -423,7 +423,7 @@ pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
423 * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific 423 * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
424 * callback routine (pci_legacy_read). 424 * callback routine (pci_legacy_read).
425 */ 425 */
426ssize_t 426static ssize_t
427pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, 427pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
428 char *buf, loff_t off, size_t count) 428 char *buf, loff_t off, size_t count)
429{ 429{
@@ -448,7 +448,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
448 * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific 448 * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
449 * callback routine (pci_legacy_write). 449 * callback routine (pci_legacy_write).
450 */ 450 */
451ssize_t 451static ssize_t
452pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, 452pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
453 char *buf, loff_t off, size_t count) 453 char *buf, loff_t off, size_t count)
454{ 454{
@@ -468,11 +468,11 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
468 * @attr: struct bin_attribute for this file 468 * @attr: struct bin_attribute for this file
469 * @vma: struct vm_area_struct passed to mmap 469 * @vma: struct vm_area_struct passed to mmap
470 * 470 *
471 * Uses an arch specific callback, pci_mmap_legacy_page_range, to mmap 471 * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap
472 * legacy memory space (first meg of bus space) into application virtual 472 * legacy memory space (first meg of bus space) into application virtual
473 * memory space. 473 * memory space.
474 */ 474 */
475int 475static int
476pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, 476pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
477 struct vm_area_struct *vma) 477 struct vm_area_struct *vma)
478{ 478{
@@ -480,7 +480,90 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
480 struct device, 480 struct device,
481 kobj)); 481 kobj));
482 482
483 return pci_mmap_legacy_page_range(bus, vma); 483 return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
484}
485
486/**
487 * pci_mmap_legacy_io - map legacy PCI IO into user memory space
488 * @kobj: kobject corresponding to device to be mapped
489 * @attr: struct bin_attribute for this file
490 * @vma: struct vm_area_struct passed to mmap
491 *
492 * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap
493 * legacy IO space (first meg of bus space) into application virtual
494 * memory space. Returns -ENOSYS if the operation isn't supported
495 */
496static int
497pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
498 struct vm_area_struct *vma)
499{
500 struct pci_bus *bus = to_pci_bus(container_of(kobj,
501 struct device,
502 kobj));
503
504 return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
505}
506
507/**
508 * pci_create_legacy_files - create legacy I/O port and memory files
509 * @b: bus to create files under
510 *
511 * Some platforms allow access to legacy I/O port and ISA memory space on
512 * a per-bus basis. This routine creates the files and ties them into
513 * their associated read, write and mmap files from pci-sysfs.c
514 *
515 * On error unwind, but don't propogate the error to the caller
516 * as it is ok to set up the PCI bus without these files.
517 */
518void pci_create_legacy_files(struct pci_bus *b)
519{
520 int error;
521
522 b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2,
523 GFP_ATOMIC);
524 if (!b->legacy_io)
525 goto kzalloc_err;
526
527 b->legacy_io->attr.name = "legacy_io";
528 b->legacy_io->size = 0xffff;
529 b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
530 b->legacy_io->read = pci_read_legacy_io;
531 b->legacy_io->write = pci_write_legacy_io;
532 b->legacy_io->mmap = pci_mmap_legacy_io;
533 error = device_create_bin_file(&b->dev, b->legacy_io);
534 if (error)
535 goto legacy_io_err;
536
537 /* Allocated above after the legacy_io struct */
538 b->legacy_mem = b->legacy_io + 1;
539 b->legacy_mem->attr.name = "legacy_mem";
540 b->legacy_mem->size = 1024*1024;
541 b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
542 b->legacy_mem->mmap = pci_mmap_legacy_mem;
543 error = device_create_bin_file(&b->dev, b->legacy_mem);
544 if (error)
545 goto legacy_mem_err;
546
547 return;
548
549legacy_mem_err:
550 device_remove_bin_file(&b->dev, b->legacy_io);
551legacy_io_err:
552 kfree(b->legacy_io);
553 b->legacy_io = NULL;
554kzalloc_err:
555 printk(KERN_WARNING "pci: warning: could not create legacy I/O port "
556 "and ISA memory resources to sysfs\n");
557 return;
558}
559
560void pci_remove_legacy_files(struct pci_bus *b)
561{
562 if (b->legacy_io) {
563 device_remove_bin_file(&b->dev, b->legacy_io);
564 device_remove_bin_file(&b->dev, b->legacy_mem);
565 kfree(b->legacy_io); /* both are allocated here */
566 }
484} 567}
485#endif /* HAVE_PCI_LEGACY */ 568#endif /* HAVE_PCI_LEGACY */
486 569
@@ -715,7 +798,7 @@ static struct bin_attribute pci_config_attr = {
715 .name = "config", 798 .name = "config",
716 .mode = S_IRUGO | S_IWUSR, 799 .mode = S_IRUGO | S_IWUSR,
717 }, 800 },
718 .size = 256, 801 .size = PCI_CFG_SPACE_SIZE,
719 .read = pci_read_config, 802 .read = pci_read_config,
720 .write = pci_write_config, 803 .write = pci_write_config,
721}; 804};
@@ -725,7 +808,7 @@ static struct bin_attribute pcie_config_attr = {
725 .name = "config", 808 .name = "config",
726 .mode = S_IRUGO | S_IWUSR, 809 .mode = S_IRUGO | S_IWUSR,
727 }, 810 },
728 .size = 4096, 811 .size = PCI_CFG_SPACE_EXP_SIZE,
729 .read = pci_read_config, 812 .read = pci_read_config,
730 .write = pci_write_config, 813 .write = pci_write_config,
731}; 814};
@@ -735,86 +818,103 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
735 return 0; 818 return 0;
736} 819}
737 820
821static int pci_create_capabilities_sysfs(struct pci_dev *dev)
822{
823 int retval;
824 struct bin_attribute *attr;
825
826 /* If the device has VPD, try to expose it in sysfs. */
827 if (dev->vpd) {
828 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
829 if (!attr)
830 return -ENOMEM;
831
832 attr->size = dev->vpd->len;
833 attr->attr.name = "vpd";
834 attr->attr.mode = S_IRUSR | S_IWUSR;
835 attr->read = pci_read_vpd;
836 attr->write = pci_write_vpd;
837 retval = sysfs_create_bin_file(&dev->dev.kobj, attr);
838 if (retval) {
839 kfree(dev->vpd->attr);
840 return retval;
841 }
842 dev->vpd->attr = attr;
843 }
844
845 /* Active State Power Management */
846 pcie_aspm_create_sysfs_dev_files(dev);
847
848 return 0;
849}
850
738int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) 851int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
739{ 852{
740 struct bin_attribute *attr = NULL;
741 int retval; 853 int retval;
854 int rom_size = 0;
855 struct bin_attribute *attr;
742 856
743 if (!sysfs_initialized) 857 if (!sysfs_initialized)
744 return -EACCES; 858 return -EACCES;
745 859
746 if (pdev->cfg_size < 4096) 860 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
747 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); 861 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
748 else 862 else
749 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); 863 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
750 if (retval) 864 if (retval)
751 goto err; 865 goto err;
752 866
753 /* If the device has VPD, try to expose it in sysfs. */
754 if (pdev->vpd) {
755 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
756 if (attr) {
757 pdev->vpd->attr = attr;
758 attr->size = pdev->vpd->len;
759 attr->attr.name = "vpd";
760 attr->attr.mode = S_IRUSR | S_IWUSR;
761 attr->read = pci_read_vpd;
762 attr->write = pci_write_vpd;
763 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
764 if (retval)
765 goto err_vpd;
766 } else {
767 retval = -ENOMEM;
768 goto err_config_file;
769 }
770 }
771
772 retval = pci_create_resource_files(pdev); 867 retval = pci_create_resource_files(pdev);
773 if (retval) 868 if (retval)
774 goto err_vpd_file; 869 goto err_config_file;
870
871 if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
872 rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
873 else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
874 rom_size = 0x20000;
775 875
776 /* If the device has a ROM, try to expose it in sysfs. */ 876 /* If the device has a ROM, try to expose it in sysfs. */
777 if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || 877 if (rom_size) {
778 (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) {
779 attr = kzalloc(sizeof(*attr), GFP_ATOMIC); 878 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
780 if (attr) { 879 if (!attr) {
781 pdev->rom_attr = attr;
782 attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
783 attr->attr.name = "rom";
784 attr->attr.mode = S_IRUSR;
785 attr->read = pci_read_rom;
786 attr->write = pci_write_rom;
787 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
788 if (retval)
789 goto err_rom;
790 } else {
791 retval = -ENOMEM; 880 retval = -ENOMEM;
792 goto err_resource_files; 881 goto err_resource_files;
793 } 882 }
883 attr->size = rom_size;
884 attr->attr.name = "rom";
885 attr->attr.mode = S_IRUSR;
886 attr->read = pci_read_rom;
887 attr->write = pci_write_rom;
888 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
889 if (retval) {
890 kfree(attr);
891 goto err_resource_files;
892 }
893 pdev->rom_attr = attr;
794 } 894 }
895
795 /* add platform-specific attributes */ 896 /* add platform-specific attributes */
796 if (pcibios_add_platform_entries(pdev)) 897 retval = pcibios_add_platform_entries(pdev);
898 if (retval)
797 goto err_rom_file; 899 goto err_rom_file;
798 900
799 pcie_aspm_create_sysfs_dev_files(pdev); 901 /* add sysfs entries for various capabilities */
902 retval = pci_create_capabilities_sysfs(pdev);
903 if (retval)
904 goto err_rom_file;
800 905
801 return 0; 906 return 0;
802 907
803err_rom_file: 908err_rom_file:
804 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) 909 if (rom_size) {
805 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); 910 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
806err_rom: 911 kfree(pdev->rom_attr);
807 kfree(pdev->rom_attr); 912 pdev->rom_attr = NULL;
913 }
808err_resource_files: 914err_resource_files:
809 pci_remove_resource_files(pdev); 915 pci_remove_resource_files(pdev);
810err_vpd_file:
811 if (pdev->vpd) {
812 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
813err_vpd:
814 kfree(pdev->vpd->attr);
815 }
816err_config_file: 916err_config_file:
817 if (pdev->cfg_size < 4096) 917 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
818 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 918 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
819 else 919 else
820 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); 920 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
@@ -822,6 +922,16 @@ err:
822 return retval; 922 return retval;
823} 923}
824 924
925static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
926{
927 if (dev->vpd && dev->vpd->attr) {
928 sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr);
929 kfree(dev->vpd->attr);
930 }
931
932 pcie_aspm_remove_sysfs_dev_files(dev);
933}
934
825/** 935/**
826 * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files 936 * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
827 * @pdev: device whose entries we should free 937 * @pdev: device whose entries we should free
@@ -830,27 +940,28 @@ err:
830 */ 940 */
831void pci_remove_sysfs_dev_files(struct pci_dev *pdev) 941void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
832{ 942{
943 int rom_size = 0;
944
833 if (!sysfs_initialized) 945 if (!sysfs_initialized)
834 return; 946 return;
835 947
836 pcie_aspm_remove_sysfs_dev_files(pdev); 948 pci_remove_capabilities_sysfs(pdev);
837 949
838 if (pdev->vpd) { 950 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
839 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
840 kfree(pdev->vpd->attr);
841 }
842 if (pdev->cfg_size < 4096)
843 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 951 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
844 else 952 else
845 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); 953 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
846 954
847 pci_remove_resource_files(pdev); 955 pci_remove_resource_files(pdev);
848 956
849 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { 957 if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
850 if (pdev->rom_attr) { 958 rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
851 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); 959 else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
852 kfree(pdev->rom_attr); 960 rom_size = 0x20000;
853 } 961
962 if (rom_size && pdev->rom_attr) {
963 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
964 kfree(pdev->rom_attr);
854 } 965 }
855} 966}
856 967