1. Linux 系统网络协议层架构

在这里插入图片描述网络子系统是 linux 操作系统里很重要的一部分。关于这部分有很多的参考资料。这里主要说明一下 phy
芯片在整个子系统里的位置。从这个结构里看到,PHY 驱动的功能处于链路层。

  • 以太网物理层与硬件连接
    在这里插入图片描述从软件角度,对 phy 芯片的控制主要包括二部分:
    1) 与 MAC 设备的接口,即是 gmii 还是 rgmii。
    2) Phy 芯片的地址正确配置,可以通过 mdio/mdc 正确访问到 phy 芯片的寄存器。

2. 链路层与 Linux 网络设备管理

Linux 网络设备系统包括设备与驱动二大部分。网络设备驱动包括 MAC 层的驱动、MDIO 总结接口驱动
与 phy 驱动。结合 linux 系统设备树定义以及设备管理系统,构成 phy 驱动在开发过程中涉及到的所有
部分。示意如下图:
在这里插入图片描述在 Linux 设备管理系统里,硬件设备对应于在/sys/devices 下有对应的节点。如 MAC 设备:

ls -l /sys/devices/platform/ | grep ethernet
drwxr-xr-x 5 root root 0 2011-01-01 13:00 ff290000.ethernet

同理,硬件的 mdio 总线和 phy 芯片也会对应有一个设备节点:


rk3288:/sys/devices/platform/ff290000.ethernet # ls -l | grep bus
lrwxrwxrwx 1 root root 0 2021-01-23 05:44 driver -> ../../../bus/platform/drivers/rk_gmac-dwmac
drwxr-xr-x 3 root root 0 2011-01-01 13:00 mdio_bus ;mdio 设备节点
lrwxrwxrwx 1 root root 0 2021-01-23 10:37 subsystem -> ../../../bus/platform
rk3288: /sys/devices/platform/ff290000.ethernet/mdio_bus/stmmac-0 # ls -l | grep stmm
drwxr-xr-x 3 root root 0 2011-01-01 13:00 stmmac-0:04 ;地址为 4 的 phy 设备节点

3. Linux 以太网 phy 驱动基本开发流程

根据上图 linux 模块之间的关系,总结 Phy 驱动的开发流程如下:

  1. 硬件设计。包括 PHY 芯片地址设定、与 MAC 接口模式(如 RGMII)、MAC 时钟的接入方式、PHY 芯
    片的复位管脚以及 PHY 芯片上电工作模式的设置。
  1. 根据硬件连接,修改 linux 系统的设备定义树.dts 文件。通常是修改 GMAC 的定义以及 MII 管脚复用
    定义。具体需要看 SOC 芯片开发平台的定义。
  2. 把 phy 驱动编译链接到到 Linux Kernel Image 里来。具体请参考文档《裕太驱动使用手册》。
  3. 开机运行,检查目标机系统里有没有网络设备,如 eht0。如果有则进行下一步网络功能与性能的测
    试。如果没有,请检查:
  • Phy 驱动有没被正确加载,参看文档《裕太驱动使用手册》。
  • MAC 驱动有没有正确运行,参看开发平台提供的 MAC 驱动,重点检查(1)在 DTS 里配置的
    compatible 字段与 MAC 驱动里的定义是否一致。(2)MAC 资源(io map)与 irq 是否加载正确。
  • MDIO 是否访问正确。在 mdio 扫描代码里增加打印看 phy 寄存器的读写是否正确。
  • Phy id 是否被正确识别。在 mdio 扫描代码里增加打印看读到的 phy id 与 phy 驱动的 phy id 是
    否一致。
  • 与硬件工程师确认 phy 芯片是否工作正常(上电时序、时钟,供电及复位等),正常的话 phy 应该可以 link up。
  1. 网络设备建议与正常 Link up 之后,就可以进行网络功能测试。主要是 ping 通。
    Ping 通是很关键的一步。Ping 通与以下配置有关:
  • 如果是 rgmii 接口,在设备树配置文件里的 tx_delay 和 rx_dealy 的配置很重要,参考后面关于
    rgmii delay line 的配置。
  • PHY 的状态(link up, speed, duplex)是否正确。这个需要在 phy state machine 里增加打印进行跟
    踪(通常在 phy.c 里)。
  • 通过统计计数(MAC 层,phy 层)来确认是哪个方向(tx 或者 rx)的问题。
  1. 网络性能测试。主要是 iperf 性能测试。测试在 1000m 和 100m 等各种情况下的网络性能。
  2. 到这里整个 phy 驱动的功能就算完成了

