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

Re: PCI hardware detection [RFC]



On Thu, 19 Jul 2001 14:30:41 +0200
"Thierry Laronde" <thierry@cri74.org> wrote:

> Hello,
> 
> 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 ;)
> 

A while back i made a program that compared a table of pci id's (obtained using libpci (from pciutils)) to kernel modules. http://cvs.debian.org/debian-installer/tools/pcidetect/

It worked for PCI network devices, but i didnt fill in the database for other devices.

> 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
> /proc/bus/pci).
> 
Personally i would have liked the next installer to not have to depend on /proc, but its more trouble than its worth.

> 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).
> 

pcidetect *only* stores pci ids that hava coresponding kernel module.

> 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
> device.
> 
> 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 ?
> 	No.
> 	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.
> 

I agree, i think we should be as independent of the kernel as possible to make it more flexible for users who want to compile there own kernel.

> 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:
> http://www.yourvote.com/pci/
> 
> 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
> 0000100
> 
> 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.
> 

It does make sense to get the pci information directly from /proc rather than probing directly, libpci can do either (compile option), so its probably easier to use it rather than making up your own /proc parsing code.

> 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) :
> 
I think detecting storage devices is just as important, unless we assume all storage drivers are installed from the start.
hmm, i guess we can fetch storage drivers to ramdisk prior to inserting them, and it wouldnt take much extra memory, i would like to be able to install to lowmem machines (4MB).

> [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
> 		modules.
> 		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
> 
Problem with depending on bootloaders is that they are different for all architectures.

> [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
> 		  drivers
> 		- load all the drivers modules requested in order to have full
> 		  access to the hardware
> 		- analyze the software situation : partitionning, existence of
> 		  existing OS
Best to scan /proc/partitions to identify existing partitions, determining existence of other OS's may be painfull though.

> 		- 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
If we use parted we could try to resize existing partitions to make room for a new partition which we can use, or create a loopfs on an existing partition, then we can have heaps of space to store packages, or base.tgz.

The catch is if installing locally we need somewhere to store partitioning software prior to partitioning, if we store it on an existing partition then it makes partitioning more complex (cant repartition over our temp space). We have to assume the boot medium is read only.

ramfs (or ramdisk) is the simplest solution, but its best we be very carefull about what we put in ramfs so as not to increase minimum memory requirements. 

> 		- 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.
> */
> [snipped]
> 
> #define DRV_NAME	"3c59x"
> 
> /* Here some enum to identify chips */
> enum vortex_chips {
> 	CH_3C590 = 0,
> 	CH_3C592,
> 	CH_3C597,
> [snipped]
> 	CH_3CCFEM656_1,
> 	CH_3C450,
> };
> 
> 
> /* 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",
> 	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
> 	{"3c592 EISA 10mbps Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
> [snipped]	 
> 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
> 	{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 },
> [snipped]
> 	{0,}						/* 0 terminated list. */
> };
> ----------------------------------------------------------------
>
Yes, thats how i got the id's for pcidetect, see lst_net_*.h
 
> 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
> 
I used the following structure

typedef struct pci_ids_s {
        u32 vendor;
        u32 device;
} pci_ids_t;

A sample entry is
pci_ids_t hamachi_pci_ids[] = {
        { 0x1318, 0x0911 },
        { 0, 0 }
};
The name of each kernel module is matched to to struct so the char name is only stored in the db once.

> An optimization will be to create database from classes of devices in order
> to allow the use of smallest databases.
> 
If we just store a minimum of information in the database it wont get that big, pcidetect is 18kB, and i think i got all network devices at the time, but i agree it would be good to seperate the database from the program so different ones could be used.

> 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).
> 
> 

Also David did kdetect, which (if i remember ocrrectly) uses both libpci and libisa (if thats the right name) to handle isa cards too, even though pci has been standard there are still lots of 10Mbit isa network cards still around, so ISA is something we have to consider as well.


Glenn



Reply to: