export PCI resources in sysfs
Subsystems (2)
PATCH 1/1 export PCI resources in sysfs
This patch sits on top of the last one that added mmap support to struct bin_attribute. It exports PCI resources from each device as a file in the device's sysfs directory as resourceN where N is the resource number. The file is mmapable so that userspace can do register reads and writes.
drivers/pci/pci-sysfs.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 2 files changed, 73 insertions(+)
Thanks,
Jesse
===== drivers/pci/pci-sysfs.c 1.13 vs edited =====
drivers/pci/pci-sysfs.c +72 -0
@@ -20,6 +20,7 @@#include <linux/pci.h> #include <linux/stat.h> #include <linux/topology.h> +#include <linux/mm.h> #include "pci.h"
@@ -178,6 +179,32 @@return count; } +#ifdef HAVE_PCI_MMAP +/** +* pci_mmap_resource - map a PCI resource into user memory space +* @kobj: kobject for mapping +* @attr: struct bin_attribute for the file being mapped +* @vma: struct vm_area_struct passed into the mmap +* +* Use the regular PCI mapping routines to map a PCI resource into userspace. +* FIXME: write combining? maybe automatic for prefetchable regions? +*/ +static int +pci_mmap_resource (struct kobject *kobj,struct bin_attribute *attr, +struct vm_area_struct *vma) +{ +struct pci_dev *pdev =to_pci_dev (container_of (kobj, + struct device, kobj)); +struct resource *res = (struct resource *)attr->private; +enum pci_mmap_state mmap_type; + + vma->vm_pgoff += res->start >>PAGE_SHIFT ; + mmap_type = res->flags &IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; + +return pci_mmap_page_range (pdev, vma, mmap_type,0 ); +} +#endif /* HAVE_PCI_MMAP */ +/** * pci_write_rom - used to enable access to the PCI ROM display * @kobj: kernel object handle
@@ -261,6 +288,10 @@int pci_create_sysfs_dev_files (struct pci_dev *pdev) { +#ifdef HAVE_PCI_MMAP +int i; +#endif +if (!sysfs_initialized)return -EACCES ;
@@ -269,6 +300,31 @@else sysfs_create_bin_file (&pdev->dev.kobj, &pcie_config_attr); +#ifdef HAVE_PCI_MMAP +/* Expose the PCI resources from this device as files */ +for (i =0 ; i <PCI_ROM_RESOURCE ; i++) { +struct bin_attribute *res_attr; + +/* skip empty resources */ +if (!pci_resource_len (pdev, i)) +continue ; + + res_attr =kmalloc (sizeof (*res_attr) +10 ,GFP_ATOMIC ); +if (res_attr) { + pdev->res_attr[i] = res_attr; +/* Allocated above after the res_attr struct */ + res_attr->attr.name = (char *)(res_attr +1 ); +sprintf (res_attr->attr.name,"resource%d" , i); + res_attr->size =pci_resource_len (pdev, i); + res_attr->attr.mode =S_IRUSR |S_IWUSR ; + res_attr->attr.owner =THIS_MODULE ; + res_attr->mmap = pci_mmap_resource; + res_attr->private = &pdev->resource[i]; +sysfs_create_bin_file (&pdev->dev.kobj, res_attr); + } + } +#endif /* HAVE_PCI_MMAP */ +/* If the device has a ROM, try to expose it in sysfs. */ if (pci_resource_len (pdev,PCI_ROM_RESOURCE )) {struct bin_attribute *rom_attr;
@@ -299,10 +355,26 @@*/ void pci_remove_sysfs_dev_files (struct pci_dev *pdev) { +#ifdef HAVE_PCI_MMAP +int i; +#endif +if (pdev->cfg_size <4096 )sysfs_remove_bin_file (&pdev->dev.kobj, &pci_config_attr);else sysfs_remove_bin_file (&pdev->dev.kobj, &pcie_config_attr); + +#ifdef HAVE_PCI_MMAP +for (i =0 ; i <PCI_ROM_RESOURCE ; i++) { +struct bin_attribute *res_attr; + + res_attr = pdev->res_attr[i]; +if (res_attr) { +sysfs_remove_bin_file (&pdev->dev.kobj, res_attr); +kfree (res_attr); + } + } +#endif /* HAVE_PCI_MMAP */ if (pci_resource_len (pdev,PCI_ROM_RESOURCE )) {if (pdev->rom_attr) {
===== include/linux/pci.h 1.142 vs edited =====
include/linux/pci.h +1 -0
@@ -539,6 +539,7 @@u32 saved_config_space[16 ];/* config space saved at suspend time */ struct bin_attribute *rom_attr;/* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled;/* has display of the rom attribute been enabled? */ +struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE ];/* sysfs file for resources */ #ifdef CONFIG_PCI_NAMES #define PCI_NAME_SIZE 96#define PCI_NAME_HALF __stringify(43)/* less than half to handle slop */
Quoted 27 lines · Jesse Barnes
int
pci_create_sysfs_dev_files(structpci_dev*pdev) {drivers/pci/pci-sysfs.c +18
-0+#ifdef HAVE_PCI_MMAP +int i; +#endif +if (!sysfs_initialized)return -EACCES ;@@ -269,6 +300,31 @@else sysfs_create_bin_file (&pdev->dev.kobj, &pcie_config_attr); +#ifdef HAVE_PCI_MMAP +/* Expose the PCI resources from this device as files */ +for (i =0 ; i <PCI_ROM_RESOURCE ; i++) { +struct bin_attribute *res_attr; + +/* skip empty resources */ +if (!pci_resource_len (pdev, i)) +continue ; + + res_attr =kmalloc (sizeof (*res_attr) +10 ,GFP_ATOMIC ); +if (res_attr) { + pdev->res_attr[i] = res_attr; +/* Allocated above after the res_attr struct */ + res_attr->attr.name = (char *)(res_attr +1 );
drivers/pci/pci-sysfs.c line 326
Quoted 10 lines
drivers/pci/pci-sysfs.c +10
-0+sprintf (res_attr->attr.name,"resource%d" , i); + res_attr->size =pci_resource_len (pdev, i); + res_attr->attr.mode =S_IRUSR |S_IWUSR ; + res_attr->attr.owner =THIS_MODULE ; + res_attr->mmap = pci_mmap_resource; + res_attr->private = &pdev->resource[i]; + sysfs_create_bin_file(&pdev->dev.kobj, res_attr); + } + } +#endif /* HAVE_PCI_MMAP */
How about wrapping these two #ifdef blocks into one function, and moving it up in the file under the other #ifdef. Do that for the other cleanup function, and it will drop a bunch of #ifdefs.
thanks,
greg k-h
Quoted 34 lines · Greg KH
Quoted 33 lines · Jesse Barnes
int
pci_create_sysfs_dev_files(structpci_dev*pdev) {drivers/pci/pci-sysfs.c +24
-0+#ifdef HAVE_PCI_MMAP +int i; +#endif +if (!sysfs_initialized)return -EACCES ;@@ -269,6 +300,31 @@else sysfs_create_bin_file (&pdev->dev.kobj, &pcie_config_attr); +#ifdef HAVE_PCI_MMAP +/* Expose the PCI resources from this device as files */ +for (i =0 ; i <PCI_ROM_RESOURCE ; i++) { +struct bin_attribute *res_attr; + +/* skip empty resources */ +if (!pci_resource_len (pdev, i)) +continue ; + + res_attr =kmalloc (sizeof (*res_attr) +10 ,GFP_ATOMIC ); +if (res_attr) { + pdev->res_attr[i] = res_attr; +/* Allocated above after the res_attr struct */ + res_attr->attr.name = (char *)(res_attr +1 ); +sprintf (res_attr->attr.name,"resource%d" , i); + res_attr->size =pci_resource_len (pdev, i); + res_attr->attr.mode =S_IRUSR |S_IWUSR ; + res_attr->attr.owner =THIS_MODULE ; + res_attr->mmap = pci_mmap_resource; + res_attr->private = &pdev->resource[i];
Quoted 8 lines
drivers/pci/pci-sysfs.c line 326
Quoted 4 lines
drivers/pci/pci-sysfs.c +4
-0+ sysfs_create_bin_file(&pdev->dev.kobj, res_attr); + } + } +#endif /* HAVE_PCI_MMAP */ How about wrapping these two #ifdef blocks into one function, and moving it up in the file under the other #ifdef. Do that for the other cleanup function, and it will drop a bunch of #ifdefs.
Yeah, that sounds good. I really don't like adding these ifdefs, and limiting their scope to a function somewhere up above would be nicer. I'll do that and respin.
Thanks,
Jesse
Quoted 7 lines · Jesse Barnes
Quoted 3 lines
How about wrapping these two #ifdef blocks into one function, and moving it up in the file under the other #ifdef. Do that for the other cleanup function, and it will drop a bunch of #ifdefs.
Yeah, that sounds good. I really don't like adding these ifdefs, and limiting their scope to a function somewhere up above would be nicer. I'll do that and respin.
Ok, here you go.
This patch exports PCI resources to userspace in the corresponding sysfs device directory. It depends on the platform HAVE_PCI_MMAP code, and is #ifdef'd accordingly. I've also added documentation describing the sysfs PCI device file layout.
Thanks,
Jesse
===== drivers/pci/pci-sysfs.c 1.13 vs edited =====
drivers/pci/pci-sysfs.c +92 -0
@@ -20,6 +20,7 @@#include <linux/pci.h> #include <linux/stat.h> #include <linux/topology.h> +#include <linux/mm.h> #include "pci.h"
@@ -178,6 +179,93 @@return count; } +#ifdef HAVE_PCI_MMAP +/** +* pci_mmap_resource - map a PCI resource into user memory space +* @kobj: kobject for mapping +* @attr: struct bin_attribute for the file being mapped +* @vma: struct vm_area_struct passed into the mmap +* +* Use the regular PCI mapping routines to map a PCI resource into userspace. +* FIXME: write combining? maybe automatic for prefetchable regions? +*/ +static int +pci_mmap_resource (struct kobject *kobj,struct bin_attribute *attr, +struct vm_area_struct *vma) +{ +struct pci_dev *pdev =to_pci_dev (container_of (kobj, + struct device, kobj)); +struct resource *res = (struct resource *)attr->private; +enum pci_mmap_state mmap_type; + + vma->vm_pgoff += res->start >>PAGE_SHIFT ; + mmap_type = res->flags &IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; + +return pci_mmap_page_range (pdev, vma, mmap_type,0 ); +} + +/** +* pci_create_resource_files - create resource files in sysfs for @dev +* @dev: dev in question +* +* Walk the resources in @dev creating files for each resource available. +*/ +static void +pci_create_resource_files (struct pci_dev *pdev) +{ +int i; + +/* Expose the PCI resources from this device as files */ +for (i =0 ; i <PCI_ROM_RESOURCE ; i++) { +struct bin_attribute *res_attr; + +/* skip empty resources */ +if (!pci_resource_len (pdev, i)) +continue ; + + res_attr =kmalloc (sizeof (*res_attr) +10 ,GFP_ATOMIC ); +if (res_attr) { + pdev->res_attr[i] = res_attr; +/* Allocated above after the res_attr struct */ + res_attr->attr.name = (char *)(res_attr +1 ); +sprintf (res_attr->attr.name,"resource%d" , i); + res_attr->size =pci_resource_len (pdev, i); + res_attr->attr.mode =S_IRUSR |S_IWUSR ; + res_attr->attr.owner =THIS_MODULE ; + res_attr->mmap = pci_mmap_resource; + res_attr->private = &pdev->resource[i]; +sysfs_create_bin_file (&pdev->dev.kobj, res_attr); + } + } +} + +/** +* pci_remove_resource_files - cleanup resource files +* @dev: dev to cleanup +* +* If we created resource files for @dev, remove them from sysfs and +* free their resources. +*/ +static void +pci_remove_resource_files (struct pci_dev *pdev) +{ +int i; + +for (i =0 ; i <PCI_ROM_RESOURCE ; i++) { +struct bin_attribute *res_attr; + + res_attr = pdev->res_attr[i]; +if (res_attr) { +sysfs_remove_bin_file (&pdev->dev.kobj, res_attr); +kfree (res_attr); + } + } +} +#else /* !HAVE_PCI_MMAP */ +static void pci_create_resource_files (struct pci_dev *dev) {return ; } +static void pci_remove_resource_files (struct pci_dev *dev) {return ; } +#endif /* HAVE_PCI_MMAP */ +/** * pci_write_rom - used to enable access to the PCI ROM display * @kobj: kernel object handle
@@ -269,6 +357,8 @@else sysfs_create_bin_file (&pdev->dev.kobj, &pcie_config_attr); +pci_create_resource_files (pdev); +/* If the device has a ROM, try to expose it in sysfs. */ if (pci_resource_len (pdev,PCI_ROM_RESOURCE )) {struct bin_attribute *rom_attr;
@@ -303,6 +393,8 @@sysfs_remove_bin_file (&pdev->dev.kobj, &pci_config_attr); else sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); + +pci_remove_resource_files (pdev);if (pci_resource_len (pdev,PCI_ROM_RESOURCE )) {if (pdev->rom_attr) {
===== include/linux/pci.h 1.142 vs edited =====
include/linux/pci.h +1 -0
@@ -539,6 +539,7 @@u32 saved_config_space[16 ];/* config space saved at suspend time */ struct bin_attribute *rom_attr;/* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled;/* has display of the rom attribute been enabled? */ +struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE ];/* sysfs file for resources */ #ifdef CONFIG_PCI_NAMES #define PCI_NAME_SIZE 96#define PCI_NAME_HALF __stringify(43)/* less than half to handle slop */
Documentation/filesystems/sysfs-pci.txt new file +64 -0
64 lines not on this page · raw message
Greg KH
AppliedQuoted 9 lines · Jesse Barnes
Quoted 7 lines · Jesse Barnes
Quoted 3 lines
How about wrapping these two #ifdef blocks into one function, and moving it up in the file under the other #ifdef. Do that for the other cleanup function, and it will drop a bunch of #ifdefs.
Yeah, that sounds good. I really don't like adding these ifdefs, and limiting their scope to a function somewhere up above would be nicer. I'll do that and respin.
Quoted 8 lines
Ok, here you go.
This patch exports PCI resources to userspace in the corresponding sysfs device directory. It depends on the platform
HAVE_PCI_MMAPcode, and is #ifdef'd accordingly. I've also added documentation describing the sysfs PCI device file layout.Signed-off-by Jesse Barnes <[email protected]>
Looks good, I made one tiny change:
drivers/pci/pci-sysfs.c line 267
Quoted 4 lines
drivers/pci/pci-sysfs.c +4
-0+#else /* !HAVE_PCI_MMAP */ +static void pci_create_resource_files (struct pci_dev *dev) {return ; } +static void pci_remove_resource_files (struct pci_dev *dev) {return ; } +#endif /* HAVE_PCI_MMAP */
I made these inline to have the compiler just "make them go away" for when that define isn't enabled.
Applied to my trees,
thanks,
greg k-h