[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

PCI hardware detection [RFC]


Just a summary of the principles I plan to use for, at least, my own stuff
and that can be of some use for others too.

The following will focus on the Linux kernel, but since the installation can
be independant from the OS installed, the use of a Linux kernel for other
system installations is not forbidden ;)

PCI remainder

In short, the PCI norm defines a way to identify the devices attached to 
the slots. 256 bytes headers are placed in the configuration memory area,
and one can scan the buses to see if there are devices here, and if this is
the fact can retrieve informations about the devices.

These informations can be retrieve, of course, with or without the correct
devices drivers built in the kernel or in modules.

If the proc filesystem is compiled in the kernel, all the informations (and
in fact, all the 256 bytes headers) are available in /proc/bus/pci
subdirectory (/proc/pci is obsolete, and there is more to do with

So, the identification of the PCI devices (including on new hardware even
IDE controlers which are built on top of PCI buses) is "obvious", and the
information is easy to have via the proc fs.

But in order to be of some use, there are supplementary action to take : to
be able to use the identification to insert the correct driver in the kernel
(compilation option if one uses a build daemon, or insertion of modules).

The PCI IDs database

The identification of the devices, in the headers, is made via integers. In
order to display a more user friendly information, one can map the integers
to strings displaying an human readable information about the type of the

In the Linux kernel, there is a compilation time option to include this
database (built from drivers/pci/pci.ids) in the kernel. But the system by
itself has nothing to care about this "sugar".

Problems :
	Does this information really belong to the kernel space ?
	The answer is definitively: no. The kernel has nothing to do with this
	stuff; this enlarges the kernel by 80ko; this is only of some utility at
	installation time; the database is incomplete, changes and do somebody
	consider that it is normal to recompile a kernel for that ? etc...
	The fact is that the DB _must_ belong to user space.

	Does we need this for installation ?
	The PCI allows automatic detection of the devices, so there is strictly
	no need to output something to the user : this must and can be done
	silently and at a relativily low cost.

Exemple of device identification using /proc

First an example.
Here is an extract of my /proc/bus/pci/devices [this is probably not the
correct informations to use, see below]. A record is display like that :

0050	10b79055	b	0000f401	fedffc00	00000000	00000000	00000000	00000000	00000000

All values here are hexa (the complete description can be found in
<linux_sources>/drivers/pci/proc.c) and some are the result of the
concatenation of several different entries of the header.

0050 bus/function
10b79055 vendor/device
b irq
<7 values> io and memory resources

for example, the vendor value is 0x10b7. If you make a search via:

you will find that this is 3Com. 0x9055 refers to a 3C905B 100bTX, on IRQ 11
(b) etc...

More information are available in /proc/bus/pci/xx/ where xx is the two
digit number of the bus, and in fact the "files" here display the headers.
Example (for the very same device) :

$ od -h /proc/bus/pci/00/0a.0

0000000 10b7 9055 0117 0210 0030 0200 5008 0000
0000020 f401 0000 fc00 fedf 0000 0000 0000 0000
0000040 0000 0000 0000 0000 0000 0000 10b7 9055
0000060 0000 0000 00dc 0000 0000 0000 010b 0a0a

here we see additionnal values like the 0x0200 specifying that this device
belongs to the class of the Ethernet controler, etc... 

In fact the entries in /proc/bus/pci/xx/ are the more complete (these are
the headers) and the right place to look for information.

Database in user space

	Bootstrapping the installation

	For my own purpose, I will mainly use network installations. The process
	is the following but in fact can be applied for other devices (not only
	NIC ones) :

[First we need to be able to reach _one_ supplementary source of data : 
Network in this case, but this can be local disks too]
	- GRUB as a bootloader
		option a : modifying GRUB so that the PCI scanning is done whether
		or not NIC drivers are compiled and sending an option to indicate to
		the DHCP server (ISC 3.0 has conditionals) what device is there in
		order to create/swith to the correct initrd with the minimal
		option b : let the server identifying the hardware device calling
		and switch to the correct initrd. The trick is to be able to use
		small memory machines and not to send a big kernel with a big initrd

[The kernel loaded is able to access the supplementary data]
	- Once the Linux kernel is loaded
		- Extract from /proc the correct informations about the devices
		- send this to a service (for CDROM installation, the service can
		  be on the very same machine) which map the ID to the correct
		- load all the drivers modules requested in order to have full
		  access to the hardware
		- analyze the software situation : partitionning, existence of
		  existing OS
		- send this info to a service that takes the "decision" about
		  partitionning and packages to install
		  	-> this step can be thought in conjunction with FAI
		- client receives the order for the installation process

Building the PCI database

There are several sources for the mapping of the PCI Ids to strings
displaying the information about vendor and devices. But this is not really
what is needed. What is needed is the mapping between Ids and driver name.

These informations are spread (in the Linux kernel sources) in the drivers
sources. For example, in the drivers/net directory, we take 3c59x.c :

/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
	Written 1996-1999 by Donald Becker.

#define DRV_NAME	"3c59x"

/* Here some enum to identify chips */
enum vortex_chips {
	CH_3C590 = 0,

/* note: this array directly indexed by above enums, and MUST
 * be kept in sync with both the enums above, and the PCI device
 * table below
static struct vortex_chip_info {
	const char *name;
	int flags;
	int drv_flags;
	int io_size;
} vortex_info_tbl[] __devinitdata = {
#define EISA_TBL_OFFSET	0		/* Offset of this entry for vortex_eisa_init */
	{"3c590 Vortex 10Mbps",
	{"3c592 EISA 10mbps Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
	{0,}, /* 0 terminated list. */

/* And here what is of most interest for the data base */

static struct pci_device_id vortex_pci_tbl[] __devinitdata = {
	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
	{ 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
	{ 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
	{0,}						/* 0 terminated list. */

So the process is :

for every driver of a pci type of card :
	for every vendorId and DeviceID
		add vendorID:DeviceID\tDRV_NAME to the database

An optimization will be to create database from classes of devices in order
to allow the use of smallest databases.

What would be great too is to have a central place (there is
http://www.yourvote.com/pci/ for the IDs to name mapping; one can know other
db) to add the informations about PCI devices and drivers (one Debian db
accessible via network for example).

Thierry LARONDE, Centre de Ressources Informatiques, Archamps - France

Reply to: