Linux网络驱动基本概念
MAC、MDIO、MII、PHY
MAC(Media Access Control)
媒体访问控制,使用硬件实现ISO网络5层网络模型的数据链路层,对数据进行数据链路层的封包和解包。一般MAC位于处理器芯片内部。
PHY(Physical Layer)
物理层,使用硬件实现ISO网络5层网络模型的物理层,一般是单独的芯片
MDIO(Management Data Input/Output Interface)
数据输入输出管理接口,是MAC与PHY之间的控制接口。用于传输控制信息。MDIO是总线式接口,即一个MDIO总线上能挂载多个PHY,多个PHY之间使用addr区分不同的PHY
MII(Media Independent Interface)
介质独立界面,是MAC与PHY之间的数据传输接口,用于传输控制信息。衍生MII接口有GMII、RGMII,RMII。R是简化,G是千兆。RGMII就是简化的千兆MII
Linux设备树
mdio@102903c0 { //MDIO总线
compatible = "vendor,gemac-mdio";
reg = <0x102903c0 0x20>;
clocks = <0x5 0x65>;
resets = <0x5 0x37cc 0x0>;
reset-names = "phy_reset";
#address-cells = <0x1>;
#size-cells = <0x0>;
ethernet-phy@1 { // PHY芯片 1
reg = <0x1>;
phandle = <0xa>;
};
ethernet-phy@2 { // PHY芯片 2
reg = <0x2>;
phandle = <0xb>;
};
};
ethernet@10290000 { // MAC
compatible = "vendor,gmac-v5";
reg = <0x10290000 0x1000 0x1029300c 0x4>;
interrupts = <0x0 0x65 0x4 0x0 0x66 0x4 0x0 0x67 0x4 0x0 0x68 0x4>;
clocks = <0x5 0x65 0x5 0x66>;
clock-names = "gmac_clk", "macif_clk";
resets = <0x5 0x37c4 0x0 0x5 0x37c0 0x0>;
reset-names = "port_reset", "macif_reset";
mac-address = [00 00 00 00 00 00];
phy-handle = <0xa>; // 通过phandle将MAC与phy链接
phy-mode = "rgmii"; // 指定phy的模式为rgmii
};
Linux 驱动结构体
```
## 调用堆栈
```c
/**
* @brief 检查给定的"compat"字符串是否与device的"compatible"属性中的某个字符串匹配
*
* @param device 设备树节点结构体
* @param compat 待匹配的compat属性
* @return int 没有匹配成功返回0
*/
int of_device_is_compatible(const struct device_node *device,const char *compat);
/**
* @brief 从device的compatible获取pyh_id,ethernet-phy-idAAAA.BBBB
*
* @param device 设备树节点结构体
* @param phy_id [out]若匹配成功则输出获取的phy_id
* @return int 匹配成功返回0,否则返回-EINVAL
*/
int of_get_phy_id(struct device_node *device, u32 *phy_id);
mdio初始化流程
bsp_gemac_mdio_probe // 注册mdio设备
of_mdiobus_register // 注册mdio_bus设备
of_mdiobus_register_phy // 遍历子phy设备并注册
get_phy_device[note:1]
get_phy_id
phy_device_create
of_mdiobus_phy_device_register
phy_device_register // PHY device注册
phy_scan_fixups // 扫描可执行的fixup
gmac初始化流程
gmac_dev_probe // 注册 gmac 设备
gmac_phy_init
gmac_dev_probe_phy
gmac_phy_register_fixups // 注册fixup函数
of_phy_connect
phy_connect_direct
phy_attach_direct
phy_init_hw
phy_scan_fixups
note:1
// 如果phy节点包含phy_id,则调用phy_device_create
if (!is_c45 && !of_get_phy_id(child, &phy_id))
phy = phy_device_create(mdio, addr, phy_id, 0, NULL);
else
phy = get_phy_device(mdio, addr, is_c45);