网卡驱动e1000解析

网卡驱动e1000解析e1000 网卡源码解析 e1000 网卡

大家好,欢迎来到IT知识分享网。

内核驱动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; } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/134711.html

(0)
上一篇 2025-07-10 14:20
下一篇 2025-07-10 14:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信