0、说明

内核网络驱动总结,从设备树到内核驱动加载初始化及网卡通信整个流程。

1、环境

1.1 硬件环境

NXP imx6ul 平台

1.2 参考资料

IMX6ULLRM.pdf   22 章 10/100-Mbps Ethernet MAC (ENET)

2、网卡驱动

2.1 内核网卡驱动启动信息

fec 2188000.ethernet (unnamed net_device) (uninitialized): Invalid MAC address: 00:00:00:00:00:00
fec 2188000.ethernet (unnamed net_device) (uninitialized): Using random MAC address: a2:a4:3a:f9:1d:81
libphy: fec_enet_mii_bus: probed
fec 2188000.ethernet eth0: registered PHC device 0

fec_enet_mii_bus: probed可以定位到驱动位置:

drivers/net/ethernet/freescale/fec_main.c

2.2 设备树文件

arch/arm/boot/dts/imx6ull.dtsi
arch/arm/boot/dts/myb-y6ull-14x14.dts
fec1: ethernet@02188000 {compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";reg = <0x02188000 0x4000>;interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_ENET>,<&clks IMX6UL_CLK_ENET_AHB>,<&clks IMX6UL_CLK_ENET_PTP>,<&clks IMX6UL_CLK_ENET_REF>,<&clks IMX6UL_CLK_ENET_REF>;clock-names = "ipg", "ahb", "ptp","enet_clk_ref", "enet_out";stop-mode = <&gpr 0x10 3>;fsl,num-tx-queues=<1>;fsl,num-rx-queues=<1>;fsl,magic-packet;fsl,wakeup_irq = <0>;status = "disabled";};&fec1 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_enet1>;phy-mode = "rmii";phy-handle = <&ethphy0>;phy-reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;phy-reset-duration = <26>;status = "okay";mdio {#address-cells = <1>;#size-cells = <0>;ethphy0: ethernet-phy@0 {compatible = "ethernet-phy-ieee802.3-c22";smsc,disable-energy-detect;reg = <0>;};ethphy1: ethernet-phy@1 {compatible = "ethernet-phy-ieee802.3-c22";smsc,disable-energy-detect;reg = <1>;};};
};

设备树compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";与驱动的匹配

