Boot&Knernel 中的 Fixed-Link 代码说明

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. 双工模式。1为单双工,2为全双工
  2. 传输速度
  3. pause
  4. 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;
}

你可能感兴趣的:(linux,networking,网络)