(转载)原文链接:[https://blog.csdn.net/u014044624/article/details/130674908]
(https://blog.csdn.net/u014044624/article/details/130674908)
前面几章我们介绍了MDIO模块的大部分内容,针对mii_bus、mdio_bus、phy_device、phy_driver相关的注册、注销均进行了介绍。基本上把mdio模块的内容介绍完了,而本篇介绍的内容,主要是针对虚拟mii_bus实现,并将虚拟phy_device注册至该mii_bus上。(本次分析内容基于LINUX3.10的内核)
那fixed-mii_bus起到什么作用呢?其应用场景如下(示意图如下):
- 两个cpu间的mac通过rgmii/sgmii等直接相连(不需要phy device),这两块核心板存在于一块单板上,无须使用phy芯片。
- cpu与fpga间的mac通过rgmii/sgmii等直接相连(不需要phy device),这两块核心板存在于一块单板上,无须使用phy芯片。
针对这两种应用场景,均没有使用phy芯片,但mac的驱动程序为保持通用性还是需要进行mii_bus注册以及net-device与phy-device的connect。因此mdio模块设计了一个虚拟的mii_bus(命名为fixed-mii_bus),用于mac芯片无需连接phy芯片的情况。针对上述情况而言,因两个mac间直接通过数据总线(rgmii/sgmii/qsgmii等)相连,因此需要手动配置mac芯片的模式(全双工)、速率(千兆/百兆/万兆等)。
fixed_mii_bus相关的数据结构说明
主要定义了struct fixed_mdio_bus、struct fixed_phy两个结构体。其中struct fixed_mdio_bus中包含了
struct mii_bus类型的成员;而struct fixed_phy包含了struct phydev类型的成员。
struct fixed_mdio_bus
该结构体表征一个虚拟mii_bus,并包含了fixed相关的信息,其中:
- 链表头phys用于将所有注册至fixed_mii_bus上的逻辑phy device链接在一起;
- irqs表示每一个虚拟phy对应的中断(基本上很少有使用该变量的,在mii_bus介绍章节中也说了,该中断可实现对phy devic link up/down的中断触发。在此处基本用不到)
struct fixed_mdio_bus {
int irqs[PHY_MAX_ADDR];
struct mii_bus *mii_bus;
struct list_head phys;
};
struct fixed_phy
该结构体表征一个虚拟phy设备,其中:
- id表示phy的addr,范围[0-31];
- regs表示该虚拟phy设备的寄存器值(因是一个虚拟phy,因此该虚拟phy的寄存器值由fxied_phy_status中的值决定)
- status中定义了该虚拟phy设备的各状态值,主要包括link状态、speed、duplex、pause、asym_pause等,而regs中的值即根据该变量中的内容进行设置;
- link_update接口用于更新虚拟phy的link状态。该接口类似于struct phydev中的adjust_link。它们之间的区别是:
- adjust_link接口根据phy device的link状态,对net_device的link状态进行更新;
- link_update接口则是根据net_device的link状态,对虚拟phy设备的link 状态进行更新。
针对该接口指针,基本上不需要使用,若需要使用,则在创建虚拟phy设备时,赋值即可。
- node主要用于将该结构体链接至fixed_mdio_bus的的phys链表上。
struct fixed_phy {
int id;
u16 regs[MII_REGS_NUM];
struct phy_device *phydev;
struct fixed_phy_status status;
int (*link_update)(struct net_device *, struct fixed_phy_status *);
struct list_head node;
};
struct fixed_phy_status {
int link;
int speed;
int duplex;
int pause;
int asym_pause;
};
fixed_mii_bus的实现流程
在《LINUX MDIO模块分析(三)mii_bus注册、注销及其驱动开发流程》中,我们已经叙述了如何开发一个mii_bus驱动,此处引用一下:
mii_bus结构体的定义如下,我们实现一个mii_bus驱动也就是实现该结构体类型的变量,并调用上述的mdiobus_register接口,即可完成mii_bus的注册。具体步骤如下:
- 需设置该mii_bus的名称与id,而在系统中可根据该id值搜索一个mii_bus;
- 完成read、write、reset方法,其中read、write主要用于与该mii_bus下的设备进行命令的交互;而reset方法主要用于对mii_bus的reset,关于这三个方法的实现,驱动开发人员可根据具体mac芯片的手册说明进行相应的开发操作。
- phy_mask主要用于设置需要忽略的phy addr,如我们需要忽略对phy addr 0的查找,则将phy_mask设置为0x01即可。
- 而irq主要指向一个数组,该数组中存储了每一个phy addr对应的irq,主要用于为每一个 phy addr对应的中断,该中断主要用于link up/down,针对该部分内容主要涉及到phy state machine,我们在后续章节中会详述该部分(大部分的mii_bus一般不提供该irq,但phy state machine提供了phy_poll机制,即是没有该irq,也可以进行phy link up/down,类似于mmc子模块中mmc card的poll机制)。
而fixed_mii_bus的实现流程也大致如此。下面我们借助mii_bus的实现流程来分析fixed_mii_bus。
- fixed_mii_bus的名称为fixed-0;
- 提供了read、write方法(比不需要实现reset方法,其实write方法也没有实现,因为挂载在该mii_bus上的均为虚拟phy设备,不需要进行设置操作)。read接口的功能为根据phy addr在fixed_mii_bus的phys链表中找到对应的虚拟phy设备,并根据该虚拟phy设备的struct fixed_phy_status类型的成员,更新其寄存器的值,并返回。
- fixed_mii_bus在初始化时,并没有设置需要忽略的phy addr;
- 将struct fixed_mdio_bus类型的全局变量platform_fmb中的irq数组赋值给platform_fmb.mii_bus->irq。
- 调用mdiobus_register完成fixed_mii_bus的注册。
fixed_mii_bus基本上严格按照我们上一篇文章中介绍的流程创建的mii_bus。而针对虚拟phy设备而言,需要各模块自行进行虚拟设备的添加,因此fixed_mii_bus模块提供了添加接口fixed_phy_add(在3.10的内核中,仅提供了该接口,这限制了fixed_mii_bus的虚拟phy设备的添加时机,后面详述。而在linux4.x以上的内核增加了接口fixed_phy_register)。
fixed_mdio_bus_init接口分析
该接口主要实现上述所说的fixed_mii_bus的实现流程:
- 为fixed_mii_bus申请对应的mii_bus,并设置其read、write、irq变量;
- 调用mdiobus_register接口,注册fixed_mii_bus。此处我们也多说一下:
- mdiobus_register接口我们在之前已经介绍过程,其会为phy addr范围为[0-31]的phy设备,调用mdiobus_scan进行phy device的搜索,若搜索到即为该虚拟phy设备创建phy_device,并注册到mdio_bus中(在搜索phy device时,即会调用fixed_mii_bus的read接口,若虚拟phy设备已添加到fixed_mii_bus中,则返回的phyid即为该虚拟phy设备的addr值,因此即会调用phy_device_create接口创建phy device,并注册至mdio_bus中。因此若在fixed_mdio_bus_init调用之前,未将虚拟phy设备添加至fixed_mii_bus上,则进行mdiobus_register时,搜索不到该虚拟phy设备)。
fixed_mdio_read接口分析
该接口用于获取一个虚拟phy设备的寄存器值,而针对虚拟phy设备,其各寄存器的值即根据fixed_phy的struct fixed_phy_status 类型的成员变量status进行设置(即根据在虚拟phy设备的添加时,会通过struct fixed_phy_status 类型的变量,设置该虚拟phy设备的工作模式等信息)。该接口的实现流程图如下,主要功能为:
- 根据输入的phy addr,查找该phy addr对应的虚拟设备是否已添加至fixed_mii_bus,若没有则返回失败;否则进入步骤b;
- 若查找的fixed_phy提供link_update接口,则调用该接口更新该fixed_phy->status变量中各成员的值;
- 调用fixed_phy_update_regs接口,根据fixed_phy->status更新该fixed_phy各寄存器的值;
- 返回该fixed_phy对应寄存器的值。
fixed_phy_add接口分析
该接口主要将一个fixed_phy添加至fixed_mii_bus中,该接口的实现流程如下所示。主要功能:
- 申请struct fixed_phy类型大小的内存空间;
- 若申请成功,则设置该fixed_phy的status成员,并更新其regs值;
- 将该fixed_phy添加至fixed_mii_bus的成员phys链表中。
该接口主要是将一个fixed_phy添加至fixed_mii_bus的成员phys中,并没有为之创建对应的phy_device。而针对fixed_mii_bus上的成员phys链表上的fixed_phy链表成员,仅在fixed_mdio_bus_init中注册fixed_mii_bus时,通过mdiobus_register时,完成将该链表上的所有链表成员,均为其注册对应的phy_device至mdio_bus上。因此若各驱动模块想通过fixed_phy_add接口添加一个fixed_phy,则必须保证其在接口fixed_mdio_bus_init调用之前被调用到,否则该添加操作不起作用(因没有创建对应的phy_device)。而在linux3.10中,仅提供了这一个接口进行fixed_phy的添加。这也是这个接口的缺陷,即必须保证调用该接口(fixed_phy_add)的代码片段在fixed_mdio_bus_init执行之前调用。
fixed_phy_register接口分析
上面分析fixed_phy_add接口的调用有所限制,必须保证其在fixed_mdio_bus_init执行之前调用。因此在 linux4.x的内核中,增加了接口fixed_phy_register,该接口弥补了fixed_phy_add的不足。接口fixed_phy_register在调用fixed_phy_add之后,调用phy_register,实现phy_device的注册,弥补了fixed_phy_add的不足。该接口的实现流程图如下:
- 获取一个可用的phy addr,若获取不到返回失败;
- 调用fixed_phy_add将该fixed_phy添加至fixed_mii_bus;
- 调用phy_register将该phy_device注册至mdio_bus上。
在linux3.10及之前的版本,并没有提供该接口,若要使用则可以自己添加该接口。以上基本上完成了fixed_mii_bus模块相关接口的介绍,下面我们主要介绍如何使用fixed_mii_bus的接口。
Mac2mac驱动程序修改流程
上面介绍了fixed_mii_bus模块的接口,下面我们说明一下如何修改一个mac的驱动,实现对fixed_phy的支持。我们从两方面说明(支持设备树、不支持设备树)
不支持设备树模式的修改流程
- 在mac驱动对应的platform driver的probe接口中,调用fixed_phy_register,完成fixed_phy的注册;
- 在该net_device的ndo_open接口中,调用phy_connect接口进行phy_device、net_device的绑定时,可根据"fixed-0:phy_addr",在mdio_bus上查找对应的phy_device,从而完成phy_device与net_device的绑定。
支持设备树模式的修改流程
- 在mac驱动对应的platform driver的probe接口中,通过获取设备树中针对phy-device的定义(如定义了fixed-link,则说明使用fixed_phy,则调用fixed_phy_register,完成fixed_phy的注册;在4.x的内核提供了接口of_phy_register_fixed_link进行fixed_phy的注册);
- 在在该net_device的ndo_open接口中,调用phy_connect接口进行phy_device、net_device的绑定时,可根据"fixed-0:phy_addr",在mdio_bus上查找对应的phy_device,从而完成phy_device与net_device的绑定。
通过进行以上的修改,即可让mac驱动支持fixed-phy的支持。
本章完成了fixed-phy的分析,也基本上完成了mdio子系统的介绍,我们分析了mii_bus相关的实现流程以及具体mii_bus驱动的实现步骤;也分析了phy_device、phy_driver、mdio_bus的实现流程,以及net_device与phy_device的绑定(phy_connect);介绍了phy_device的状态机流转相关的内容;fixed_mii_bus与fixed_phy的实现以及如何修改mac驱动支持fixed_phy。