6.4. Example of PCI NIC Driver Registration
Let's use the Intel PRO/100 Ethernet driver in drivers/net/e100.c to illustrate a driver registration:
#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {/ PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, / PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } static struct pci_device_id e100_id_table[] = { INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), ... }
We saw in the section "Registering a PCI NIC Device Driver" that a PCI NIC device driver registers with the kernel a vector of pci_device_id structures that lists the devices it can handle. e100_id_table is, for instance, the structure used by the e100.c driver. Note that:
-
The first field (which corresponds to vendor in the structure's definition) has the fixed value of PCI_VENDOR_ID_INTEL which is initialized to the vendor ID assigned to Intel.[*]
[*] You can find an updated list at http://pciids.sourceforge.net.
-
The third and fourth fields (subvendor and subdevice) are often initialized to the wildcard value PCI_ANY_ID, because the first two fields (vendor and device) are sufficient to identify the devices.
-
Many devices use the macro _ _devinitdata on the table of devices to mark it as initialization data, although e100_id_table does not. You will see in Chapter 7 exactly what that macro is used for.
The module is initialized by e100_init_module, as specified by the module_init macro.[*] When the function is executed by the kernel at boot time or at module loading time, it calls pci_module_init, the function introduced in the section "Registering a PCI NIC Device Driver." This function registers the driver, and, indirectly, all the associated NICs, as briefly described in the later section "The Big Picture."
[*] See Chapter 7 for more details on module initialization code.
The following snapshot shows the key parts of the e100 driver with regard to the PCI layer interface:
NAME "e100" static int _ _devinit e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { ... } static void _ _devexit e100_remove(struct pci_dev *pdev) { ... } #ifdef CONFIG_PM static int e100_suspend(struct pci_dev *pdev, u32 state) { ... } static int e100_resume(struct pci_dev *pdev) { ... } #endif static struct pci_driver e100_driver = { .name = DRV_NAME, .id_table = e100_id_table, .probe = e100_probe, .remove = _ _devexit_p(e100_remove), #ifdef CONFIG_PM .suspend = e100_suspend, .resume = e100_resume, #endif }; static int _ _init e100_init_module(void) { ... return pci_module_init(&e100_driver); } static void _ _exit e100_cleanup_module(void) { pci_unregister_driver(&e100_driver); } module_init(e100_init_module); module_exit(e100_cleanup_module);
Also note that:
-
suspend and resume are initialized only when the kernel has support for power management, so the two routines e100_suspend and e100_resume are included in the image only when that condition is true.
-
The remove field of pci_driver is tagged with the _ _devexit_p macro, and e100_remove is tagged with _ _devexit.
-
e100_probe is tagged with _ _devinit.
You will see in Chapter 7 what the _ _devXXX macros mentioned in the list are used for.
6.5. The Big PictureLet's put together what we saw in the previous sections and see what happens at boot time in a system with a PCI bus and a few PCI devices.[*]
When the system boots, it creates a sort of database that associates each bus to a list of detected devices that use the bus. For example, the descriptor for the PCI bus includes, among other parameters, a list of detected PCI devices. As we saw in the section "Registering a PCI NIC Device Driver," each PCI device is uniquely identified by a large collection of fields in the structure pci_device_id, although only a few are usually necessary. We also saw how PCI device drivers define an instance of pci_driver and register with the PCI layer with pci_register_driver (or its alias, pci_module_init). By the time device drivers are loaded, the kernel has already built its database:[
When device driver A is loaded, it registers with the PCI layer by calling pci_register_driver and providing its instance of pci_driver. The pci_driver structure includes a vector with the IDs of those PCI devices it can drive. The PCI layer then uses that table to see what devices match in its list of detected PCI devices. It thus creates the driver's device list shown in Figure 6-1(b). In addition, for each matching device, the PCI layer invokes the probe function provided by the matching driver in its pci_driver structure. The probe function creates and registers the associated network device. In this case, device Dev3 needs an additional device driver, called B. When driver B eventually registers with the kernel, Dev3 will be assigned to it. Figure 6-1(c) shows the results of loading the driver.
Figure 6-1. Binding between bus and drivers, and between driver and devicesWhen the driver is unloaded later, the module's module_exit routine invokes pci_unregister_driver. The PCI layer then, thanks to its database, goes through all the devices associated with the driver and invokes the driver's remove function. This function unregisters the network device. You can find more details about the internals of the probe and remove functions in Chapter 8.
6.6. Tuning via /proc FilesystemThe /proc/pci file can be used to dump information about registered PCI devices. The lspci command, part of the pciutils package, can also be used to print useful information about the local PCI devices, but it retrieves its information from /sys.
6.7. Functions and Variables Featured in This ChapterTable 6-1 summarizes the functions, macros, and data structures introduced in this chapter.
6.8. Files and Directories Featured in This ChapterFigure 6-2 lists the files and directories referred to in the chapter. The figure does not include all the files used by the topics covered in the chapter. For example, the drivers/pci/ directory includes several other files.
Figure 6-2. Files and directories featured in this chapter |