1. 固定链路网络驱动概述
在嵌入式Linux系统开发中,Fixed-Link(固定链路)是一种特殊的网络连接方式,它不需要物理层芯片(PHY)就能实现网络通信。这种技术常见于SoC内部集成的网络控制器与外部交换机芯片直接相连的场景,或者开发板与调试主机之间的点对点连接。
我第一次接触Fixed-Link是在调试一块定制开发板时,发现网口指示灯不亮但实际能ping通目标机。经过排查才发现这个设计使用了MAC-to-MAC的直接连接方式。与传统PHY连接相比,Fixed-Link配置有以下几个显著特点:
- 省去了PHY芯片及其相关电路
- 链路状态始终被视为"已连接"
- 需要手动配置链路参数(速度、双工模式等)
- 常见于交换机芯片、工业控制设备等场景
2. Fixed-Link的工作原理
2.1 与传统PHY连接的区别
常规以太网连接需要MAC控制器通过MII/RMII/GMII等接口连接PHY芯片,由PHY处理物理层信号。而Fixed-Link模式下,MAC控制器直接连接到另一个MAC设备(通常是交换机芯片),省去了中间的PHY层。
这种架构下,软件需要明确告知驱动:
- 链路始终处于up状态
- 固定的速率和双工模式
- 不需要自动协商(auto-negotiation)
2.2 Linux内核中的实现机制
Linux网络驱动通过of_fixed_link_register()函数注册Fixed-Link设备。关键数据结构包括:
c复制struct fixed_phy_status {
int link; /* 固定为1 */
int speed; /* 如SPEED_100 */
int duplex; /* DUPLEX_FULL */
int pause; /* 流控设置 */
int asym_pause; /* 非对称流控 */
};
驱动开发者需要在设备树中明确指定这些参数:
dts复制fixed-link {
speed = <100>;
full-duplex;
};
3. 驱动开发实战
3.1 设备树配置详解
完整的Fixed-Link设备树节点示例:
dts复制ethernet@1 {
compatible = "vendor,eth-mac";
reg = <1>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
asym-pause;
};
};
各参数说明:
speed:必须指定,常见值10/100/1000full-duplex:全双工模式(不带值表示true)pause:启用流控asym-pause:非对称流控
3.2 驱动代码适配要点
在驱动代码中需要处理的关键点:
- 解析设备树节点:
c复制if (of_phy_is_fixed_link(np)) {
ret = of_phy_register_fixed_link(np);
if (ret) {
dev_err(dev, "Failed to register fixed PHY\n");
return ret;
}
}
- 实现phy_fixup(如果需要特殊配置):
c复制static int eth_phy_fixup(struct phy_device *phy)
{
phy->autoneg = AUTONEG_DISABLE;
phy->speed = SPEED_1000;
phy->duplex = DUPLEX_FULL;
return 0;
}
phy_register_fixup_for_uid(PHY_KSZ886X_ID, 0xffffffff, eth_phy_fixup);
4. 典型问题排查指南
4.1 常见故障现象
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| ifconfig显示NO-CARRIER | 设备树未正确配置fixed-link | 检查设备树speed/duplex设置 |
| 能ping通但丢包严重 | 两端速率/双工模式不匹配 | 确保两端配置一致 |
| 完全无法通信 | MAC地址未设置或冲突 | ifconfig检查并设置MAC地址 |
4.2 调试技巧
- 查看phy状态:
bash复制cat /sys/class/net/eth0/phy_state
- 强制重新协商(某些驱动支持):
bash复制ethtool -r eth0
- 详细寄存器检查:
bash复制ethtool -d eth0
重要提示:Fixed-Link模式下ethtool显示的链路状态可能不准确,应以实际通信测试为准
5. 性能优化建议
5.1 中断合并配置
由于没有PHY的物理层中断,建议调整中断合并参数:
bash复制ethtool -C eth0 rx-usecs 100 tx-usecs 100
5.2 DMA缓冲区设置
根据实际负载调整:
c复制static struct ethtool_ring_param ring = {
.rx_max_pending = 4096,
.tx_max_pending = 4096,
};
dev->ethtool_ops->get_ringparam(dev, &ring);
5.3 硬件流控启用
如果设备支持,建议启用流控:
dts复制fixed-link {
speed = <1000>;
full-duplex;
pause;
};
6. 实际案例:Marvell 88E6390交换机连接
这是我在某工业网关项目中的真实配置:
dts复制eth0: ethernet@20000 {
compatible = "marvell,armada-3700-eth";
phy-mode = "sgmii";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch@10 {
compatible = "marvell,mv88e6390";
ports {
port@1 {
phy-mode = "sgmii";
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
关键点:
- 两端必须使用相同的phy-mode
- 速率和双工设置必须完全一致
- 建议在交换机侧也明确声明fixed-link
7. 进阶话题:虚拟PHY实现
对于需要更灵活控制的场景,可以实现虚拟PHY:
c复制static int virt_phy_read_status(struct phy_device *phydev)
{
phydev->link = 1;
phydev->speed = SPEED_1000;
phydev->duplex = DUPLEX_FULL;
return 0;
}
static struct phy_driver virt_phy_driver = {
.phy_id = 0x12345678,
.name = "Virtual PHY",
.read_status = virt_phy_read_status,
};
这种方案适合需要动态调整链路参数的场景。我在一个5G CPE项目中就采用类似方案实现了速率自适应功能。