static const struct of_device_id fec_dt_ids[] = {{ .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },{ .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);

驱动fec_probe调用,开始网卡硬件的初始化及准备。

2.3 网卡驱动probe

最主要任务就是根据设备树中的信息及硬件信息,初始化网卡硬件,并向内核注册网卡设备,从而产生网络设备提供应用层使用。

其中涉及重要的结构体。主要分为内核结构体(platform_device、net_device)和厂家自定义板级结构体(如NXP的fec_enet_private,一般以私有数据排列在net_device后:fep = netdev_priv(ndev))芯片原厂定义自己的网卡结构体结合内核net_device,完成网卡驱动维护。

网卡probe主要任务

  • 获取设备树队列数量
  • 分配net_device结构体 alloc_etherdev_mqs
  • SET_NETDEV_DEV(net_device和platform_device关联)
  • 板级结构体安排到net_device后排列,netdev_priv
  • of_match_device 绑定网卡信息
  • 初步初始化板级结构体。fep->netdev = ndev;fep->num_rx_queues = num_rx_qs;....
  • 获取网卡寄存器地址并映射虚拟空间platform_get_resource、devm_ioremap_resource
  • 网卡配置解析(FEC_WOL_HAS_MAGIC_PACKET)
  • 获取phy信息(of_parse_phandle(np, "phy-handle", 0)、of_get_phy_mode)
  • 网卡时钟填充至板级结构体(devm_clk_get)
  • 复位phy(fec_reset_phy、reset_phy)
  • 申请描述符BD空间(fec_enet_init)
  • 获取中断信息并注册中断(platform_get_irq、devm_request_irq)
  • MII总结-mdio初始化(fec_enet_mii_init、mdiobus_register)
  • 关闭网卡netif_carrier_off(ndev) 等待phy启动它
  • register_netdev注册内核空间,产生网卡

        综上,网卡probe函数最主要是完成net_device的创建,其中主要需要关联net_device、platform_device、fec_enet_private进行后续网卡维护使用、获取设备树信息来初始化网卡配置、初始化phy并注册mii_bus及phy_device、申请中断、完成描述符创建及初始化、注册网卡进内核空间。

2.4 网卡收发队列

板级结构体中,定义有收发队列的变量。同时在注册网卡alloc_etherdev_mqs的时候也传递了队列数量。

 unsigned int num_tx_queues;                                                                                          ~                   unsigned int num_rx_queues;                                                                                          ~                   ~                   /* The saved address of a sent-in-place packet/buffer, for skfree(). */                                              ~                   struct fec_enet_priv_tx_q *tx_queue[FEC_ENET_MAX_TX_QS];                                                             ~                   struct fec_enet_priv_rx_q *rx_queue[FEC_ENET_MAX_RX_QS];  

发送队列

struct fec_enet_priv_tx_q {                                                                                              ~                   int index;                                                                                                           ~              //open的时候未tx_bounce分配控件,用于与skb复制   unsigned char *tx_bounce[TX_RING_SIZE];                                                                              ~                   //在发送后与skb一致,用于发送完成后skb释放使用struct  sk_buff *tx_skbuff[TX_RING_SIZE];                                                                            ~                   ~                   //在申请描述符的时候得到的发送描述符对应的物理地址--物理地址dma_addr_t  bd_dma;                                                                                                  ~                   //发送描述符BD的基址,在分配描述符后计算得出--虚拟地址struct bufdesc  *tx_bd_base;            //环形缓冲的大小,也是申请发送描述符的大小                                                                             ~                   uint tx_ring_size;                                                                                                   ~                   ~                   unsigned short tx_stop_threshold;                                                                                    ~                   unsigned short tx_wake_threshold;                                                                                    ~                   ~                   //指示下一次发送使用的描述符struct bufdesc  *cur_tx;                                                                                             ~                   //指示已经使用但为在中断中处理的描述符struct bufdesc  *dirty_tx;                                                                                           ~                   char *tso_hdrs;                                                                                                      ~                   dma_addr_t tso_hdrs_dma;                                                                                             ~
};    

接收队列

struct fec_enet_priv_rx_q {                                                                                              ~                   int index;                                                                                                           ~                   struct  sk_buff *rx_skbuff[RX_RING_SIZE];                                                                            ~                   ~                   dma_addr_t  bd_dma;                                                                                                  ~                   struct bufdesc  *rx_bd_base;                                                                                         ~                   uint rx_ring_size;                                                                                                   ~                   ~                   struct bufdesc  *cur_rx;                                                                                             ~
};         

2.5 网卡open

执行ifconfig将网卡up,在PHY协商后同步到mac后网卡更新至running状态。

open中主要任务

  • 开启时钟
  • 复位phy
  • 初始化描述符
  • 复位mac
  • 连接至phy上: phy_connect/of_phy_connect
  • 使能napi_enable、phy_start、netif_tx_start_all_queues

2.6 网卡close

2.7 网卡中断

2.8 网卡发包ndo_start_xmit

发包流程:

  • ndo_start_xmit函数被调用
  • skb提取队列index,准备队列调用二级发送函数fec_enet_txq_submit_skb(txq, skb, ndev);
  • 剩余描述符大小判断,需要大于最小分片包数
  • 得到一个描述符头
  • 提取skb地址和数据长度信息
  • 进行sdk数据映射到dma地址
  • 设置描述符一些标志
  • 将dma物理地址和数据长度写入描述符
  • 更新描述符头指针
  • 置位描述符发送准备就绪标志,等待硬件完成传输
  • 发送完成触发中断,中断读取事件类型
  • 中断处理,判断发送标志置位,则释放资源
  • 完成一次发送

如图,imx6ul共计512个发送环形描述符。由于描述符地址空间连续,可以很方便的使用和维护队列。网卡初始化完成后cur_rx为0,dirty_tx为511。当发送一包后,cur_rx向前移动,发几包移动几个。注意此时发送数量可能大于中断数量,因为dma发送需要时间。当发送完成中断被触发,在中断中判断完成标志,将发送完成标志置位的数据一起处理后移动dirty_tx指针。

dirty_tx下一个与cur_rx直接的描述符为未释放空间,表示发送已经执行,单未在中断中处理。

2.9 网卡收包

收包流程

  • 触发中断,开启软中断处理
  • 查寄存器判断中断触发类型
  • 遍历接收描述符
  • 判断状态位是否发生错误包
  • 丢去FCS
  • 处理可能的VLAN
  • 上报协议栈napi_gro_receive(&fep->napi, skb);
  • 循环NAPI_POLL_WEIGHT

2.10 MDIO PHY MII驱动

根据如上设备树以及在mac probe中,有队mii的初始化,同时在open时候也有队mii的probe。如fec_enet_mii_init、fec_enet_mii_probe。

网卡驱动中对于MDIO的操作主要有注册mii,注册phy_devcie。启动phy状态机。

网卡驱动中的probe(fec_enet_mii_init)

  • 注册mii总线of_mdiobus_register(fep->mii_bus, node);
  • 注册phy设备of_mdiobus_register_phy,同时匹配phy驱动,在phy_device时候初始化了一个delay_work:INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);

