| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> Orin 10G网络分析 二 -> 正文阅读 |
|
[系统运维]Orin 10G网络分析 二 |
平台:nvidia orin 内核版本:linux-5.10 Orin 支持10G Tx 网络,所用的PHY芯片为AQR113,硬件在上篇文章已经介绍,本文主要从软件流程介绍: 设备树文件:
通过XFI接口 连接,设置10G模式: mgbe0_aqr113c_phy: ethernet_phy@0 { ? ? ? ? ? ? ? ? compatible = "ethernet-phy-ieee802.3-c45"; 可以看到使用的PHY芯片,及使用MDIO协议为c45 compatible = "nvidia,eqos-mdio"; 找到对应的驱动文件: kernel/nvidia/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c
platform_driver_register(ðer_driver);注册网络平台设备,进入porbe函数: ether_probe ??????? -> alloc_etherdev_mq? 申请网络设备,网络的eth0 接口 ??????? ->ether_parse_dt 解析设备树文件信息 ?????? ->ether_set_ethtool_ops 设置ethtool操作函数 ??????? ->ether_alloc_napi 支持napi ??????? ->ndev->netdev_ops = ðer_netdev_ops; 重点函数,设置网络操作的函数指针 ???? ?? ->register_netdev 注册网络设备 ?????? INIT_DELAYED_WORK(&pdata->ether_stats_work, ether_stats_work_func); ?????? INIT_DELAYED_WORK(&pdata->set_speed_work, set_speed_work_func);
进入ether_open ->ether_mdio_register? 注册mii_bus结构体并扫描phy设备 ->devm_mdiobus_alloc? 分配mdiobus ->new_bus->read = ether_mdio_read; 设置mdio读的回调函数 ->new_bus->write = ether_mdio_write; 设置mdio写的回调函数 ->of_mdiobus_register device_register将mii_bus设备注册进设备模型,之后获取设备树中记录的phy节点信息 ??????? ->of_mdiobus_register_phy 探测并创建phy_device设备 ??????? ->is_c45 = of_device_is_compatible(child, ? ? ? ? ? ? ? ? ? ? ?"ethernet-phy-ieee802.3-c45"); ????????????? ->get_phy_device(mdio, addr, is_c45); 调用get_phy_id读取phy芯片的id号 ?????????????? -> phy_device_create 分配了phy_device结构体并对其进行初始化 ?扫描到phy device后,创建phy device
?c45协议
上述函数中mdiobus_c45_read的调用关系 mdiobus_c45_read ?????????->mdiobus_read ? ????????->__mdiobus_read ?? ?????? ->retval = bus->read(bus, addr, regnum); 最终是调用的ether_mdio_register 注册mdio总线时的回调函数: 如下两个 new_bus->read = ether_mdio_read; new_bus->write = ether_mdio_write; phy device注册的流程: of_mdiobus_register of_mdiobus_register_phy of_mdiobus_phy_device_register phy_device_register mdiobus_register_device 此函数主要功能是赋值? mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev; phy_scan_fixups device_add? 会调用kobject_add将device注册进sysfs,再调用bus_add_device和bus_probe_device。bus_add_device将设备挂接到其总线(mdio_bus_type)的设备列表。bus_probe_device将遍历总线上已注册的所有驱动程序,调用总线的match函数检查驱动是否能和该设备匹配。若匹配则将设备和驱动程序绑定,然后调用驱动的probe函数,这里完成device_add之后就进入了phy_probe函数中。 再进入PHY 的probe函数 phy_probe 这个是同样的 PHY 的驱动函数,在kernel-5.10/drivers/net/phy/phy_device.c 函数中已经提前初始化了驱动函数: subsys_initcall(phy_init);? - > static int __init phy_init(void) ->phy_driver_register(&genphy_c45_driver, THIS_MODULE); 略去此段, 进入phy_probe 函数之后 ->phy_device_reset genphy_c45_pma_read_abilities 此函数主要读取PHY的能力 phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2); ........ 再真正进入PHY的初始化: ether_phy_init ????????->of_phy_connect ????????->phy_connect_direct ????????->phy_attach_direct 判断phy_device是否绑定了phy驱动,如果没有的话则将通用phy驱动genphy_driver作为phy_device的驱动,然后调用genphy_driver的probe函数,即phy_probe函数进行初始化处理,再调用device_bind_driver将设备和驱动正式绑定 ????????->get_device ????????->phy_sysfs_create_links ????????->phy_init_hw? 初始化 ??????? ->phy_scan_fixups ????????->phy_disable_interrupts 禁止中断 ????????->phy_resume? 唤醒PHY ????????->phy_led_triggers_register? LED显示 ether_adjust_link 真正判断link状态的是在这个函数中进行 cancel_delayed_work_sync(&pdata->set_speed_work); phy_print_status(phydev);? 打印网络状态 最后说一下Orin mdio_read 的过程: ether_mdio_read osi_read_phy_reg ?l_core->if_ops_p->if_read_phy_reg(osi_core, phyaddr, phyreg) if_ops_p->if_read_phy_reg = osi_hal_read_phy_reg; l_core->ops_p->read_phy_reg(osi_core, phyaddr, phyreg); ops->read_phy_reg = mgbe_read_phy_reg; 这复杂的调用关系,晕了晕了,到此结束
再提一下,mdio phy 设备名称的过程:可以看到/sys/class/mdio_bus/?? mdio_bus 下面有 可以看到 设备 6810000.ethernet 的名称 这个名字是如何注册来的呢? ether_mdio_register snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
此时的dev_name(dev) 正是 6810000.ethernet ??????? dev的名字是如何来的呢?? ether_probe(struct platform_device *pdev)? 时通过platform_device 解析设备树节点信息,传递过来的。这又是一个可以写一大篇的过程了,略去不表,总之是内核启动时自动将device_node转换为platform_device。 接着在phy_device_create 函数 phy设备创建时。 dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr); 创建了名字6810000.ethernet:00; 而 6810000.ethernet:00 即为 phy 设备的信息 参考文章: 基于对zynq以太网驱动的分析理解linux phy子系统_xiangweiky的博客-CSDN博客
以太网PHY寄存器分析_kunkliu的博客-CSDN博客_phy 寄存器 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 14:22:51- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |