Overviewthe kernel's PCI subsystem, or PCI layer, provides a number of common features for different devices to simplify various device drivers.
The important structure of the PCI layer is as follows:
pci_device_id
device identification, based on the ID defined by the PCI flag, instead of Linux Local.
Pci_dev
a net_device similar to a network device. Each PCI is assigned a Net_dev instance.
Pci_driverinterface between the PCI layer and the device driver. Mainly consists of some function pointers. As shown below:
struct Pci_driver { struct list_head node; Char *name; Driver name const struct PCI_DEVICE_ID *id_table; /* ID vector, the kernel is used to associate the device to this driver */ int (*probe) (struct Pci_dev *dev, const struct pci_device_id *id); /* New Device inserted */ void (*remove) (struct Pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ int (*suspend) (struct Pci_dev *dev, pm_message_t s Tate); /* Device suspended */ int (*suspend_late) (struct Pci_dev *dev, pm_message_t state); int (*resume_early) (struct Pci_dev *dev); int (*resume) (struct Pci_dev *dev); /* Device Woken up */ void (*shutdown) (struct Pci_dev *dev); struct Pci_error_handlers *err_handler; struct device_driver driver; struct pci_dynids dynids;};
registration of PCI NIC devicesthe PCI device isPCI_DEVICE_ID (the member common) unique identity.
struct PCI_DEVICE_ID { __u32 vendor, device; /* Vendor and device ID or pci_any_id*///usually Vendor, the device is sufficient to identify devices __u32 Subvendor, subdevice;/* Subsystem ID ' s or PC i_any_id *///rarely used __u32 class, Class_mask; /* (CLASS,SUBCLASS,PROG-IF) triplet *///device belongs to class, such as Network class kernel_ulong_t driver_data; * * Data Private to the driver */ Does not belong to the PCI identity section, but drives the private parameter};
Each device driver registers aa vector of pci_device_id instances (that is, a series ofpci_device_id Instances), this vector contains the ID of the device that the driver can handle. The following are the registration and deletion functions of the device driver:
int __pci_register_driver (struct pci_driver *drv, struct module *owner, const char *mod_name) void Pci_unregister_driver ( struct Pci_driver *drv) pci_module_init ()//On some drivers as __pci_register_driver aliases
The kernel queries the device's driver based on the device ID, which is a detection mechanism. There are two ways of probing: static and dynamic.
Static:
Given the ID of a PCI, the kernel queries the corresponding driver from the id_table vector based on the ID .
Dynamic:based on the user's manually configured ID, it is less used and requires kernel compilation to support hot-swapping.
power management and wake on LANPCI power management events are performed with Pci_driver suspend and resume. These two functions are responsible for the preservation and recovery of PCI State respectively. If you encounter a NIC, you need to perform the following steps separately:
suspend: Stop the device exit queue so that the device can no longer be transferred:
Resume: Restarts the egress queue, where the device can continue to transmit.
The wake on LAN feature allows the NIC to wake the system when it receives a particular frame. This feature is usually disabled, butThis feature can be opened or closed with Pci_enable_wake. On this Part I found that linux-3.12.36 does not seem to have this function, may have used other network wake-up method, save later added.
example of PCI NIC driver registration
The Intel pro/100 Ethernet driver describes the registration of the NIC device driver, and the source file is drivers/net/e100.c.
Initialize pci_device_id content:
#define Intel_8255x_ethernet_device (device_id, ich) {\ Pci_vendor_id_intel, device_id, pci_any_id, pci_any_id, \ P Ci_class_network_ethernet << 8, 0xffff00, ich}/************************************************************* /#define DEFINE_PCI_DEVICE_TABLE (_table) \ const struct PCI_DEVICE_ID _table[] __devinitco Nst/***************************************************************************************/static DEFINE_PCI_ Device_table (e100_id_table) = {Intel_8255x_ethernet_device (0x1029, 0), Intel_8255x_ethernet_device (0x1030, 0), Intel_8255x_ethernet_device (0x1031, 3), Intel_8255x_ethernet_device (0x1032, 3), Intel_8255x_ethernet_device (0x10 3), Intel_8255x_ethernet_device (0x1034, 3), Intel_8255x_ethernet_device (0x1038, 3), Intel_8255x_ethernet_d Evice (0x1039, 4), Intel_8255x_ethernet_device (0x103a, 4), Intel_8255x_ethernet_device (0x103b, 4), INTEL_8255X_ Ethernet_device (0x103c, 4), intel_8255x_ethernet_device (0x103d, 4), Intel_8255x_ethernet_device (0x103e, 4), Intel_8255x_ethernet_device (0x1050, 5), I Ntel_8255x_ethernet_device (0x1051, 5), Intel_8255x_ethernet_device (0x1052, 5), Intel_8255x_ethernet_device (0x1053, 5), Intel_8255x_ethernet_device (0x1054, 5), Intel_8255x_ethernet_device (0x1055, 5), Intel_8255x_ethernet_devi CE (0x1056, 5), Intel_8255x_ethernet_device (0x1057, 5), Intel_8255x_ethernet_device (0x1059, 0), Intel_8255x_eth Ernet_device (0x1064, 6), Intel_8255x_ethernet_device (0x1065, 6), Intel_8255x_ethernet_device (0x1066, 6), INTEL _8255x_ethernet_device (0x1067, 6), Intel_8255x_ethernet_device (0x1068, 6), Intel_8255x_ethernet_device (0x1069, 6), Intel_8255x_ethernet_device (0x106a, 6), Intel_8255x_ethernet_device (0x106b, 6), Intel_8255x_ethernet_device (0 x1091, 7), Intel_8255x_ethernet_device (0x1092, 7), Intel_8255x_ethernet_device (0x1093, 7), Intel_8255x_etherne T_device (0x1094, 7), Intel_8255x_ethernet_device (0x1095, 7), Intel_8255x_ethernet_device (0X10FE, 7), Intel_8255x_ethernet_device (0x120 9, 0), Intel_8255x_ethernet_device (0x1229, 0), Intel_8255x_ethernet_device (0x2449, 2), Intel_8255x_ethernet_de VICE (0x2459, 2), Intel_8255x_ethernet_device (0x245d, 2), Intel_8255x_ethernet_device (0X27DC, 7), {0,}};
Complete the registration and logoff of the PCI device driver in the initialization and uninstallation interfaces of the module:
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/ * Power Management hooks */ . Suspend = E100_suspend, . Resume = E100_resume, #endif . Shutdown = E100_shutdown, . Err_handler = &e100_err_handler,};static int __init e100_init_module (void) { if (((1 << Debug)-1) & NETIF_MSG_DRV) { pr_info ("%s,%s\n", Drv_description, drv_version); Pr_info ("%s\n", drv_copyright); } Return Pci_register_driver (&e100_driver); }static void __exit e100_cleanup_module (void) { pci_unregister_driver (&e100_driver);} Module_init (E100_init_module); Module_exit (E100_cleanup_module);
Some of these function pointer prototypes:
#define DRV_NAME "e100" static int __devinit e100_probe (struct Pci_dev *pdev, const struct pci_device_id *ent) { C2/>struct Net_device *netdev; struct NIC *nic; int err; if (! ( Netdev = Alloc_etherdev (sizeof (struct NIC))) { if (((1 << Debug)-1) & Netif_msg_probe) pr_err ("ether Dev Alloc failed, aborting\n "); Return-enomem; } ... ......}
Overview of the PCI subsystem
(a) When the system boots, a database is created that associates each bus to a list of devices that have been detected and used on that bus. The PCI bus descriptor handles other parameters, including a list of detected PCI devices.
(b) When the driver is loaded and the call Pci_register_driver registers pci_driver to the PCI layer, PCI uses the PCI device ID parameter id_table in the Pci_driver structure to match the list of detected PCI devices. A list of devices that will establish the driver if it matches. For each device that matches, the PCI layer invokes the probe function in the pci_driver structure in the matching driver to establish and register the associated network device.
The/proc/pci file contains information about a registered PCI device. The LSPCI command in the Pciutils suite outputs information about the local PCI device, some of which are taken from/sys.
Deep understanding of Linux Network Technology Insider--PCI layer and network interface card