From: Albert Cahalan <albert@users.sf.net>
To: linux-kernel <linux-kernel@vger.kernel.org>
Cc: akpm@digeo.com, torvalds@osdl.org
Subject: [PATCH] /proc/bus/pci* changes
Date: 13 Jul 2003 23:51:48 -0400 [thread overview]
Message-ID: <1058154708.747.1391.camel@cube> (raw)
The existing /proc/bus/pci/*/* files are a
hack involving ioctl and out-of-bounds mmap.
The following patch starts a transition to
something sane while keeping compatibility.
Typical user-space drivers for polled devices
should be easy to port to the new interface.
The X server will need some per-arch enhancements
to handle write-combining (non-x86 lack MTRRs)
and the use of multiple VGA-style devices.
In the new interface, pci/00/00.0 is a symbolic
link to a ../../pci*/bus0/dev0/fn0/config-space
file, where the '*' is typically 0. (PCI domain)
Simple and direct per-resource mmap() is provided,
via pci0/bus0/dev0/fn0/bar0 and so on.
diff -Naurd old/drivers/pci/proc.c new/drivers/pci/proc.c
--- old/drivers/pci/proc.c 2003-07-13 23:10:29.000000000 -0400
+++ new/drivers/pci/proc.c 2003-07-13 23:09:06.000000000 -0400
@@ -199,6 +199,14 @@
int write_combine;
};
+
+/*
+ * 2001-05-20 Alexander Viro "BTW, -pre4 got new bunch of ioctls. On
procfs, no less."
+ * 2001-05-20 Linus Torvalds "This particular braindamage is not too
late to fix.."
+ * 2003-06-30 Matthew Wilcox "The current fugly ioctl really has to
go."
+ *
+ * Damn, this lives in 2.6.xx, but at least a new interface is in
place.
+ */
static int proc_bus_pci_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
const struct proc_dir_entry *dp = PDE(inode);
@@ -240,6 +248,7 @@
}
#ifdef HAVE_PCI_MMAP
+/* old interface */
static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct
*vma)
{
struct inode *inode = file->f_dentry->d_inode;
@@ -379,43 +388,215 @@
struct proc_dir_entry *proc_bus_pci_dir;
+
+#ifdef HAVE_PCI_MMAP
+
+struct pci_bar_private {
+ struct pci_dev *pdev;
+ int bar;
+};
+
+
+/* For now, a wrapper. Next fixes: do a proper per-arch version of
this, plus mmap flags. */
+static int pci_bar_mmap_page_range(struct pci_dev *pdev, struct
vm_area_struct *vma, int bar)
+{
+ enum pci_mmap_state type; /* which PCI address space, MMIO or IO
ports? */
+ unsigned busaddr;
+ unsigned npages;
+ int ret;
+
+ type = pci_resource_flags(pdev,bar) & IORESOURCE_MEM ? pci_mmap_mem :
pci_mmap_io;
+
+ /* check size limit */
+ npages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ if(npages + vma->vm_pgoff > pci_resource_len(pdev,bar) >> PAGE_SHIFT)
+ return -EINVAL;
+
+ /* Eeew. Make the old per-arch interface happy. */
+ /* Too bad "busaddr = pci_resource_start(pdev,bar)" only works on
i386 */
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + bar * 4, &busaddr);
+ vma->vm_pgoff += busaddr >> PAGE_SHIFT;
+
+ /* vma ought to choose: uncache, write-combine, write-back... */
+ ret = pci_mmap_page_range(pdev, vma, type, 0);
+ if (ret<0)
+ return ret;
+ return 0;
+}
+
+
+static int proc_pci_bar_mmap(struct file *file, struct vm_area_struct
*vma)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ const struct proc_dir_entry *dp = PDE(inode);
+ struct pci_bar_private *private = dp->data;
+
+ int ret;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ ret = pci_bar_mmap_page_range(private->pdev, vma, private->bar);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int proc_pci_bar_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int proc_pci_bar_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ file->private_data = NULL;
+
+ return 0;
+}
+#endif /* HAVE_PCI_MMAP */
+
+static struct file_operations proc_pci_bar_operations = {
+#ifdef HAVE_PCI_MMAP
+ .open = proc_pci_bar_open,
+ .release = proc_pci_bar_release,
+ .mmap = proc_pci_bar_mmap,
+#ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA
+ .get_unmapped_area = get_pci_unmapped_area,
+#endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */
+#endif /* HAVE_PCI_MMAP */
+};
+
+/* TODO: per-arch way to hang a proc_dir_entry off of a pci domain */
+#ifdef CONFIG_PCI_DOMAINS
+static struct proc_dir_entry *procdom[0x10000];
+#else
+static struct proc_dir_entry *procdom[1];
+#endif
+
int pci_proc_attach_device(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
struct proc_dir_entry *de, *e;
char name[16];
+ char target[48]; /* sized for
../../pci65535/bus255/dev31/fn7/config-space */
+ int i;
if (!proc_initialized)
return -EACCES;
- if (!(de = bus->procdir)) {
- if (pci_name_bus(name, bus))
- return -EEXIST;
- de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
+ /* Create new-style /proc/bus/pci65535/bus255/dev31/fn7/config-space &
friends. */
+ if (!(de = bus->procbus)) {
+ if (!( de = procdom[pci_domain_nr(bus)] )) {
+ sprintf(name, "pci%u", pci_domain_nr(bus));
+ de = procdom[pci_domain_nr(bus)] = proc_mkdir(name, proc_bus);
+ if (!de)
+ return -ENOMEM;
+ }
+ sprintf(name, "bus%u", bus->number);
+ de = bus->procbus = proc_mkdir(name, de);
if (!de)
return -ENOMEM;
}
- sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO |
S_IWUSR, de);
+
+ if (!( de = bus->procdevs[PCI_SLOT(dev->devfn)] )) {
+ sprintf(name, "dev%u", PCI_SLOT(dev->devfn));
+ de = bus->procdevs[PCI_SLOT(dev->devfn)] = proc_mkdir(name,
bus->procbus);
+ if (!de)
+ return -ENOMEM;
+ }
+
+ sprintf(name, "fn%u", PCI_FUNC(dev->devfn));
+ de = dev->procfn = proc_mkdir(name, de);
+ if (!de)
+ return -ENOMEM;
+
+ e = dev->proccfg = create_proc_entry("config-space", S_IFREG | S_IRUGO
| S_IWUSR, de);
if (!e)
return -ENOMEM;
e->proc_fops = &proc_bus_pci_operations;
e->data = dev;
e->size = PCI_CFG_SPACE_SIZE;
+ /* one entry per resource */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE && pci_resource_start(dev,i);
i++) {
+ struct pci_bar_private *private;
+ private = kmalloc(sizeof(*private), GFP_KERNEL);
+ if (!private)
+ return -ENOMEM;
+ private->pdev = dev;
+ private->bar = i;
+ sprintf(name, "bar%u", i);
+ e = dev->procbar[i] = create_proc_entry(name, S_IFREG | S_IRUGO |
S_IWUSR, dev->procfn);
+ if (!e)
+ return -ENOMEM;
+ e->proc_fops = &proc_pci_bar_operations;
+ e->data = private;
+ e->size = pci_resource_len(dev,i);
+ }
+
+ /* Create old-style /proc/bus/pci/ff/1f.7 entry as a symlink. */
+ if (!(de = bus->procdir)) {
+ if (pci_name_bus(name, bus))
+ return -EEXIST; /* fail if name taken by some other PCI domain
*/
+ de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
+ if (!de)
+ return -ENOMEM;
+ }
+ sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ sprintf(target, "../../pci%d/bus%d/dev%d/fn%d/config-space",
pci_domain_nr(bus), bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
+ dev->procent = proc_symlink(name, de, target);
+ if (!dev->procent)
+ return -ENOMEM;
+
return 0;
}
int pci_proc_detach_device(struct pci_dev *dev)
{
struct proc_dir_entry *e;
+ int i;
+ /* old-style */
if ((e = dev->procent)) {
if (atomic_read(&e->count))
return -EBUSY;
remove_proc_entry(e->name, dev->bus->procdir);
dev->procent = NULL;
}
+ /* the config-space file */
+ if ((e = dev->proccfg)) {
+ if (atomic_read(&e->count))
+ return -EBUSY;
+ remove_proc_entry(e->name, dev->procfn);
+ dev->proccfg = NULL;
+ }
+ /* one entry per resource */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE && pci_resource_start(dev,i);
i++) {
+ e = dev->procbar[i];
+ if(!e)
+ continue;
+ if(atomic_read(&e->count))
+ return -EBUSY;
+ remove_proc_entry(e->name, dev->procfn);
+ dev->procbar[i] = NULL;
+ }
+ /* the per-fn directory */
+ if ((e = dev->procfn)) {
+ if (atomic_read(&e->count))
+ return -EBUSY;
+ kfree(e->data);
+ remove_proc_entry(e->name, dev->bus->procdevs[PCI_SLOT(dev->devfn)]);
+ dev->procfn = NULL;
+ }
+ /* the per-dev directory */
+ if ((e = dev->bus->procdevs[PCI_SLOT(dev->devfn)])) {
+ if (atomic_read(&e->count))
+ return -EBUSY;
+ remove_proc_entry(e->name, dev->bus->procbus);
+ dev->bus->procdevs[PCI_SLOT(dev->devfn)] = NULL;
+ }
return 0;
}
@@ -441,6 +622,9 @@
struct proc_dir_entry *de = bus->procdir;
if (de)
remove_proc_entry(de->name, proc_bus_pci_dir);
+ de = bus->procbus;
+ if (de)
+ remove_proc_entry(de->name, procdom[pci_domain_nr(bus)]);
return 0;
}
diff -Naurd old/include/linux/pci.h new/include/linux/pci.h
--- old/include/linux/pci.h 2003-07-13 23:09:45.000000000 -0400
+++ new/include/linux/pci.h 2003-07-13 23:09:17.000000000 -0400
@@ -371,7 +371,10 @@
struct pci_bus *subordinate; /* bus this device bridges to */
void *sysdata; /* hook for sys-specific extension */
- struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
+ struct proc_dir_entry *procent; /* in /proc/bus/pci (old-style) */
+ struct proc_dir_entry *procfn; /* in /proc/bus/pci* (new-style) */
+ struct proc_dir_entry *proccfg; /* config-space (new-style) */
+ struct proc_dir_entry *procbar[DEVICE_COUNT_RESOURCE]; /* per-bar
entries */
unsigned int devfn; /* encoded device & function index */
unsigned short vendor;
@@ -454,7 +457,9 @@
struct pci_ops *ops; /* configuration access functions */
void *sysdata; /* hook for sys-specific extension */
- struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
+ struct proc_dir_entry *procdir; /* old-style /proc/bus/pci entry */
+ struct proc_dir_entry *procbus; /* new-style /proc/bus/pci* entry */
+ struct proc_dir_entry *procdevs[32]; /* new-style /proc/bus/pci*
per-slot */
unsigned char number; /* bus number */
unsigned char primary; /* number of primary bridge */
next reply other threads:[~2003-07-14 3:45 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-07-14 3:51 Albert Cahalan [this message]
2003-07-14 4:53 ` [PATCH] /proc/bus/pci* changes Greg KH
2003-07-14 5:40 ` Albert Cahalan
2003-07-14 17:38 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1058154708.747.1391.camel@cube \
--to=albert@users.sf.net \
--cc=akpm@digeo.com \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.