网卡驱动open(fec_enet_mii_probe)

  • 连接至phy_device,of_phy_connect
  • 初始化phy硬件phy_init_hw,完成复位及config
  • 填充adjust_link函数phy_prepare_link
  • 启动状态机phy_start_machine(循环调用DELAYED_WORK)
  • 进入phy状态机运行状态,反复读取phy寄存器
  • 同步phy状态到网卡。

总结

基于NAPI的网卡驱动,一次中断不再面对一个包,而是多个包,通过中断+轮询的方式给CPU降低持续网络通信带来的中断消耗。

probe中网卡的注册,包含注册网卡设备,申请中断,初始化时钟及相关网卡寄存器,申请描述符、注册mdio相关等。

发送函数中,将sdk映射到dma物理地址上,同时给描述符标记包准备就绪。发送完成后触发中断,中断中根据描述符中发送完成标志对已经发送的一系列包做释放。同时对连续地址的环形队列做移动。

接收函数中,判断描述符中头指针开始的一系列接收完成的数据包,进行包错误检查,skb预处理后上交协议栈,并移动头描述符。

PHY的信息在probe中获取,并注册内核mii_bus,同时将phy以phy_device的形式注册进内核与phy_driver进行匹配,在open中,连接至phy,启动状态机,检测phy寄存器变化将网络情况同步至mac。

