2025年网卡驱动e1000解析

网卡驱动e1000解析内核驱动 e1000 具有如下 PCI 配置空间初始化 注册接口 pci register driver 电源管理 设备暂停和恢复 e1000 pm ops 类型 dev pm ops static SIMPLE DEV PM OPS e1000 pm ops e1000 suspend e1000 resume static

大家好,我是讯享网,很高兴认识大家。

内核驱动e1000具有如下:


讯享网

PCI 配置空间初始化

注册接口 pci_register_driver

//电源管理 设备暂停和恢复 e1000_pm_ops 类型 dev_pm_ops static SIMPLE_DEV_PM_OPS(e1000_pm_ops, e1000_suspend, e1000_resume); static struct pci_driver e1000_driver = { 
    .name = e1000_driver_name, // 对应的驱动名称 .id_table = e1000_pci_tbl, // 支持的pci设备编号,与pci.ids设备对应 .probe = e1000_probe, // pci设备入口函数 .remove = e1000_remove, // pci设备删除函数 .driver = { 
    .pm = &e1000_pm_ops, // 电源管理模块注册结构 }, .shutdown = e1000_shutdown, // 系统关闭操作函数 .err_handler = &e1000_err_handler // 错误处理函数 }; static int __init e1000_init_module(void) { 
    int ret; pr_info("%s\n", e1000_driver_string); pr_info("%s\n", e1000_copyright); ret = pci_register_driver(&e1000_driver); // 注册 pci 设备入口 if (copybreak != COPYBREAK_DEFAULT) { 
    if (copybreak == 0) pr_info("copybreak disabled\n"); else pr_info("copybreak enabled for " "packets <= %u bytes\n", copybreak); } return ret; } 

讯享网

pci 初始化后续逻辑

PCI 卡都遵循一个标准,x86 通过往两个内存地址读写就可以控制 IO 访问一个内部寄存器+一个地址偏移,就可以读写 PCI 的配置空间。