4. Linux 设备树里 MAC 定义

MAC 设备的硬件描述在不同的平台里有区别。大多数的系统平台都使用 linux 的.dts 文件。如rk3556的RGMII:

&gmac1 {
	phy-mode = "rgmii";
	clock_in_out = "input";
	snps,reset-gpio = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>;
	snps,reset-active-low;
	snps,reset-delays-us = <0 20000 100000>;
	assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>, <&cru CLK_MAC1_OUT>;
	assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&gmac1_clkin>;
	assigned-clock-rates = <0>, <125000000>, <25000000>;
	pinctrl-names = "default";
	pinctrl-0 = <&gmac1m1_miim
		     &gmac1m1_tx_bus2
		     &gmac1m1_rx_bus2
		     &gmac1m1_rgmii_clk
		     &gmac1m1_rgmii_bus
		     /*&eth1m1_pins*/
		     &gmac1m1_clkinout>;
	tx_delay = <0x28>;
	rx_delay = <0x0>;
	phy-handle = <&rgmii_phy1>;
	status = "okay";
};


&mdio1 {
	status = "okay";
	rgmii_phy1: phy@1 {	//phy的地址:001
		compatible = "ethernet-phy-ieee802.3-c22";
		reg = <0x1>;	//phy的地址
		clocks = <&cru CLK_MAC1_OUT>;
	};
};

这其中phy的地址需要跟硬件确认,我之前调试的时候一直attch不到phy就是phy的地址没有弄正确

5.RGMII 接口 delay line 调整

对于 RGMII 接口,rx 和 tx delay line 调整的过程如下:

  1. 如果有参考的板子,可以按照参考值尝试。如果不行就按下面的步骤再进行。
  2. 在 DTS 里,把 tx_delay 和 rx_delay 都设置为 0。 3) 上电看能不能 ping 通。
  3. 如果不能 ping 通或者 ping 时断时续,就按下面的步骤,修改 PHY 本身的 delay 配置。通常 rx_delay不用调整。下面调整 tx_delay。Phy 寄存器读写方法参见下面的说明。
  • 设置 Ext. Reg 0xc.bit[7:4]为 0xf
  • 软件复位 phy(mii_reg_0.b15=1)
  • Link up 之后,看能不能 ping 通。
  • 如果不行,按二分法减少 delay 值,设置 Ext. Reg 0xc.bit[7:4],再从 b)步骤尝试,直到 ping 通。如果尝试了所有值都不通,再修改 DTS 里 tx_delay 为 0xf 再从步骤 3)开始尝试。
  1. 最后找到的值配置 dts 文件或者 Ext. Reg 0xc.bit[7:4](这里时修改phy的寄存器)。建议优先设置 dts 文件。

6。寄存器读写工具

6.1 PHY 寄存器读写
6.1.1 Linux MAC 设备 mdio 方法

通常 linux 系统的 mac 设备都有一个通用的方法对 phy 寄存器进行读写,不太好用,但不需要额外工作可以直接使用。方法是:

  1. 找到 phy 设备,如:
ls -l /sys/devices/platform/ | grep eth 
drwxr-xr-x 5 root root 0 2011-01-01 13:00 ff290000.ethernet

上面例子里,找到 mac 设备 ff290000.ethernet,继续找到 phy 设备,如下:

ls -l /sys/devices/platform/ff290000.ethernet/mdio_bus/
total 0
drwxr-xr-x 5 root root 0 2011-01-01 13:00 stmmac-0
ls -l /sys/devices/platform/ff290000.ethernet/mdio_bus/stmmac-0/
total 0
lrwxrwxrwx 1 root root 0 2021-01-23 13:32 device -> ../../../ff290000.ethernet
drwxr-xr-x 2 root root 0 2011-01-01 13:00 power
drwxr-xr-x 3 root root 0 2011-01-01 13:00 stmmac-0:00
drwxr-xr-x 3 root root 0 2011-01-01 13:00 stmmac-0:04
lrwxrwxrwx 1 root root 0 2021-01-23 13:32 subsystem -> ../../../../../class/mdio_bus
-rw-r--r-- 1 root root 4096 2011-01-01 13:00 uevent