linux网络-网卡驱动分析(基于imx6ul和ZYNQ分析)相关推荐

  1. Linux服务器网卡驱动安装及故障排除(转)

    Linux服务器网卡驱动安装及故障排除(转) 转自:http://www.ccw.com.cn/server/yyjq/htm2005/20050817_15OF4.htm感谢原创作者 曹江华 Lin ...

  2. Linux下网卡驱动安装及故障排除

    Linux下网卡驱动安装及故障排除 赛迪网 2007-4-26 9:10:00文/forgiven 网卡是Linux服务器中最重要网络设备.据统计,Linux网络故障有35%在物理层.25%在数据链路 ...

  3. linux 查看网卡损坏,Linux服务器网卡驱动安装及故障排除

    Linux服务器网卡驱动安装及故障排除 网卡是Linux服务器中最重要网络设备.据统计,Linux网络故障有35%在物理层.25%在数据链路层.10%在网络层.10%在传输层.10%在对话.7%在表示 ...

  4. linux下u盘网卡驱动,通过U盘给Linux系统安装网卡驱动的方法

    通过U盘给Linux系统安装网卡驱动的方法 RTL8169的网卡,系统是as 4.4 64位. 最精简安装,只安装了开发包. 没有驱动起来网卡,随机光盘没有for linux的网卡驱动. 只好到 rt ...

  5. linux下u盘网卡驱动,通过u盘给linux安装网卡驱动的做法——深圳培训linux

    简单方便使用,随手可得. 简洁快速,只需一个u盘即可为linux系统安装网卡驱动. 简便快捷的方法都是受大众喜欢的,这样可以快速的简单的解决问题. 通过u盘给linux系统安装网卡驱动的方法,这是一个 ...

  6. 基于linux的千兆网卡驱动程序实现及数据传输效率优化,嵌入式Linux下网卡驱动的实现与数据转发性能优化分析...

    摘要: 伴随着互联网的快速发展和后PC时代的到来,嵌入式系统已逐步成为当今IT产业的焦点之一,广阔的市场前景使嵌入式系统获得了空前的发展机遇.由于Linux操作系统具有代码开放.内核可裁减.网络功能强 ...

  7. linux 网卡驱动分析,基于linux下网卡驱动分析及实现技术研究

    摘    要 Linux技术是当前计算机技术中最大的一个热点,在我国以及全世界得到了迅猛的发展,被广泛的应用于嵌入式系统.服务器.网络系统.安全等领域.从而使得掌握在 Linux环境下的开发技术,成为 ...

  8. Linux 网卡驱动学习(一)(分析一个虚拟硬件的网络驱动样例)

    在Linux,网络分为两个层,各自是网络堆栈协议支持层,以及接收和发送网络协议的设备驱动程序层. 网络堆栈是硬件中独立出来的部分.主要用来支持TCP/IP等多种协议,网络设备驱动层是连接网络堆栈协议层 ...

  9. Linux PCI网卡驱动分析

    http://www.uplinux.com/shizi/wenxian/4429.html Linux网卡驱动分析 学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难 ...

最新文章

  1. CSS滤镜(Filters)
  2. [译]ASP.NET Core 2.0 机密配置项
  3. c语言大数相乘的算法_MIT 算法导论(三)
  4. CodeForces - 197A Plate Game(博弈+思维)
  5. 如何在Ubuntu中修改默认程序
  6. 文学系列:《叶之震颤》读书笔记
  7. jdbc连接linux下的mysql_Linux JDBC连接MySQL数据库
  8. 低功耗电波钟的制作 - 电子设计竞赛
  9. java去掉边框_java swing怎么去掉边框
  10. matlab中ones函数的使用方法详细介绍(附matlab代码)
  11. CSS-增加字体和颜色样式
  12. CAD中打开CAD图纸看不到内容怎么办?
  13. 基于Goolgle最新NavigationDrawer实现全屏水平平移
  14. 美国大学生解释为什么那么喜欢snapchat
  15. 计算机主机通电启动不了,电脑不通电,开机没反应?这里有问题!
  16. 命令行下将Debian10升级为Debian11
  17. cassandra 数据库
  18. 全国计算机等级考试一级教程讲义资料,全国计算机等级考试一级教程讲义资料.pdf...
  19. 游戏开发中的各种角色浅析
  20. 教你快速去掉VC运行环境下的Press any key to continue

热门文章

  1. 什么是“以管理员身份运行”
  2. 三星泰泽Tizen系统挑战Android系统
  3. 哔哩哔哩视频下载(python3+asyncio+断点续传+有注释)
  4. 图像光学失真预处理_摄影中的光学失真是什么?
  5. 十四、JTABLE类
  6. SwipeRefreshLayout实现下拉刷新功能
  7. 教你一招:修复win7 系统自带的截图工具损坏
  8. PHPJS字符串转数组,数组转字符串
  9. 2021年不限地区不限行业,减轻税负压力,税收优惠政策汇总
  10. 记我参加过的竞赛——“飞思卡尔杯”全国大学生智能汽车竞赛