* [PATCH] export PCI resources in sysfs
@ 2004-12-21 17:43 Jesse Barnes
2004-12-21 18:43 ` Greg KH
0 siblings, 1 reply; 5+ messages in thread
From: Jesse Barnes @ 2004-12-21 17:43 UTC (permalink / raw)
To: Greg KH, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 503 bytes --]
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(+)
Signed-off-by: Jesse Barnes <jbarnes@sgi.com>
Thanks,
Jesse
[-- Attachment #2: sysfs-pci-resource.patch --]
[-- Type: text/plain, Size: 3843 bytes --]
===== drivers/pci/pci-sysfs.c 1.13 vs edited =====
--- 1.13/drivers/pci/pci-sysfs.c 2004-11-30 11:54:02 -08:00
+++ edited/drivers/pci/pci-sysfs.c 2004-12-21 09:38:49 -08:00
@@ -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 =====
--- 1.142/include/linux/pci.h 2004-10-31 14:10:04 -08:00
+++ edited/include/linux/pci.h 2004-12-21 09:08:37 -08:00
@@ -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 */
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] export PCI resources in sysfs 2004-12-21 17:43 [PATCH] export PCI resources in sysfs Jesse Barnes @ 2004-12-21 18:43 ` Greg KH 2004-12-21 19:09 ` Jesse Barnes 0 siblings, 1 reply; 5+ messages in thread From: Greg KH @ 2004-12-21 18:43 UTC (permalink / raw) To: Jesse Barnes; +Cc: linux-kernel On Tue, Dec 21, 2004 at 09:43:39AM -0800, Jesse Barnes wrote: > 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 */ 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 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] export PCI resources in sysfs 2004-12-21 18:43 ` Greg KH @ 2004-12-21 19:09 ` Jesse Barnes 2004-12-21 19:56 ` Jesse Barnes 0 siblings, 1 reply; 5+ messages in thread From: Jesse Barnes @ 2004-12-21 19:09 UTC (permalink / raw) To: Greg KH; +Cc: linux-kernel On Tuesday, December 21, 2004 10:43 am, Greg KH wrote: > On Tue, Dec 21, 2004 at 09:43:39AM -0800, Jesse Barnes wrote: > > 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 */ > > 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 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] export PCI resources in sysfs 2004-12-21 19:09 ` Jesse Barnes @ 2004-12-21 19:56 ` Jesse Barnes 2004-12-21 20:18 ` Greg KH 0 siblings, 1 reply; 5+ messages in thread From: Jesse Barnes @ 2004-12-21 19:56 UTC (permalink / raw) To: Greg KH; +Cc: linux-kernel [-- Attachment #1: Type: text/plain, Size: 767 bytes --] On Tuesday, December 21, 2004 11:09 am, Jesse Barnes wrote: > > 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. Signed-off-by: Jesse Barnes <jbarnes@sgi.com> Thanks, Jesse [-- Attachment #2: sysfs-pci-resource-2.patch --] [-- Type: text/plain, Size: 6969 bytes --] ===== drivers/pci/pci-sysfs.c 1.13 vs edited ===== --- 1.13/drivers/pci/pci-sysfs.c 2004-11-30 11:54:02 -08:00 +++ edited/drivers/pci/pci-sysfs.c 2004-12-21 11:28:57 -08:00 @@ -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 ===== --- 1.142/include/linux/pci.h 2004-10-31 14:10:04 -08:00 +++ edited/include/linux/pci.h 2004-12-21 11:21:50 -08:00 @@ -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 */ --- /dev/null 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5-pcires/Documentation/filesystems/sysfs-pci.txt 2004-12-21 11:50:26.000000000 -0800 @@ -0,0 +1,64 @@ +Accessing PCI device resources through sysfs + +sysfs, usually mounted at /sys, provides access to PCI resources on platforms +that support it. For example, a given bus might look like this: + + pci0000:17 + |-- 0000:17:00.0 + | |-- class + | |-- config + | |-- detach_state + | |-- device + | |-- irq + | |-- local_cpus + | |-- resource + | |-- resource0 + | |-- resource1 + | |-- resource2 + | |-- rom + | |-- subsystem_device + | |-- subsystem_vendor + | `-- vendor + `-- detach_state + +The topmost element describes the PCI domain and bus number. In this case, +the domain number is 0000 and the bus number is 17 (both values are in hex). +This bus contains a single function device in slot 0. The domain and bus +numbers are reproduced for convenience. Under the device directory are several +files, each with their own function. + + file function + ---- -------- + class PCI class (ascii, ro) + config PCI config space (binary, rw) + detach_state connection status (bool, rw) + device PCI device (ascii, ro) + irq IRQ number (ascii, ro) + local_cpus nearby CPU mask (cpumask, ro) + resource PCI resource host addresses (ascii, ro) + resource0..N PCI resource N, if present (binary, mmap) + rom PCI ROM resource, if present (binary, ro) + subsystem_device PCI subsystem device (ascii, ro) + subsystem_vendor PCI subsystem vendor (ascii, ro) + vendor PCI vendor (ascii, ro) + + ro - read only file + rw - file is readable and writable + mmap - file is mmapable + ascii - file contains ascii text + binary - file contains binary data + cpumask - file contains a cpumask type + +The read only files are informational, writes to them will be ignored. +Writable files can be used to perform actions on the device (e.g. changing +config space, detaching a device). mmapable files are available via an +mmap of the file at offset 0 and can be used to do actual device programming +from userspace. Note that some platforms don't support mmapping of certain +resources, so be sure to check the return value from any attempted mmap. + +Supporting PCI access on new platforms + +In order to support PCI resource mapping as described above, Linux platform +code must define HAVE_PCI_MMAP and provide a pci_mmap_page_range function. +Platforms are free to only support subsets of the mmap functionality, but +useful return codes should be provided. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] export PCI resources in sysfs 2004-12-21 19:56 ` Jesse Barnes @ 2004-12-21 20:18 ` Greg KH 0 siblings, 0 replies; 5+ messages in thread From: Greg KH @ 2004-12-21 20:18 UTC (permalink / raw) To: Jesse Barnes; +Cc: linux-kernel On Tue, Dec 21, 2004 at 11:56:39AM -0800, Jesse Barnes wrote: > On Tuesday, December 21, 2004 11:09 am, Jesse Barnes wrote: > > > 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. > > Signed-off-by: Jesse Barnes <jbarnes@sgi.com> Looks good, I made one tiny change: > +#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 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2004-12-21 20:18 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2004-12-21 17:43 [PATCH] export PCI resources in sysfs Jesse Barnes 2004-12-21 18:43 ` Greg KH 2004-12-21 19:09 ` Jesse Barnes 2004-12-21 19:56 ` Jesse Barnes 2004-12-21 20:18 ` Greg KH
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox