6.4. Example of PCI NIC Driver Registration

 

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 Picture

Let'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.[*]

[*] Other buses behave in a similar way. Please refer to Linux Device Drivers for details.

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:[] let's then take the example of Figure 6-1(a) with three PCI devices and see what happens when device drivers A and B are loaded.

[] This may not be possible for all bus types.

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 devices


When 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 Filesystem

The /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 Chapter

Table 6-1 summarizes the functions, macros, and data structures introduced in this chapter.

Table 6-1. Functions, macros, and data structures related to PCI device handling

Name

Description

Functions and macros

 

pci_register_driver

pci_unregister_driver

pci_module_init

Register, unregister, and initialize a PCI driver.

Data structure

 

struct pci_driver

struct pci_device_id

struct pci_dev

The first data structure defines a PCI driver (and consists mostly of virtual function callbacks). The second stores the universal ID associated with a PCI device. The last one represents a PCI device in kernel space.


 

6.8. Files and Directories Featured in This Chapter

Figure 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值