* [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