基于335X的Linux网口驱动分析
Posted lh03061238
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于335X的Linux网口驱动分析相关的知识,希望对你有一定的参考价值。
基于335X的linux网口驱动分析
一、 系统构成
1、 硬件平台 AM335X
2、 LINUX内核版本 4.4.12
二、 网口驱动构架(mdio部分)
mdio网口驱动部分 使用 总线、设备、驱动模型,总结如下:
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }; |
davinci_mdio_driver |
若设备和驱动匹配,则执行
davinci_mdio_probe
--> mdiobus_register
--> device_register
--> mdiobus_scan
--> get_phy_device
--> get_phy_id // 读寄存器
--> phy_device_create // 创建phy设备
--> INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); // !!!!!!初始化状态机函数
--> phy_device_register
经过以上步骤,由davinci_mdio_driver又创建出一个mdio_bus_type类型的bus.并扫描并创建了连接在bus上的phydev.
struct bus_type mdio_bus_type = { .name = "mdio_bus", .match = mdio_bus_match, .pm = MDIO_BUS_PM_OPS, .dev_groups = mdio_dev_groups, }; |
davinci_mdio_probe --> mdiobus_register --> device_register --> mdiobus_scan --> get_phy_device --> get_phy_id // 读寄存器 --> phy_device_create // 创建phy设备 --> INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); // !!!!!!初始化状态机函数 --> phy_device_register
|
代码路径:drivers/net/phy/phy_device.c phy_init --> mdio_bus_init 注册mdio总线 --> class_register(&mdio_bus_class); --> bus_register(&mdio_bus_type); --> phy_driver_register(&genphy_driver); // 赋值总线、probe等 --> driver_register |
若设备和驱动匹配,这时,也进行了phydev和phy_driver的匹配和绑定。则执行phy_probe
以上总线下的设备和驱动的匹配过程如下,以platform_bus为例,其它总线也是这个流程
platform_device跟platform_driver的匹配
drivers/base/platform.c
a. 注册 platform_driver 的过程:
platform_driver_register
__platform_driver_register
drv->driver.probe = platform_drv_probe;
driver_register
bus_add_driver
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); // 把 platform_driver 放入 platform_bus_type 的driver链表中
driver_attach
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); // 对于plarform_bus_type下的每一个设备, 调用__driver_attach
__driver_attach
ret = driver_match_device(drv, dev); // 判断dev和drv是否匹配成功
return drv->bus->match ? drv->bus->match(dev, drv) : 1; // 调用 platform_bus_type.match
driver_probe_device(drv, dev);
really_probe
drv->probe // platform_drv_probe
platform_drv_probe
struct platform_driver *drv = to_platform_driver(_dev->driver);
drv->probe
b. 注册 platform_device 的过程:
platform_device_register
platform_device_add
device_add
bus_add_device
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); // 把 platform_device 放入 platform_bus_type的device链表中
bus_probe_device(dev);
device_initial_probe
__device_attach
ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); // // 对于plarform_bus_type下的每一个driver, 调用 __device_attach_driver
__device_attach_driver
ret = driver_match_device(drv, dev);
return drv->bus->match ? drv->bus->match(dev, drv) : 1; // 调用platform_bus_type.match
driver_probe_device
匹配函数是platform_bus_type.match, 即platform_match,
匹配过程按优先顺序罗列如下:
a. 比较 platform_dev.driver_override 和 platform_driver.drv->name
b. 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table
c. 比较 platform_dev.name 和 platform_driver.id_table
d. 比较 platform_dev.name 和 platform_driver.drv->name
有一个成功, 即匹配成功
CPSW也是一个内部设备,也遵循总线、设备、驱动模型。CPSW设备从设备树中获得,DRV则是系统注册,匹配后进行probe,其主要执行过程如下:
cpsw_probe
--> CPSW平台数据、资源、DMA初始化、赋值netdev_ops、ethtool_ops
--> 注册网络设备:register_netdev
--> cpsw_ndo_open (此处根据实际经验得到,目前还没有从源代码级别解答出调用过程)
--> cpsw_slave_open
--> phy_connect (传递cpsw_adjust_link)
--> bus_find_device_by_name (从mdio总线上查找device)
--> to_phy_device (从device结构体中找到phy_device)
--> phy_connect_direct (传递handler,初始化 ***)
--> phy_attach_direct ()
--> d->driver = &genphy_driver[GENPHY_DRV_1G].driver;(通用驱动赋值,3.17支持1G和10G)
--> d->driver->probe (这里就调用到Generic PHY的检测函数phy_probe)
--> device_bind_driver (绑定驱动到设备)
--> phydev->attached_dev = dev; (有函数使用到attached_dev指针)
--> phydev->state = PHY_READY; (将PHY状态标记为PHY_READY)
--> phy_init_hw (硬件级的初始化,最后会调用genphy_config_init)
--> phy_prepare_link (赋值cpsw_adjust_link为adjust_link)
--> phy_start_machine (启动PHY状态机 ***)
--> phy_start_interrupts (经测了,但好像没调用到这里)
--> phy_start(PHY_READY变成PHY_UP)
--> 其它的CPSW的初始化
基于335X的linux网口驱动分析
一、 系统构成
1、 硬件平台 AM335X
2、 LINUX内核版本 4.4.12
二、 网口驱动构架(mdio部分)
mdio网口驱动部分 使用 总线、设备、驱动模型,总结如下:
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }; |
davinci_mdio_driver |
若设备和驱动匹配,则执行
davinci_mdio_probe
--> mdiobus_register
--> device_register
--> mdiobus_scan
--> get_phy_device
--> get_phy_id // 读寄存器
--> phy_device_create // 创建phy设备
--> INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); // !!!!!!初始化状态机函数
--> phy_device_register
经过以上步骤,由davinci_mdio_driver又创建出一个mdio_bus_type类型的bus.并扫描并创建了连接在bus上的phydev.
struct bus_type mdio_bus_type = { .name = "mdio_bus", .match = mdio_bus_match, .pm = MDIO_BUS_PM_OPS, .dev_groups = mdio_dev_groups, }; |
davinci_mdio_probe --> mdiobus_register --> device_register --> mdiobus_scan --> get_phy_device --> get_phy_id // 读寄存器 --> phy_device_create // 创建phy设备 --> INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); // !!!!!!初始化状态机函数 --> phy_device_register
|
代码路径:drivers/net/phy/phy_device.c phy_init --> mdio_bus_init 注册mdio总线 --> class_register(&mdio_bus_class); --> bus_register(&mdio_bus_type); --> phy_driver_register(&genphy_driver); // 赋值总线、probe等 --> driver_register |
若设备和驱动匹配,这时,也进行了phydev和phy_driver的匹配和绑定。则执行phy_probe
以上总线下的设备和驱动的匹配过程如下,以platform_bus为例,其它总线也是这个流程
platform_device跟platform_driver的匹配
drivers/base/platform.c
a. 注册 platform_driver 的过程:
platform_driver_register
__platform_driver_register
drv->driver.probe = platform_drv_probe;
driver_register
bus_add_driver
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); // 把 platform_driver 放入 platform_bus_type 的driver链表中
driver_attach
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); // 对于plarform_bus_type下的每一个设备, 调用__driver_attach
__driver_attach
ret = driver_match_device(drv, dev); // 判断dev和drv是否匹配成功
return drv->bus->match ? drv->bus->match(dev, drv) : 1; // 调用 platform_bus_type.match
driver_probe_device(drv, dev);
really_probe
drv->probe // platform_drv_probe
platform_drv_probe
struct platform_driver *drv = to_platform_driver(_dev->driver);
drv->probe
b. 注册 platform_device 的过程:
platform_device_register
platform_device_add
device_add
bus_add_device
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); // 把 platform_device 放入 platform_bus_type的device链表中
bus_probe_device(dev);
device_initial_probe
__device_attach
ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); // // 对于plarform_bus_type下的每一个driver, 调用 __device_attach_driver
__device_attach_driver
ret = driver_match_device(drv, dev);
return drv->bus->match ? drv->bus->match(dev, drv) : 1; // 调用platform_bus_type.match
driver_probe_device
匹配函数是platform_bus_type.match, 即platform_match,
匹配过程按优先顺序罗列如下:
a. 比较 platform_dev.driver_override 和 platform_driver.drv->name
b. 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table
c. 比较 platform_dev.name 和 platform_driver.id_table
d. 比较 platform_dev.name 和 platform_driver.drv->name
有一个成功, 即匹配成功
CPSW也是一个内部设备,也遵循总线、设备、驱动模型。CPSW设备从设备树中获得,DRV则是系统注册,匹配后进行probe,其主要执行过程如下:
cpsw_probe
--> CPSW平台数据、资源、DMA初始化、赋值netdev_ops、ethtool_ops
--> 注册网络设备:register_netdev
--> cpsw_ndo_open (此处根据实际经验得到,目前还没有从源代码级别解答出调用过程)
--> cpsw_slave_open
--> phy_connect (传递cpsw_adjust_link)
--> bus_find_device_by_name (从mdio总线上查找device)
--> to_phy_device (从device结构体中找到phy_device)
--> phy_connect_direct (传递handler,初始化 ***)
--> phy_attach_direct ()
--> d->driver = &genphy_driver[GENPHY_DRV_1G].driver;(通用驱动赋值,3.17支持1G和10G)
--> d->driver->probe (这里就调用到Generic PHY的检测函数phy_probe)
--> device_bind_driver (绑定驱动到设备)
--> phydev->attached_dev = dev; (有函数使用到attached_dev指针)
--> phydev->state = PHY_READY; (将PHY状态标记为PHY_READY)
--> phy_init_hw (硬件级的初始化,最后会调用genphy_config_init)
--> phy_prepare_link (赋值cpsw_adjust_link为adjust_link)
--> phy_start_machine (启动PHY状态机 ***)
--> phy_start_interrupts (经测了,但好像没调用到这里)
--> phy_start(PHY_READY变成PHY_UP)
--> 其它的CPSW的初始化
以上是关于基于335X的Linux网口驱动分析的主要内容,如果未能解决你的问题,请参考以下文章