讯享网static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { 
    need_ioport = e1000_is_need_ioport(pdev); //判断设备是否需要pci端口io if (need_ioport) { 
    // 获得int 类型 Base Address Register 掩码 表示支持pci端口IO,pci内存映射 // 此时bar int类型32位 bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); err = pci_enable_device(pdev);// 使能pci设备 } else { 
    bars = pci_select_bars(pdev, IORESOURCE_MEM); err = pci_enable_device_mem(pdev); } if (err) return err; // 该操作可获得设备物理地址 err = pci_request_selected_regions(pdev, bars, e1000_driver_name); if (err) goto err_pci_reg; pci_set_master(pdev); //开启pci总线主控 err = pci_save_state(pdev); //保存pci 配置(寄存器配置相关) if (err) goto err_alloc_etherdev; err = -ENOMEM; //分配网卡设备结构,加入网卡设备队列,可以分配任意数据类型(关联任意网卡抽象结构) netdev = alloc_etherdev(sizeof(struct e1000_adapter)); if (!netdev) goto err_alloc_etherdev; // 设置设备从属关系 netdev.parent-> (&pdev->dev) SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); // pci关联网卡私有数据接口 // 缓存数据到 adapter 网卡队列节点 adapter = netdev_priv(netdev); // 获取netdev私有数据操作类 adapter->netdev = netdev; // 设置netdev adapter->pdev = pdev; // 设置pci结构 adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); // 日志打印等级 adapter->bars = bars; // pci掩码 adapter->need_ioport = need_ioport; //设置是否需要io口 hw = &adapter->hw; //硬件结构过去 hw->back = adapter; //设置parent hw->hw_addr = pci_ioremap_bar(pdev, BAR_0); // pci寄存器地址映射到虚拟地址 BAR_0:pci bar 0, 可通过虚拟地址访问(writel,readl接口) if (!hw->hw_addr) goto err_ioremap; if (adapter->need_ioport) { 
    for (i = BAR_1; i < PCI_STD_NUM_BARS; i++) { 
    // 执行 bar 1~5  if (pci_resource_len(pdev, i) == 0) continue; if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { 
    // 硬件Mem IO类型 hw->io_base = pci_resource_start(pdev, i); // 缓存IO Bar 起始地址 break; } } } /* make ready for any if (hw->...) below */ err = e1000_init_hw_struct(adapter, hw); // 初始化硬件结构,填充其他数据段、设置硬件mac地址等 if (err) goto err_sw_init; /* there is a workaround being applied below that limits * 64-bit DMA addresses to 64-bit hardware. There are some * 32-bit adapters that Tx hang when given 64-bit DMA addresses */ pci_using_dac = 0; if ((hw->bus_type == e1000_bus_type_pcix) && // pcix 类型(多pci引脚类型) !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { 
    // 设置64位掩码,内存映射需要使用 pci_using_dac = 1; // 条件控制初始化后续逻辑 } else { 
    err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); // 设置32位掩码 if (err) { 
    pr_err("No usable DMA config, aborting\n"); goto err_dma; } } netdev->netdev_ops = &e1000_netdev_ops; // 网络操作结构赋值 e1000_set_ethtool_ops(netdev); // netdev->ethtool_ops = &e1000_ethtool_ops; netdev->watchdog_timeo = 5 * HZ; // 看门狗超时时钟,用于实现传出超时的时间设定 // 驱动添加poll轮讯操作 // netdev是指向网络设备的指针,dapter->napi是指向NAPI实例的指针,e1000_clean是驱动程序提供的轮询函数,weight是设备的权重64。 netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); //赋值pci名称到网卡名称 adapter->bd_number = cards_found; /* setup the private structure */ err = e1000_sw_init(adapter); //tx rx 队列初始化,设置DOWN状态flags标志位,关中断 e1000_irq_disable(adapter); if (err) goto err_sw_init; err = -EIO; // mac类型条件特化操作,映射其他Bar到虚拟地址, if (hw->mac_type == e1000_ce4100) { 
    //目测当前设备是64位映射,需要使用BAR_1,e1000_bus_type_pcix 对应 hw->ce4100_gbe_mdio_base_virt = ioremap(pci_resource_start(pdev, BAR_1), pci_resource_len(pdev, BAR_1)); if (!hw->ce4100_gbe_mdio_base_virt) goto err_mdio_ioremap; } // 32位寄存器 // 硬件特性赋值 if (hw->mac_type >= e1000_82543) { 
    netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_RX; netdev->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER; } if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_82547)) netdev->hw_features |= NETIF_F_TSO; netdev->priv_flags |= IFF_SUPP_NOFCS; netdev->features |= netdev->hw_features; netdev->hw_features |= (NETIF_F_RXCSUM | NETIF_F_RXALL | NETIF_F_RXFCS); if (pci_using_dac) { 
    netdev->features |= NETIF_F_HIGHDMA; netdev->vlan_features |= NETIF_F_HIGHDMA; } netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_HW_CSUM | NETIF_F_SG); /* Do not set IFF_UNICAST_FLT for VMWare's 82545EM */ if (hw->device_id != E1000_DEV_ID_82545EM_COPPER || hw->subsystem_vendor_id != PCI_VENDOR_ID_VMWARE) netdev->priv_flags |= IFF_UNICAST_FLT; /* MTU range: 46 - 16110 */ netdev->min_mtu = ETH_ZLEN - ETH_HLEN; // 发送包的最小单元 60-14 netdev->max_mtu = MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN); //发送包的最大单元 3f00 - (14 + 4) adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw); /* initialize eeprom parameters */ if (e1000_init_eeprom_params(hw)) { 
    // 读取片上eeprom中硬件信息等,写入hw结构体 e_err(probe, "EEPROM initialization failed\n"); goto err_eeprom; } /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ e1000_reset_hw(hw); // 回写数据到eeprom /* make sure the EEPROM is good */ if (e1000_validate_eeprom_checksum(hw) < 0) { 
    // eeprom 校验 e_err(probe, "The EEPROM Checksum Is Not Valid\n"); e1000_dump_eeprom(adapter); /* set MAC address to all zeroes to invalidate and temporary * disable this device for the user. This blocks regular * traffic while still permitting ethtool ioctls from reaching * the hardware as well as allowing the user to run the * interface after manually setting a hw addr using * `ip set address` */ memset(hw->mac_addr, 0, netdev->addr_len); } else { 
    /* copy the MAC address out of the EEPROM */ if (e1000_read_mac_addr(hw)) e_err(probe, "EEPROM Read Error\n"); } /* don't block initialization here due to bad MAC address */ eth_hw_addr_set(netdev, hw->mac_addr); // MAC地址写入结构体 if (!is_valid_ether_addr(netdev->dev_addr)) e_err(probe, "Invalid MAC Address\n"); // 绑定函数由内核规则调用,比如fifo_stall_task INIT_DELAYED_WORK(&adapter->watchdog_task, e1000_watchdog); //看门狗执行任务绑定 INIT_DELAYED_WORK(&adapter->fifo_stall_task, e1000_82547_tx_fifo_stall_task); // tx 队列失效时任务绑定 INIT_DELAYED_WORK(&adapter->phy_info_task, e1000_update_phy_info_task); //硬件信息更新任务绑定 INIT_WORK(&adapter->reset_task, e1000_reset_task); // 重置任务操作绑定 e1000_check_options(adapter); //检查功能项 // LAN ACPI低功耗功能唤醒设置,根据mac_type进行相关硬件设置 /* Initial Wake on LAN setting * If APM wake is enabled in the EEPROM, * enable the ACPI Magic Packet filter */ switch (hw->mac_type) { 
    case e1000_82542_rev2_0: case e1000_82542_rev2_1: case e1000_82543: break; case e1000_82544: e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); eeprom_apme_mask = E1000_EEPROM_82544_APM; break; case e1000_82546: case e1000_82546_rev_3: if (er32(STATUS) & E1000_STATUS_FUNC_1) { 
    e1000_read_eeprom(hw, EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); break; } fallthrough; default: e1000_read_eeprom(hw, EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); break; } if (eeprom_data & eeprom_apme_mask) adapter->eeprom_wol |= E1000_WUFC_MAG; /* now that we have the eeprom settings, apply the special cases * where the eeprom may be wrong or the board simply won't support * wake on lan on a particular port */ switch (pdev->device) { 
    case E1000_DEV_ID_82546GB_PCIE: adapter->eeprom_wol = 0; break; case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: /* Wake events only supported on port A for dual fiber * regardless of eeprom setting */ if (er32(STATUS) & E1000_STATUS_FUNC_1) adapter->eeprom_wol = 0; break; case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: /* if quad port adapter, disable WoL on all but port A */ if (global_quad_port_a != 0) adapter->eeprom_wol = 0; else adapter->quad_port_a = true; /* Reset for multiple quad port adapters */ if (++global_quad_port_a == 4) global_quad_port_a = 0; break; } /* initialize the wol settings based on the eeprom settings */ adapter->wol = adapter->eeprom_wol; device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); /* Auto detect PHY address */ if (hw->mac_type == e1000_ce4100) { 
    for (i = 0; i < 32; i++) { 
    hw->phy_addr = i; e1000_read_phy_reg(hw, PHY_ID2, &tmp); if (tmp != 0 && tmp != 0xFF) break; } if (i >= 32) goto err_eeprom; } /* reset the hardware with the new settings */ e1000_reset(adapter); strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); // 注册网卡设备结构 if (err) goto err_register; e1000_vlan_filter_on_off(adapter, false); //关闭 vlan_filter /* print bus type/speed/width info */ e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n", ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""), ((hw->bus_speed == e1000_bus_speed_133) ? 133 : (hw->bus_speed == e1000_bus_speed_120) ? 120 : (hw->bus_speed == e1000_bus_speed_100) ? 100 : (hw->bus_speed == e1000_bus_speed_66) ? 66 : 33), ((hw->bus_width == e1000_bus_width_64) ? 64 : 32), netdev->dev_addr); /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); e_info(probe, "Intel(R) PRO/1000 Network Connection\n"); cards_found++; return 0; err_register: err_eeprom: e1000_phy_hw_reset(hw); if (hw->flash_address) iounmap(hw->flash_address); kfree(adapter->tx_ring); kfree(adapter->rx_ring); err_dma: err_sw_init: err_mdio_ioremap: iounmap(hw->ce4100_gbe_mdio_base_virt); iounmap(hw->hw_addr); err_ioremap: disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags); free_netdev(netdev); err_alloc_etherdev: pci_release_selected_regions(pdev, bars); err_pci_reg: if (!adapter || disable_dev) pci_disable_device(pdev); return err; } 
小讯
上一篇 2025-02-25 16:03
下一篇 2025-02-19 19:43

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/60103.html