aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2010-07-19 11:45:34 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-07-30 12:32:08 -0400
commit8633328be242677fdedc42052838dd0608e7f342 (patch)
tree20b16af605298a1d05973d7ec2d0a479412ed3e6
parent2491762cfb475dbdfa3db11ebea6de49f58b7fac (diff)
PCI: Allow read/write access to sysfs I/O port resources
PCI sysfs resource files currently only allow mmap'ing. On x86 this works fine for memory backed BARs, but doesn't work at all for I/O port backed BARs. Add read/write to I/O port PCI sysfs resource files to allow userspace access to these device regions. Acked-by: Chris Wright <chrisw@redhat.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--Documentation/filesystems/sysfs-pci.txt7
-rw-r--r--drivers/pci/pci-sysfs.c68
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
57The read only files are informational, writes to them will be ignored, with 59The read only files are informational, writes to them will be ignored, with
58the exception of the 'rom' file. Writable files can be used to perform 60the exception of the 'rom' file. Writable files can be used to perform
59actions on the device (e.g. changing config space, detaching a device). 61actions on the device (e.g. changing config space, detaching a device).
60mmapable files are available via an mmap of the file at offset 0 and can be 62mmapable files are available via an mmap of the file at offset 0 and can be
61used to do actual device programming from userspace. Note that some platforms 63used to do actual device programming from userspace. Note that some platforms
62don't support mmapping of certain resources, so be sure to check the return 64don't support mmapping of certain resources, so be sure to check the return
63value from any attempted mmap. 65value from any attempted mmap. The most notable of these are I/O port
66resources, which also provide read/write access.
64 67
65The 'enable' file provides a counter that indicates how many times the device 68The 'enable' file provides a counter that indicates how many times the device
66has been enabled. If the 'enable' file currently returns '4', and a '1' is 69has 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
781static ssize_t
782pci_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
829static ssize_t
830pci_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
837static ssize_t
838pci_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);