(转载)原文链接:[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起到什么作用呢?其应用场景如下(示意图如下):
?
?
?
? ? ? 针对这两种应用场景,均没有使用phy芯片,但mac的驱动程序为保持通用性还是需要进行mii_bus注册以及net-device与phy-device的connect。因此mdio模块设计了一个虚拟的mii_bus(命名为fixed-mii_bus),用于mac芯片无需连接phy芯片的情况。针对上述情况而言,因两个mac间直接通过数据总线(rgmii/sgmii/qsgmii等)相连,因此需要手动配置mac芯片的模式(全双工)、速率(千兆/百兆/万兆等)。
?
主要定义了struct fixed_mdio_bus、struct fixed_phy两个结构体。其中struct fixed_mdio_bus中包含了
struct mii_bus类型的成员;而struct fixed_phy包含了struct phydev类型的成员。
该结构体表征一个虚拟mii_bus,并包含了fixed相关的信息,其中:
struct fixed_mdio_bus {
int irqs[PHY_MAX_ADDR];
struct mii_bus *mii_bus;
struct list_head phys;
};
?
该结构体表征一个虚拟phy设备,其中:
? 针对该接口指针,基本上不需要使用,若需要使用,则在创建虚拟phy设备时,赋值即可。
?
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;
};
?
?
?
?
在《LINUX MDIO模块分析(三)mii_bus注册、注销及其驱动开发流程》中,我们已经叙述了如何开发一个mii_bus驱动,此处引用一下:
? ? ? mii_bus结构体的定义如下,我们实现一个mii_bus驱动也就是实现该结构体类型的变量,并调用上述的mdiobus_register接口,即可完成mii_bus的注册。具体步骤如下:
?
而fixed_mii_bus的实现流程也大致如此。下面我们借助mii_bus的实现流程来分析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_mii_bus的实现流程:
?
?
?
?
?
? ? ? 该接口用于获取一个虚拟phy设备的寄存器值,而针对虚拟phy设备,其各寄存器的值即根据fixed_phy的struct fixed_phy_status 类型的成员变量status进行设置(即根据在虚拟phy设备的添加时,会通过struct fixed_phy_status 类型的变量,设置该虚拟phy设备的工作模式等信息)。该接口的实现流程图如下,主要功能为:
?
?
?
该接口主要将一个fixed_phy添加至fixed_mii_bus中,该接口的实现流程如下所示。主要功能:
?
? ? ? ?该接口主要是将一个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_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的不足。该接口的实现流程图如下:
?
?
?
? ? ? ? 在linux3.10及之前的版本,并没有提供该接口,若要使用则可以自己添加该接口。以上基本上完成了fixed_mii_bus模块相关接口的介绍,下面我们主要介绍如何使用fixed_mii_bus的接口。
?
上面介绍了fixed_mii_bus模块的接口,下面我们说明一下如何修改一个mac的驱动,实现对fixed_phy的支持。我们从两方面说明(支持设备树、不支持设备树)
?
?
?
?
?
?
通过进行以上的修改,即可让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。