找到 phy 设备 stmmac-0:04:

cd /sys/devices/platform/ff290000.ethernet/mdio_bus/stmmac-0/stmmac-0:04
ls -l
total 0
lrwxrwxrwx 1 root root 0 2021-01-23 05:23 driver -> ../../../../../../bus/mdio_bus/drivers/YT8511 Gigabit Ethernet
-r--r--r-- 1 root root 4096 2021-01-23 05:23 phy_has_fixups
-r--r--r-- 1 root root 4096 2021-01-23 05:23 phy_id
-r--r--r-- 1 root root 4096 2021-01-23 05:23 phy_interface
-rw-r--r-- 1 root root 4096 2021-01-23 05:23 phy_registers
drwxr-xr-x 2 root root 0 2011-01-01 13:00 power
lrwxrwxrwx 1 root root 0 2021-01-23 05:23 subsystem -> ../../../../../../bus/mdio_bus
-rw-r--r-- 1 root root 4096 2011-01-01 13:00 uevent

对 phy 寄存器的读写就是操作文件 phy_registers。
2) 读寄存器
cat phy_registers
3) 写 mii 寄存器
例:写 mii reg 0 为 0x9000:
echo 0x0 0x9000> phy_registers
4) 读 ext 寄存器
例:读 ext reg 0xc:
echo 0x1e 0xc> phy_registers && cat phy_registers
30: 0xc
31: 0x8052
返回值在 mii reg 0x1f(31d)里,例中为 0x8052。
5) 写 ext 寄存器
例:写 ext reg 0xc 值为 0x80f6:
echo 0x1e 0xc> phy_registers && echo 0x1f 0x80f6> phy_registers

6.2 GMAC 寄存器读写

这个依赖于不同的平台。以下以瑞芯微 rk3399 开发平台为例。

6.2.1 内存读写工具: io

注意 GMAC 的基地址是 0xff730000。GMAC 基地址可以在 DTS 文件中查到。

  1. 读 GMAC 寄存器(32 位寄存器,从偏移为 0 开始的 4 个寄存器)
    [root@cqrk3399:/]# io -4 -l 16 0xff730000 ;显示当前 gpio1 的 in/out,及值配置
    ff730000: 00000018 01024018 00000000 00000000 ;gpio1 a[1]=input, val=0
  2. 写 GMAC 寄存器(32 位寄存器,偏移地址为 4)
    [root@cqrk3399:/]# io -4 -w 0xff730004 0x0102401a; GPIO DDR 寄存器,gpio1 a[1]=output
  3. 写 GMAC 寄存器(32 位寄存器,偏移地址为 0)
    [root@cqrk3399:/]# io -4 -w 0xff730000 0x1a ; GPIO DR 寄存器,gpio1 a[1]=output 1

7. 收发包统计计数查看

在定位 phy 收发包问题时,重要的一步是分清是发送问题还是接收问题。所以查看收发包的计数可以帮
忙定位问题。

7.1 MAC 层收发包计数
7.1.1 ifconfig
ifconfig eth0 
eth0 Link encap:Ethernet HWaddr 5e:8a:8a:5b:9f:74 Driver rk_gmac-dwmac
 inet addr:192.168.1.202 Bcast:192.168.1.255 Mask:255.255.255.0 
 inet6 addr: fe80::d6ea:73da:63fa:8827/64 Scope: Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:1993 errors:0 dropped:0 overruns:0 frame:0 
 TX packets:1046 errors:0 dropped:0 overruns:0 carrier:0 
 collisions:0 txqueuelen:1000 
 RX bytes:142969 TX bytes:128206 
 Interrupt:41

这里的 RX/TX packets 表示 MAC 成功接收和发出的包数。通过多次读取并对比可以确定哪个方向有问题。

7.1.2 /proc/net/dev

Linux proc 文件系统也提供了网络设备 MAC 层的包统计信息:

cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
ip6tnl0:        0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
ip6_vti0:      0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  can0:          0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth0:          0       0    0    0    0     0          0         0     4644       0    0    0    0     0       0          0
dummy0:   0       0    0    0    0     0          0         0      560       8    0    0    0     0       0          0
ip_vti0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
    lo:             0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  sit0:           0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