/proc/pcibus patch

Stephen Williams (steve@icarus.icarus.com)
Sat, 13 Sep 1997 18:55:36 +0800


The included patch introduces the /proc/pcibus directory and the config
selection to turn it on/off. This is the first step in getting the
vendor and device strings out of the kernel and into user land.

The idea of this job is *not* to save kernel memory, as a few people
have been presuming, but to get the PCI list *administration* out of
the kernel. The only use of the kernel list is getting a pretty display
of the installed devices.

I have yet to remove /proc/pci.

So now how 'bout the people who have been administering the pci.c and pci.h
files that have all the vendor strings in them. We need to arrange for a
program in user mode that displays in ascii the contents of the /proc/pcibus
directory.

-- 
Steve Williams
steve@icarus.com
steve@picturel.com

"The woods are lovely, dark and deep. But I have promises to keep, And lines to code before I sleep, And lines to code before I sleep."

diff -Ncr -X ../exclude ./Documentation/Configure.help /usr/src/linux-2.1.55/Documentation/Configure.help *** ./Documentation/Configure.help Sat Sep 6 10:43:49 1997 --- /usr/src/linux-2.1.55/Documentation/Configure.help Sat Sep 13 11:02:38 1997 *************** *** 4243,4249 **** trouble if two devices are mistakenly configured to use the same IRQ). Several programs depend on this, so everyone should say Y here. ! NFS filesystem support CONFIG_NFS_FS If you are connected to some other (usually local) Unix computer --- 4243,4256 ---- trouble if two devices are mistakenly configured to use the same IRQ). Several programs depend on this, so everyone should say Y here. ! ! /proc/pcibus support ! CONFIG_PROC_PCIBUS ! This adds support for the pcibus directory under /proc. It allows ! the query of the configuration space of all the pci devices on the ! local computer. ! ! NFS filesystem support CONFIG_NFS_FS If you are connected to some other (usually local) Unix computer diff -Ncr -X ../exclude ./Documentation/pcibus.txt /usr/src/linux-2.1.55/Documentation/pcibus.txt *** ./Documentation/pcibus.txt Wed Dec 31 16:00:00 1969 --- /usr/src/linux-2.1.55/Documentation/pcibus.txt Sat Sep 13 16:36:48 1997 *************** *** 0 **** --- 1,21 ---- + + The /proc/pcibus directory provides support for access to the + configuration space of installed PCI devices. The directory contains a + file for every discovered function unit in the system. The file name + is a hex represent of the 16 bits arranged as follows: + + 15 - 8 7 - 3 2 - 0 + +------------+-----+-----+ + | BUS Number | dev | fn# | + +------------+-----+-----+ + + The numbers (except for the fn#) are assigned to the slot in a + mother-board specific way. The fn# allows for a device to have up to 8 + distinct functional units. + + Each file contains exactly 256 bytes. This is the official size of the + PCI configuration space for a device/function. Reading the bytes gets + the contents of the cnfiguration space directly from the + hardware. (Writing is currently not supported.) The layout of the + configuration space is defined by the ``PCI Local Bus Specification.'' + diff -Ncr -X ../exclude ./Makefile /usr/src/linux-2.1.55/Makefile *** ./Makefile Mon Sep 8 21:57:58 1997 --- /usr/src/linux-2.1.55/Makefile Thu Sep 11 16:56:47 1997 *************** *** 11,17 **** # # NOTE! SMP is experimental. See the file Documentation/SMP.txt # ! SMP = 1 # # SMP profiling options # SMP_PROF = 1 --- 11,17 ---- # # NOTE! SMP is experimental. See the file Documentation/SMP.txt # ! # SMP = 1 # # SMP profiling options # SMP_PROF = 1 diff -Ncr -X ../exclude ./fs/Config.in /usr/src/linux-2.1.55/fs/Config.in *** ./fs/Config.in Sat Aug 16 09:53:08 1997 --- /usr/src/linux-2.1.55/fs/Config.in Sat Sep 13 11:02:16 1997 *************** *** 16,21 **** --- 16,25 ---- dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS bool '/proc filesystem support' CONFIG_PROC_FS + if [ "$CONFIG_PROC_FS" = "y" -a "$CONFIG_PCI" = "y" ]; then + bool '/proc/pcibus support' CONFIG_PROC_PCIBUS + fi + if [ "$CONFIG_INET" = "y" ]; then tristate 'NFS filesystem support' CONFIG_NFS_FS if [ "$CONFIG_NFS_FS" = "y" ]; then diff -Ncr -X ../exclude ./fs/proc/Makefile /usr/src/linux-2.1.55/fs/proc/Makefi le *** ./fs/proc/Makefile Sat Aug 16 09:53:08 1997 --- /usr/src/linux-2.1.55/fs/proc/Makefile Sat Sep 13 10:49:03 1997 *************** *** 28,31 **** --- 28,35 ---- O_OBJS += proc_devtree.o endif + ifeq ($(CONFIG_PROC_PCIBUS),y) + O_OBJS += pcibus.o + endif + include $(TOPDIR)/Rules.make diff -Ncr -X ../exclude ./fs/proc/pcibus.c /usr/src/linux-2.1.55/fs/proc/pcibus .c *** ./fs/proc/pcibus.c Wed Dec 31 16:00:00 1969 --- /usr/src/linux-2.1.55/fs/proc/pcibus.c Sat Sep 13 15:40:31 1997 *************** *** 0 **** --- 1,151 ---- + /* + * Copyright (c) 1997 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. In order to redistribute the software in + * binary form, you will need a Picture Elements Binary Software + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + /* + * The /proc/pcibus directory contains files for all the known PCI + * devices. The contents of each file is the configuration space of + * the device and can only be read. + */ + + # include <linux/proc_fs.h> + # include <linux/bios32.h> + # include <linux/pci.h> + # include <linux/malloc.h> + # include <linux/init.h> + # include <asm/uaccess.h> + + /* + * Do the actual read of PCI configuration space. Access only DWORD + * values because there are PCI BIOSs out there that cannot properly + * do otherwise. Anyhow, there is no real point of doing less on a + * 32bit wide bus. + * + * The device to manipulate is passed as the data pointer, which was + * in turn set up by the init function when it created the file inode. + */ + static int pcibus_read(char*page, char **start, off_t off, + int cnt, int *eof, void *data) + { + struct pci_dev*dev = (struct pci_dev*)data; + unsigned tpos = off; + unsigned long tcnt; + unsigned *valp; + + if (tpos >= 256) { *eof = 1; return 0; } + if ((tpos + cnt) >= 256) { *eof = 1; cnt = 256 - tpos; } + + tcnt = cnt; + if (tpos & 3) { + tcnt += tpos & 3; + tpos &= ~3; + } + + tcnt = (tcnt + 3) & ~3; + + valp = (unsigned*)(page + tpos); + while (tcnt) { + int rc = pcibios_read_config_dword(dev->bus->number, + dev->devfn, tpos, + valp); + if (rc != PCIBIOS_SUCCESSFUL) { + printk("/proc/pcibus: Error %d reading config space.\n", rc); + return -EIO; + } + tcnt -= 4; + valp += 1; + } + + *start = page + off; + return cnt; + } + + static struct proc_dir_entry proc_root_pcibus = { + 0, /* Get the inode number dynamically */ + 6, "pcibus", + S_IFDIR | S_IRUGO | S_IXUGO, + 2, + 0, 0, + 0, + &proc_dir_inode_operations, + 0, 0, + 0, 0, 0, + 0, + NULL, NULL }; + + static const struct proc_dir_entry proc_root_dev_sample __initdata = { + 0, /* Get the inode number dynamically */ + 4, 0, /* All fine names are 4 characters, filled in later. */ + S_IFREG | S_IRUGO, + 1, + 0, 0, + 256, + NULL, + 0, 0, + 0, 0, 0, + 0, + pcibus_read, NULL }; + + + __initfunc(void proc_pcibus_init(void)) + { + struct proc_dir_entry*dev_table = 0; + struct pci_dev*dev; + struct proc_dir_entry*curp; + char*strp; + unsigned dev_count; + + if (!pcibios_present()) return; + + proc_register(&proc_root, &proc_root_pcibus); + + /* Count the PCI devices. I need the count to size the various + tables following. */ + dev_count = 0; + for (dev = pci_devices ; dev ; dev = dev->next) + dev_count += 1; + + if (dev_count == 0) return; + + /* This hack of allocating a single chunk of memory to hold + all my stuff is an attempt to reduce the malloc + overhead. Anyhow, it does the job with little fuss. */ + dev_table = kmalloc(dev_count * sizeof(struct proc_dir_entry) + + 5 * dev_count, GFP_KERNEL); + if (! dev_table) { + printk("/proc/pcibios: Not enough memory.\n"); + return; + } + + curp = dev_table; + strp = (char*)(dev_table + dev_count); + + for (dev = pci_devices ; dev ; dev = dev->next) { + *curp = proc_root_dev_sample; + curp->name = strp; + curp->data = dev; + sprintf(strp, "%02x%02x", dev->bus->number, dev->devfn); + + proc_register(&proc_root_pcibus, curp); + + curp += 1; + strp += 5; + } + } diff -Ncr -X ../exclude ./fs/proc/root.c /usr/src/linux-2.1.55/fs/proc/root.c *** ./fs/proc/root.c Sun Sep 7 14:00:24 1997 --- /usr/src/linux-2.1.55/fs/proc/root.c Sat Sep 13 10:51:27 1997 *************** *** 284,289 **** --- 284,293 ---- extern void openpromfs_init (void); #endif /* CONFIG_SUN_OPENPROMFS */ + #ifdef CONFIG_PROC_PCIBUS + extern void proc_pcibus_init(void); + #endif + static int make_inode_number(void) { int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); *************** *** 635,640 **** --- 639,647 ---- #endif #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); + #endif + #ifdef CONFIG_PROC_PCIBUS + proc_pcibus_init(); #endif }