网卡驱动e1000解析

阅读: 评论:0

网卡驱动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 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("%sn", e1000_driver_string);pr_info("%sn", e1000_copyright);ret = pci_register_driver(&e1000_driver); // 注册 pci 设备入口if (copybreak != COPYBREAK_DEFAULT) {if (copybreak == 0)pr_info("copybreak disabledn");elsepr_info("copybreak enabled for ""packets <= %u bytesn", 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端口ioif (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;	   // 设置netdevadapter->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; //设置parenthw->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, abortingn");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-14netdev->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 failedn");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 Validn");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 Errorn");}/* 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 Addressn");// 绑定函数由内核规则调用,比如fifo_stall_taskINIT_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;elseadapter->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) %pMn",((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 Connectionn");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;
}

本文发布于:2024-02-02 02:19:05,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170681461340759.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:网卡驱动
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23