一、环境说明
内核版本:Linux 3.10
内核源码地址:https://elixir.bootlin.com/linux/v3.10/source (包含各个版本内核源码,且王页可全局搜索函数)
网卡:Intel的igb网卡
网卡驱动源码目录:drivers/net/ethernet/intel/igb/
二、网卡驱动的加载
网卡需要有驱动才能工作,驱动是加载到内核中的模块,负责衔接网卡和内核。
当相应的网卡收到数据包时,网络模块会调用相应的驱动程序处理数据。
网卡驱动程序 igb 向 Linux 内核通过 module_init 宏注册一个初始化函数 igb_init_module,当驱动加载的时候,该函数被内核调用。
// file: drivers/net/ethernet/intel/igb/igb_main.c static struct pci_driver igb_driver = { .name = igb_driver_name, .id_table = igb_pci_tbl, //所支持的设备列表 .probe = igb_probe, //探测函数 .remove = igb_remove, ...... }; static int __init igb_init_module(void) { ...... ret = pci_register_driver(&igb_driver); return ret; } module_init(igb_init_module);
igb_init_module()->pci_register_driver()->__pci_register_driver()->driver_register(),把网卡的驱动(driver)加载到内核 PCI 子系统。
三、网卡驱动的初始化
一个驱动程序可以支持一个或多个设备,而一个设备只会绑定一个驱动程序。
驱动程序将其支持的所有设备保存在一个列表 struct pci_device_id 中。
igb 驱动程序所支持的 PCI 设备列表部分如下:
// file: drivers/net/ethernet/intel/igb/igb_main.c static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 }, /* required last entry */ {0, } };
内核通过设备 ID 与驱动支持的设备列表匹配,选择合适的驱动控制网卡,然后调用之前注册到内核 PCI 子系统的探测函数(probe)完成初始化。
例如 igb 驱动程序的 igb_probe 函数,其处理流程包括:
- 设置 DMA 寻址限制和缓存一致性;
- 申请内核内存;
- struct net_device 结构体的创建、初始化和注册;
- 注册 struct net_device_ops(里面有 igb_open)到 net_device;
- 注册驱动支持的 ethtool 调用函数;
- 注册 poll 函数到 NAPI 子系统;
igb 驱动程序中 igb_probe 函数的部分代码如下:
// file: drivers/net/ethernet/intel/igb/igb_main.c static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { /* 申请 DMA 内存空间和 I/O 端口 */ err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); /* 获取 PCIe 设备的 Resource(Memory BAR、I/O BAR 和 MSI-X BAR),并通过这些 BARs 完成一系列访问和初始化 */ err = pci_request_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM), igb_driver_name); /* 网络设备 */ netdev = alloc_etherdev_mq(sizeof(struct igb_adapter), IGB_MAX_TX_QUEUES); /* net_device_ops 结构体,代表一个网络设备 */ netdev->netdev_ops = &igb_netdev_ops; /* 注册驱动支持的 ethtool 调用函数 */ igb_set_ethtool_ops(netdev); /* 函数里面注册了 poll 函数 */ err = igb_sw_init(adapter); }
四、网卡设备的启用
标签:INTEL,linux,DEV,网卡,PCI,之五,VDEVICE,ID,E1000 From: https://www.cnblogs.com/573583868wuy/p/17810582.html