Fixed-Link
fixed link 是一种写死 mac 与 phy 之间配置的一种办法,这种办法一般用在没有 phy 的直连场景之下。
设备树配置
一般情况下设备支持设备树,只需要在其内部配置好 fixed link 属性就可以了。其中 fixed-link 属性可以有新旧两种配置方式
旧:
&enet1 {
status = "okay";
fixed-link = <2 1 1000 0 0>;
auto-nego-mode= "sgmii-mac";
};
在旧模式下 fixed-link 后边的五个值的含义分别为
0. 为模拟 PHY 的 ID
- 双工模式。1为单双工,2为全双工
- 传输速度
- pause
- asym_pause
新:
fixed-link {
speed = <1000>;
full-duplex;
};
- ‘speed’(整数,必填),表示链接速度。通常情况下的值为 10、100、1000
- ’ 全双工’(布尔值,可选),表示工作在全双工情况下。如果没有配置,则假定为半双工。
- ‘pause’(布尔值,可选),表示可以暂停启用。
- ‘asym-pause’(布尔值,可选),指示 asym_pause 功能允许被启用。
- ‘link-gpios’(‘gpio-list’,可选),指示是否可以读取 gpio 确定链接是否正常。
通常这些配置之后就会初始化该网络设备使用配置过的 fixed link 进行链接。
boot 下的 fixed link 流程
在 u-boot 2020 中的代码流程如下:
在 phy 初始化的时候,如果开启了 CONFIG_PHY_FIXED 编译选项,就会激活 fixed phy 进行初始化。
int phy_init(void)
{
...
#ifdef CONFIG_PHY_FIXED
phy_fixed_init();
#endif
...
}
u-boot(后简称为 boot)会利用 phy 驱动去虚拟一个 phy 并利用在设备树中的配置去配饰这个虚拟的 phy 设备。在后续的 mac 初始化中与之匹配。
此时这个虚拟的 phy uid 为 PHY_FIXED_ID 其值为 #define PHY_FIXED_ID 0xa5a55a5a
static struct phy_driver fixedphy_driver = {
.uid = PHY_FIXED_ID,
.mask = 0xffffffff,
.name = "Fixed PHY",
.features = PHY_GBIT_FEATURES | SUPPORTED_MII,
.probe = fixedphy_probe,
.startup = fixedphy_startup,
.shutdown = fixedphy_shutdown,
};
int phy_fixed_init(void)
{
phy_register(&fixedphy_driver);
return 0;
}
一般在 mac 初始化完成后会利用 phy_connect 函数进行与 phy 设备的连接工作。在 fixed link 功能被使能之后(通过 CONFIG_PHY_FIXED 宏)会利用 phy_connect_fixed 函数进行设备树参数解析,并利用设备树参数进行 phy 设备的创建。
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
struct eth_device *dev,
phy_interface_t interface)
{
struct phy_device *phydev = NULL;
uint mask = (addr >= 0) ? (1 << addr) : 0xffffffff;
#ifdef CONFIG_PHY_FIXED
phydev = phy_connect_fixed(bus, dev, interface);
#endif
#ifdef CONFIG_PHY_NCSI
if (!phydev)
phydev = phy_device_create(bus, 0, PHY_NCSI_ID, false, interface);
#endif
#ifdef CONFIG_PHY_XILINX_GMII2RGMII
if (!phydev)
phydev = phy_connect_gmii2rgmii(bus, dev, interface);
#endif
if (!phydev)
phydev = phy_find_by_mask(bus, mask, interface);
if (phydev)
phy_connect_dev(phydev, dev);
else
printf("Could not get PHY for %s: addr %d\n", bus->name, addr);
return phydev;
}
而在 phy_connect_fixed 函数中,如果发现在设备树中有 fixed-link 的话,创建 phy 就会利用 PHY_FIXED_ID 作为 phy 地址传入下面的函数中。这样实际代码运行的时候连接的 phy 其实就是 phy_fixed_init 函数,创建的虚拟 phy 设备。
static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
u32 phy_id, bool is_c45,
phy_interface_t interface)
内核下的 fixed-link
boot 好多设计就是源于内核,但是要较内核简化不少。大致的逻辑还是和 boot 中一样的,都是创建虚拟 phy 设备用于 fixed-link
一般在 mac 驱动里会有如下的代码,of_phy_is_fixed_link 函数是用于判断设备树中有没有设置 fixed-link 的配置,创建虚拟 phy 设备的位置就是在 of_phy_register_fixed_link 函数中进行实现的。
if (!priv->phy_node && of_phy_is_fixed_link(np)) {
err = of_phy_register_fixed_link(np);
if (err)
return -1;
}