diff options
| -rw-r--r-- | Documentation/filesystems/sysfs-pci.txt | 7 | ||||
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 68 |
2 files changed, 73 insertions, 2 deletions
diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index 85354b32d731..74eaac26f8b8 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt | |||
| @@ -39,7 +39,7 @@ files, each with their own function. | |||
| 39 | local_cpus nearby CPU mask (cpumask, ro) | 39 | local_cpus nearby CPU mask (cpumask, ro) |
| 40 | remove remove device from kernel's list (ascii, wo) | 40 | remove remove device from kernel's list (ascii, wo) |
| 41 | resource PCI resource host addresses (ascii, ro) | 41 | resource PCI resource host addresses (ascii, ro) |
| 42 | resource0..N PCI resource N, if present (binary, mmap) | 42 | resource0..N PCI resource N, if present (binary, mmap, rw[1]) |
| 43 | resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap) | 43 | resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap) |
| 44 | rom PCI ROM resource, if present (binary, ro) | 44 | rom PCI ROM resource, if present (binary, ro) |
| 45 | subsystem_device PCI subsystem device (ascii, ro) | 45 | subsystem_device PCI subsystem device (ascii, ro) |
| @@ -54,13 +54,16 @@ files, each with their own function. | |||
| 54 | binary - file contains binary data | 54 | binary - file contains binary data |
| 55 | cpumask - file contains a cpumask type | 55 | cpumask - file contains a cpumask type |
| 56 | 56 | ||
| 57 | [1] rw for RESOURCE_IO (I/O port) regions only | ||
| 58 | |||
| 57 | The read only files are informational, writes to them will be ignored, with | 59 | The read only files are informational, writes to them will be ignored, with |
| 58 | the exception of the 'rom' file. Writable files can be used to perform | 60 | the exception of the 'rom' file. Writable files can be used to perform |
| 59 | actions on the device (e.g. changing config space, detaching a device). | 61 | actions on the device (e.g. changing config space, detaching a device). |
| 60 | mmapable files are available via an mmap of the file at offset 0 and can be | 62 | mmapable files are available via an mmap of the file at offset 0 and can be |
| 61 | used to do actual device programming from userspace. Note that some platforms | 63 | used to do actual device programming from userspace. Note that some platforms |
| 62 | don't support mmapping of certain resources, so be sure to check the return | 64 | don't support mmapping of certain resources, so be sure to check the return |
| 63 | value from any attempted mmap. | 65 | value from any attempted mmap. The most notable of these are I/O port |
| 66 | resources, which also provide read/write access. | ||
| 64 | 67 | ||
| 65 | The 'enable' file provides a counter that indicates how many times the device | 68 | The 'enable' file provides a counter that indicates how many times the device |
| 66 | has been enabled. If the 'enable' file currently returns '4', and a '1' is | 69 | has been enabled. If the 'enable' file currently returns '4', and a '1' is |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5935b854917f..f7692dc531e4 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
| @@ -778,6 +778,70 @@ pci_mmap_resource_wc(struct file *filp, struct kobject *kobj, | |||
| 778 | return pci_mmap_resource(kobj, attr, vma, 1); | 778 | return pci_mmap_resource(kobj, attr, vma, 1); |
| 779 | } | 779 | } |
| 780 | 780 | ||
| 781 | static ssize_t | ||
| 782 | pci_resource_io(struct file *filp, struct kobject *kobj, | ||
| 783 | struct bin_attribute *attr, char *buf, | ||
| 784 | loff_t off, size_t count, bool write) | ||
| 785 | { | ||
| 786 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, | ||
| 787 | struct device, kobj)); | ||
| 788 | struct resource *res = attr->private; | ||
| 789 | unsigned long port = off; | ||
| 790 | int i; | ||
| 791 | |||
| 792 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | ||
| 793 | if (res == &pdev->resource[i]) | ||
| 794 | break; | ||
| 795 | if (i >= PCI_ROM_RESOURCE) | ||
| 796 | return -ENODEV; | ||
| 797 | |||
| 798 | port += pci_resource_start(pdev, i); | ||
| 799 | |||
| 800 | if (port > pci_resource_end(pdev, i)) | ||
| 801 | return 0; | ||
| 802 | |||
| 803 | if (port + count - 1 > pci_resource_end(pdev, i)) | ||
| 804 | return -EINVAL; | ||
| 805 | |||
| 806 | switch (count) { | ||
| 807 | case 1: | ||
| 808 | if (write) | ||
| 809 | outb(*(u8 *)buf, port); | ||
| 810 | else | ||
| 811 | *(u8 *)buf = inb(port); | ||
| 812 | return 1; | ||
| 813 | case 2: | ||
| 814 | if (write) | ||
| 815 | outw(*(u16 *)buf, port); | ||
| 816 | else | ||
| 817 | *(u16 *)buf = inw(port); | ||
| 818 | return 2; | ||
| 819 | case 4: | ||
| 820 | if (write) | ||
| 821 | outl(*(u32 *)buf, port); | ||
| 822 | else | ||
| 823 | *(u32 *)buf = inl(port); | ||
| 824 | return 4; | ||
| 825 | } | ||
| 826 | return -EINVAL; | ||
| 827 | } | ||
| 828 | |||
| 829 | static ssize_t | ||
| 830 | pci_read_resource_io(struct file *filp, struct kobject *kobj, | ||
| 831 | struct bin_attribute *attr, char *buf, | ||
| 832 | loff_t off, size_t count) | ||
| 833 | { | ||
| 834 | return pci_resource_io(filp, kobj, attr, buf, off, count, false); | ||
| 835 | } | ||
| 836 | |||
| 837 | static ssize_t | ||
| 838 | pci_write_resource_io(struct file *filp, struct kobject *kobj, | ||
| 839 | struct bin_attribute *attr, char *buf, | ||
| 840 | loff_t off, size_t count) | ||
| 841 | { | ||
| 842 | return pci_resource_io(filp, kobj, attr, buf, off, count, true); | ||
| 843 | } | ||
| 844 | |||
| 781 | /** | 845 | /** |
| 782 | * pci_remove_resource_files - cleanup resource files | 846 | * pci_remove_resource_files - cleanup resource files |
| 783 | * @pdev: dev to cleanup | 847 | * @pdev: dev to cleanup |
| @@ -828,6 +892,10 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) | |||
| 828 | sprintf(res_attr_name, "resource%d", num); | 892 | sprintf(res_attr_name, "resource%d", num); |
| 829 | res_attr->mmap = pci_mmap_resource_uc; | 893 | res_attr->mmap = pci_mmap_resource_uc; |
| 830 | } | 894 | } |
| 895 | if (pci_resource_flags(pdev, num) & IORESOURCE_IO) { | ||
| 896 | res_attr->read = pci_read_resource_io; | ||
| 897 | res_attr->write = pci_write_resource_io; | ||
| 898 | } | ||
| 831 | res_attr->attr.name = res_attr_name; | 899 | res_attr->attr.name = res_attr_name; |
| 832 | res_attr->attr.mode = S_IRUSR | S_IWUSR; | 900 | res_attr->attr.mode = S_IRUSR | S_IWUSR; |
| 833 | res_attr->size = pci_resource_len(pdev, num); | 901 | res_attr->size = pci_resource_len(pdev, num); |
