第一次接触复旦微FMQL芯片的工程师,可能会被PS端网口的配置搞得一头大。这里我把自己踩过的坑总结一下,希望能帮你少走弯路。FMQL的PS端网口采用的是Synopsys DesignWare GMAC控制器,和Xilinx Zynq的架构类似,但在细节上还是有些差异需要注意。
先说说最基本的设备树配置。FMQL的GMAC控制器在设备树中的节点名是gmac0和gmac1,这点和Zynq保持一致。最简单的单PHY配置如下:
c复制&gmac0 {
status = "okay";
snps,reset-gpio = <&portb 17 GPIO_ACTIVE_LOW>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 100000>;
phy-mode = "rgmii";
phy-handle = <&phy0>;
mdio@0 {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy0: eth-phy@7 {
reg = <7>;
};
};
};
这里有几个关键点需要注意:
snps,reset-gpio必须正确配置,否则PHY芯片无法正常复位snps,reset-delays-us三个参数分别代表复位前延时、复位脉冲宽度和复位后延时,单位是微秒phy-mode要根据实际硬件连接选择,常见的有rgmii、rgmii-id等在实际项目中,PHY地址的配置有两种常见方式:明确指定和自动扫描。两种方式各有优缺点,需要根据具体情况选择。
这种方式直接在设备树中写明PHY的地址,如上文的eth-phy@7表示PHY地址是7。优点是明确可靠,不会出现地址冲突;缺点是不够灵活,如果硬件设计变更需要修改设备树。
c复制phy0: eth-phy@7 {
reg = <7>;
};
如果不指定PHY地址,内核会扫描所有可能的PHY地址(0-31):
c复制&gmac0 {
status = "okay";
snps,reset-gpio = <&portb 17 GPIO_ACTIVE_LOW>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 100000>;
phy-mode = "rgmii";
};
这种方式的好处是灵活,不需要关心PHY的具体地址;缺点是启动时会花费更多时间扫描,而且如果总线上有多个PHY可能会引起混淆。
特别提醒:在20210816版本的BSP中,即使使用自动扫描方式,也必须保留mdio节点,因为uboot对共享MDIO总线的支持做了修改。
在一些设计中,两个GMAC可能共享同一个MDIO总线控制多个PHY。这种情况下配置要格外小心,我遇到过不少坑。
下面是典型的共享MDIO总线配置:
c复制&gmac0 {
status = "okay";
snps,reset-gpio = <&portb 17 0>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 100000>;
phy-handle = <&phy0>;
mdio@0 {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy0: eth-phy@7 {
reg = <7>;
};
phy1: eth-phy@4 {
reg = <4>;
};
};
};
&gmac1 {
phy-mode = "rgmii-id";
status = "okay";
phy-handle = <&phy1>;
};
这里有几个要点:
这里要特别强调一个坑:共享MDIO总线时,PHY地址不能使用0!因为0是广播地址,不同PHY芯片对广播地址的处理方式不同,可能导致各种奇怪的问题。
有些PHY厂家允许关闭对0地址的响应(比如88E1116R),但为了保险起见,最好避免使用0地址。单PHY情况下没有这个限制,因为不存在地址冲突。
phy-mode的配置对网络稳定性影响很大,也是调试中最容易出问题的地方之一。
FMQL支持的phy-mode主要有以下几种:
rgmii:MAC和PHY都不添加延迟rgmii-id:PHY内部提供RX和TX延迟rgmii-rxid:仅PHY内部提供RX延迟rgmii-txid:仅PHY内部提供TX延迟选择哪种模式取决于PHY芯片的特性和硬件设计。一般来说,现代PHY芯片都支持内部延迟,推荐使用rgmii-id。
当遇到网络不稳定、丢包等问题时,很可能是延迟配置不当导致的。可以尝试以下调试方法:
c复制max-speed = <100>;
百兆模式对延迟要求较低,如果能稳定工作,说明问题可能出在千兆模式的延迟配置上。
c复制phy-mode = "rgmii-id"; // 或rgmii、rgmii-rxid、rgmii-txid
bash复制ethtool eth0 # 查看网口状态
ethtool -s eth0 speed 100 duplex full # 强制设为百兆
去年在一个国产化替代项目中,我们遇到了一个典型的GMAC调试问题。现象是网络时断时续,百兆模式下基本正常,但千兆模式下丢包严重。
经过排查,发现问题出在phy-mode的配置上。硬件设计使用的是PHY内部延迟,但设备树中配置的是rgmii模式。修改为rgmii-id后问题解决:
c复制phy-mode = "rgmii-id";
另一个案例是共享MDIO总线的问题。两个GMAC共用一个MDIO总线控制两个PHY,其中一个PHY地址设为0。结果发现两个网口会随机出现无法连接的情况。将PHY地址改为非0值后问题消失。
在调试GMAC相关问题时,以下几个技巧可能会帮到你:
bash复制dmesg | grep gmac
这会显示GMAC驱动加载时的详细信息,包括PHY检测结果、工作模式等。
bash复制mdio-tool eth0 read 0x1 0x0 # 读取PHY ID寄存器
mdio-tool eth0 read 0x1 0x11 # 读取PHY状态寄存器
bash复制echo 1 > /sys/class/net/eth0/phydev/reset
检查时钟配置:
确保GMAC参考时钟频率正确,通常为125MHz或25MHz。
使用示波器测量:
Q:为什么我的网口无法连接?
A:按照以下步骤排查:
Q:千兆模式下不稳定怎么办?
A:尝试以下方法:
Q:如何确认PHY地址?
A:有以下几种方法:
Q:两个网口无法同时工作?
A:可能是共享MDIO总线冲突导致,检查:
对于有更高要求的应用场景,还可以进行以下优化:
c复制&gmac0 {
snps,pbl = <32>;
snps,txpbl = <32>;
snps,rxpbl = <32>;
snps,no-pbl-xon;
};
c复制&gmac0 {
max-frame-size = <9000>; // 支持Jumbo Frame
};
c复制&gmac0 {
snps,eee-force-disable;
};
c复制&gmac0 {
interrupts = <0 45 4>;
interrupt-names = "macirq";
};
这些优化需要根据具体应用场景进行调整,建议在基本功能调通后再进行尝试。