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.c260
1 files changed, 195 insertions, 65 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 9c718583a237..110022d78689 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -16,6 +16,7 @@
16 16
17 17
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/sched.h>
19#include <linux/pci.h> 20#include <linux/pci.h>
20#include <linux/stat.h> 21#include <linux/stat.h>
21#include <linux/topology.h> 22#include <linux/topology.h>
@@ -422,7 +423,7 @@ pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
422 * 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
423 * callback routine (pci_legacy_read). 424 * callback routine (pci_legacy_read).
424 */ 425 */
425ssize_t 426static ssize_t
426pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, 427pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
427 char *buf, loff_t off, size_t count) 428 char *buf, loff_t off, size_t count)
428{ 429{
@@ -447,7 +448,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
447 * 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
448 * callback routine (pci_legacy_write). 449 * callback routine (pci_legacy_write).
449 */ 450 */
450ssize_t 451static ssize_t
451pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr, 452pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
452 char *buf, loff_t off, size_t count) 453 char *buf, loff_t off, size_t count)
453{ 454{
@@ -467,11 +468,11 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
467 * @attr: struct bin_attribute for this file 468 * @attr: struct bin_attribute for this file
468 * @vma: struct vm_area_struct passed to mmap 469 * @vma: struct vm_area_struct passed to mmap
469 * 470 *
470 * 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
471 * legacy memory space (first meg of bus space) into application virtual 472 * legacy memory space (first meg of bus space) into application virtual
472 * memory space. 473 * memory space.
473 */ 474 */
474int 475static int
475pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, 476pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
476 struct vm_area_struct *vma) 477 struct vm_area_struct *vma)
477{ 478{
@@ -479,11 +480,109 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
479 struct device, 480 struct device,
480 kobj)); 481 kobj));
481 482
482 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 }
483} 567}
484#endif /* HAVE_PCI_LEGACY */ 568#endif /* HAVE_PCI_LEGACY */
485 569
486#ifdef HAVE_PCI_MMAP 570#ifdef HAVE_PCI_MMAP
571
572static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
573{
574 unsigned long nr, start, size;
575
576 nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
577 start = vma->vm_pgoff;
578 size = pci_resource_len(pdev, resno) >> PAGE_SHIFT;
579 if (start < size && size - start >= nr)
580 return 1;
581 WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n",
582 current->comm, start, start+nr, pci_name(pdev), resno, size);
583 return 0;
584}
585
487/** 586/**
488 * pci_mmap_resource - map a PCI resource into user memory space 587 * pci_mmap_resource - map a PCI resource into user memory space
489 * @kobj: kobject for mapping 588 * @kobj: kobject for mapping
@@ -510,6 +609,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
510 if (i >= PCI_ROM_RESOURCE) 609 if (i >= PCI_ROM_RESOURCE)
511 return -ENODEV; 610 return -ENODEV;
512 611
612 if (!pci_mmap_fits(pdev, i, vma))
613 return -EINVAL;
614
513 /* pci_mmap_page_range() expects the same kind of entry as coming 615 /* pci_mmap_page_range() expects the same kind of entry as coming
514 * from /proc/bus/pci/ which is a "user visible" value. If this is 616 * from /proc/bus/pci/ which is a "user visible" value. If this is
515 * different from the resource itself, arch will do necessary fixup. 617 * different from the resource itself, arch will do necessary fixup.
@@ -696,7 +798,7 @@ static struct bin_attribute pci_config_attr = {
696 .name = "config", 798 .name = "config",
697 .mode = S_IRUGO | S_IWUSR, 799 .mode = S_IRUGO | S_IWUSR,
698 }, 800 },
699 .size = 256, 801 .size = PCI_CFG_SPACE_SIZE,
700 .read = pci_read_config, 802 .read = pci_read_config,
701 .write = pci_write_config, 803 .write = pci_write_config,
702}; 804};
@@ -706,7 +808,7 @@ static struct bin_attribute pcie_config_attr = {
706 .name = "config", 808 .name = "config",
707 .mode = S_IRUGO | S_IWUSR, 809 .mode = S_IRUGO | S_IWUSR,
708 }, 810 },
709 .size = 4096, 811 .size = PCI_CFG_SPACE_EXP_SIZE,
710 .read = pci_read_config, 812 .read = pci_read_config,
711 .write = pci_write_config, 813 .write = pci_write_config,
712}; 814};
@@ -716,86 +818,103 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
716 return 0; 818 return 0;
717} 819}
718 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
719int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) 851int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
720{ 852{
721 struct bin_attribute *attr = NULL;
722 int retval; 853 int retval;
854 int rom_size = 0;
855 struct bin_attribute *attr;
723 856
724 if (!sysfs_initialized) 857 if (!sysfs_initialized)
725 return -EACCES; 858 return -EACCES;
726 859
727 if (pdev->cfg_size < 4096) 860 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
728 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); 861 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
729 else 862 else
730 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); 863 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
731 if (retval) 864 if (retval)
732 goto err; 865 goto err;
733 866
734 /* If the device has VPD, try to expose it in sysfs. */
735 if (pdev->vpd) {
736 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
737 if (attr) {
738 pdev->vpd->attr = attr;
739 attr->size = pdev->vpd->len;
740 attr->attr.name = "vpd";
741 attr->attr.mode = S_IRUSR | S_IWUSR;
742 attr->read = pci_read_vpd;
743 attr->write = pci_write_vpd;
744 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
745 if (retval)
746 goto err_vpd;
747 } else {
748 retval = -ENOMEM;
749 goto err_config_file;
750 }
751 }
752
753 retval = pci_create_resource_files(pdev); 867 retval = pci_create_resource_files(pdev);
754 if (retval) 868 if (retval)
755 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;
756 875
757 /* 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. */
758 if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || 877 if (rom_size) {
759 (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) {
760 attr = kzalloc(sizeof(*attr), GFP_ATOMIC); 878 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
761 if (attr) { 879 if (!attr) {
762 pdev->rom_attr = attr;
763 attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
764 attr->attr.name = "rom";
765 attr->attr.mode = S_IRUSR;
766 attr->read = pci_read_rom;
767 attr->write = pci_write_rom;
768 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
769 if (retval)
770 goto err_rom;
771 } else {
772 retval = -ENOMEM; 880 retval = -ENOMEM;
773 goto err_resource_files; 881 goto err_resource_files;
774 } 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;
775 } 894 }
895
776 /* add platform-specific attributes */ 896 /* add platform-specific attributes */
777 if (pcibios_add_platform_entries(pdev)) 897 retval = pcibios_add_platform_entries(pdev);
898 if (retval)
778 goto err_rom_file; 899 goto err_rom_file;
779 900
780 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;
781 905
782 return 0; 906 return 0;
783 907
784err_rom_file: 908err_rom_file:
785 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) 909 if (rom_size) {
786 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); 910 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
787err_rom: 911 kfree(pdev->rom_attr);
788 kfree(pdev->rom_attr); 912 pdev->rom_attr = NULL;
913 }
789err_resource_files: 914err_resource_files:
790 pci_remove_resource_files(pdev); 915 pci_remove_resource_files(pdev);
791err_vpd_file:
792 if (pdev->vpd) {
793 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
794err_vpd:
795 kfree(pdev->vpd->attr);
796 }
797err_config_file: 916err_config_file:
798 if (pdev->cfg_size < 4096) 917 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
799 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 918 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
800 else 919 else
801 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); 920 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
@@ -803,6 +922,16 @@ err:
803 return retval; 922 return retval;
804} 923}
805 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
806/** 935/**
807 * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files 936 * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
808 * @pdev: device whose entries we should free 937 * @pdev: device whose entries we should free
@@ -811,27 +940,28 @@ err:
811 */ 940 */
812void pci_remove_sysfs_dev_files(struct pci_dev *pdev) 941void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
813{ 942{
943 int rom_size = 0;
944
814 if (!sysfs_initialized) 945 if (!sysfs_initialized)
815 return; 946 return;
816 947
817 pcie_aspm_remove_sysfs_dev_files(pdev); 948 pci_remove_capabilities_sysfs(pdev);
818 949
819 if (pdev->vpd) { 950 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
820 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->vpd->attr);
821 kfree(pdev->vpd->attr);
822 }
823 if (pdev->cfg_size < 4096)
824 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 951 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
825 else 952 else
826 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); 953 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
827 954
828 pci_remove_resource_files(pdev); 955 pci_remove_resource_files(pdev);
829 956
830 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { 957 if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
831 if (pdev->rom_attr) { 958 rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
832 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); 959 else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
833 kfree(pdev->rom_attr); 960 rom_size = 0x20000;
834 } 961
962 if (rom_size && pdev->rom_attr) {
963 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
964 kfree(pdev->rom_attr);
835 } 965 }
836} 966}
837 967