# 以太网驱动调试指南
## 概述

在计算机网络和通信中，MAC（介质接入控制）和 PHY（物理层）是两个重要的概念，它们分别涉及到数据链路层和物理层的不同功能。

MAC（Medium Access Control）是数据链路层的一部分，主要负责在共享通信介质上管理数据的传输。它确保了多个设备能够在同一个网络上有效、协调地共享通信信道，避免冲突和干扰。

MAC的主要功能
- 地址管理：在数据链路层，MAC负责为每个网络设备分配一个唯一的 MAC 地址，用以在网络中标识不同的设备。
- 帧封装和解封装：MAC 层负责将上层协议传输的数据封装成帧（Frame）。在接收端，它还会解封装数据。
- 流量控制：通过控制数据的发送速率，避免网络拥塞，确保网络的稳定运行。
- 冲突避免：在共享信道中，MAC 协议还需要解决数据发送冲突的问题。例如，在以太网中使用 CSMA/CD 协议来检测和避免数据冲突。
- 传输顺序管理：确保数据按正确的顺序传输，防止丢包和重复。

PHY（Physical Layer）是网络协议栈的最低层，负责在物理介质上传输原始数据比特流。它处理信号的传输、接收以及转换问题，并规定了网络硬件的电气和机械特性。

PHY的主要功能
- 信号编码与解码：PHY 层将数字数据转换为适合在物理介质上传输的信号格式。接收方会对信号进行解码，恢复原始的比特流。
- 比特传输：PHY 层负责将数据按比特的形式发送出去。
- 调制与解调：在无线通信中，PHY 层还包括调制和解调的过程，即将数字信号转化为适合无线电波传输的形式，并在接收端进行反向操作。
- 信道管理：PHY 层还负责物理信道的选择、管理和监控，包括信号强度、信号噪声比（SNR）等参数，以优化通信质量。

**名词解释**

| 名词 | 说明 |
| ----------- | ----------- |
| MAC | Medium Access Control，介质接入控制层 |
| PHY | Port Physical Layer，物理层 |
| MII | Media Independent Interface，一种数据链路层接口，用于连接 MAC 和 PHY |
| RMII | Reduced Media Independent Interface，简化版的 MII 接口标准 |
| GMII | Gigabit Media Independent Interface，用于千兆以太网设备的标准接口 |
| RGMII | Reduced Gigabit Media Independent Interface，对传统 GMII 接口的简化版本 |
| MDIO | Management Data Input/Output，在 MAC 和 PHY 之间进行管理控制 |



## 特点

X5 支持 MAC 10/100/1000M 以太网控制器，其特性如下

- 支持全双工和半双工操作模式
- 支持通过 RGMII 接口实现 10/100/1000 Mbps 数据传输速率
- 支持通过 RMII 接口实现 10/100 Mbps 数据传输速率
- 符合 IEEE 802.3-2015 以太网 MAC 标准，支持时间敏感网络（TSN）流量
- 符合 IEEE 1588-2008 标准，用于精准的网络时钟同步
- 支持 TCP/UDP 卸载功能，以减少 CPU 负载


## 功能描述

### 典型应用

典型连接示意图如下:

![mac_phy_connect.png](_static/_images/15-GMAC_Driver_Debug_Guide/mac_phy_connect.png)

### 功能原理

MII（媒体独立接口）是以太网设备中常见的标准接口，用于连接 MAC 层和 PHY 层。MII 定义了一组信号和协议，允许 MAC 和 PHY 之间的数据交换独立于物理媒介（如电缆或无线电波）。它使得 MAC 和 PHY 之间的交互可以在不同的物理层技术（如10Mbps、100Mbps、1000Mbps以太网）上进行。

#### RMII

MII 接口是传统以太网设备中常用的接口，用于连接 MAC（介质接入控制层）和 PHY（物理层）之间。在标准 MII 中，需要使用20条引脚来传输数据、时钟、控制信号等，这在很多应用场合可能会导致硬件成本较高。RMII 是为了解决这一问题而提出的，它通过减少信号线的数量，简化了 MII 接口，使得硬件设计更加紧凑、成本更低。

**RMII 的主要特性**

- 引脚数减少：与标准 MII 接口相比。RMII 的数据线仅需要2bit，大大减少了连接的复杂度和所需引脚数，从而降低了芯片和电路板的成本。
- 数据传输速率：RMII支持 10Mbps 和 100Mbps 的以太网传输速率。
- 时钟频率：RMII接口使用更高频率的时钟来驱动数据传输。与 MII 相比，RMII 的时钟频率通常为50 MHz，这意味着数据传输是基于每时钟周期传输两位数据。

**RMII 引脚定义如下**

| 管脚      | 描述 | 方向 |
| ----------- | ----------- | ----------- |
| REF_CLK | 发送参考时钟，速率50M | 参考时钟可以是外部时钟源，也可以是 MAC -> PHY，或者是 PHY -> MAC |
| TXD[0:1] | 发送数据线 | MAC -> PHY |
| RXD[0:1] | 接收数据线 | PHY -> MAC |
| TXEN | 发送使能 | MAC -> PHY |
| RXER | 接收错误 | PHY -> MAC |
| CRS/CRS_DV | 载波侦听/接收数据有效。当接收介质非空闲时，CRS_DV 必须被 PHY 置位 | PHY -> MAC |

#### RGMII

RGMII（Reduced Gigabit Media Independent Interface）是以太网设备中用于连接 MAC（介质接入控制层）和PHY（物理层）的接口标准，专为支持千兆以太网（Gigabit Ethernet，1Gbps）的设备设计。它是对传统 GMII（Gigabit Media Independent Interface）接口的简化版本，旨在减少硬件成本和复杂性，同时保留支持千兆速率的功能。

**RGMII 的主要特性**
- 引脚数减少：与传统的 GMII 接口相比，RGMII 通过简化设计减少了引脚数量
- 支持千兆以太网：RGMII 能够支持 1Gbps 的以太网速率
- 时钟频率：RGMII 使用125 MHz的时钟频率来传输数据

**RGMII 引脚定义如下**

| 管脚      | 描述 | 方向 |
| ----------- | ----------- | ----------- |
| TXC | 发送参考时钟，根据 PHY工作模式选择 125M / 25M / 2.5M | MAC -> PHY |
| TXD[0:3] | 发送数据线 | MAC -> PHY |
| TXCTL | 发送控制 | MAC -> PHY |
| RXC | 接收参考时钟，根据 PHY工作模式选择 125M / 25M / 2.5M | PHY -> MAC |
| RXD[0:3] | 接收数据线 | PHY -> MAC |
| RXCTL | 接收控制 | PHY -> MAC |

#### MDIO
MDIO（Management Data Input/Output）是一个用于以太网设备中的管理功能的接口标准，它是IEEE 802.3（以太网标准）中的一部分，主要用于在 MAC（介质接入控制层）和PHY（物理层）之间进行管理数据的通信。MDIO 接口通常用于读取和配置PHY的状态、速率设置、链路状态等信息。

MDIO 主要作用
- 链路状态监测：可以用来读取 PHY 的链路状态，判断物理链路是否正常、是否已经建立连接。
- 速率和双工模式配置：通过 MDIO 接口，MAC 可以设置 PHY 的工作速率（如10/100/1000Mbps）和双工模式（全双工或半双工）。
- 自协商功能：MDIO 可以用于启动或读取PHY的自协商过程，这允许设备根据网络条件自动选择最佳的工作速率和模式。
- 故障诊断：MDIO 可用于诊断 PHY 的工作状态，例如读取错误计数、诊断信息等。


## 驱动代码

### uboot 驱动说明
**注意: uboot 目前仅支持 PHY 工作模式在 RGMII**

#### uboot 设备树
X5 uboot 设备树路径位于目录`uboot/arch/arm/dts`，用户修改项目对应的设备树文件，此处以 X5 EVB 主板配置文件 `x5-soc.dtsi` 为例。MAC 与 PHY 相关配置位于节点 `x5_soc_ethernet_tsn`。如下所示

```dts
x5_soc_ethernet_tsn: gmac-tsn@35010000 {
    compatible = "horizon,sunrise5-dwmac";
    status = "okay";
    reg = <0x35010000 0x10000>;
    reg-names = "stmmaceth";
    clock-names = "stmmaceth",
            "mac-clk-tx",
            "mac-clk-rx",
            "ethstp",
            "syscfg-clk";
    clocks = <&refclk>,
        <&refclk>,
        <&refclk>,
        <&refclk>,
        <&refclk>;
    phy-mode = "rgmii-id";
    phy-handle = <&x5_soc_ethphy0>;
    max-speed = <1000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_enet &pinctrl_lsio_gpio0_31_output_normal>;

    mdio {
        compatible = "snps,dwmac-mdio";
        #address-cells = <1>;
        #size-cells = <0>;

        x5_soc_ethphy0: ethernet-phy@1 {
            compatible = "ethernet-phy-ieee802.3-c22";
            reg = <1>;
            max-frequency = <125000000>;
        };
    };
};
```
**`x5_soc_ethernet_tsn` 节点属性说明**
- `status`: GMAC 驱动使能状态，需确保值为 `okay`
- `phy-mode`: PHY 工作模式，uboot 目前仅支持 RGMII
- `max-speed`: PHY 工作速率，RGMII 对应 1000Mbps
- `pinctrl-0`: 管脚复用，此处使用示例
  - `&pinctrl_enet`: 复用为 RGMII 功能管脚
  - `&pinctrl_lsio_gpio0_31_output_normal`: PHY 复位管脚，此处使用 `lsio_gpio0_31`，用户以实际使用为准

**`x5_soc_ethphy0` 节点属性说明**
- `reg`: PHY 地址，0表示使用广播发送，非0表示对应 PHY 地址
- `max-frequency`: PHY 时钟，RGMII 使用 125M 时钟

#### uboot 驱动源码
uboot GMAC 驱动源码位于 `uboot/drivers/net/dwc_eth_qos.c`

##### 新增新的 PHY 厂商驱动的典型方法
本示例以新厂商命名为 `new phy`，用户根据实际使用的 PHY 厂商替换其命名即可。

- 在 uboot 中添加厂商驱动源码

uboot PHY 厂商驱动源码位于 `uboot/drivers/net/phy` 目录下，例如：将 `new_phy.c` 放置到该目录下。

- 修改 Makefile
修改 `uboot/drivers/net/phy/Makefile`，添加 `new phy` 源码的编译项。
```
obj-$(CONFIG_NEW_PHY) += new_phy.o
```
**注意: 需确保板级 uboot 配置文件中 `CONFIG_NEW_PHY=y`**

- 在 PHY 框架初始化过程中，增加对厂商 `new_phy` 驱动的入口调用。
修改 uboot 源码`uboot/drivers/net/phy/phy.c`，添加 `new phy` 的初始化函数。
```C
int phy_init(void)
{
...(省略代码)...
#ifdef CONFIG_NEW_PHY
	phy_new_phy_init();   // 添加厂商 new phy 的初始化函数，该函数由 new_phy.c 实现
#endif
...(省略代码)...
}
```

`new_phy.c` 将实现其初始化函数，示例如下:
```C
/* Support for NEW PHY */
static struct phy_driver new_phy_driver = {
	.name = "new phy",
	.uid = 0x12ABCD,               // 对应 new phy 的网卡 PHY ID，注意: 需要 PHY ID 匹配后才会调用对应的驱动函数
	.mask = 0xffffff,              // PHY ID 掩码，注意: PHY ID = uid & mask
	.features = PHY_GBIT_FEATURES,
	.probe = &new_phy_probe,
	.config = &new_phy_config,
	.startup = &new_phy_startup,
	.shutdown = &new_phy_shutdown,
};

int new_phy_init(void)
{
	phy_register(&new_phy_driver);

	return 0;
}
```


### kernel 驱动说明
**注意: kernel 目前支持 PHY 工作模式在 RMII 和 RGMII，默认使用 RGMII**

#### kernel 设备树
X5 kernel 设备树路径位于目录`kernel/arch/arm64/boot/dts/hobot`，用户修改项目对应的设备树文件，此处以 X5 EVB 主板配置文件 `x5-evb.dtsi` 为例。

MAC 与 PHY 相关配置位于这三个节点 `gmac_tsn`  `hobot_tsn`  `horizon_tsn`，分别对应三个驱动。

**注意: 用户使用 RGMII 推荐使用 `horizon_tsn`，使用 RMII 推荐使用 `gmac_tsn`**

下面以 `horizon_tsn` 为例说明

```dts
horizon_tsn: horizon_tsn@35010000 {
    compatible = "snps,dwc-qos-ethernet-5.10a";
    status = "disabled";
    reg = <0x35010000 0x10000>,
        <0x35050000 0x4>;
    interrupt-parent = <&gic>;
    interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
    interrupt-names = "mac-irq";
    clocks = <&hpsclks X5_HSIO_ENET_AXI_CLK>,
            <&hpsclks X5_HSIO_ENET_RGMII_CLK>,
            <&hpsclks X5_HSIO_ENET_PCLK>,
            <&hpsclks X5_HSIO_ENET_REF_CLK>,
            <&hpsclks X5_HSIO_ENET_PTP_REFCLK>;
    clock-names = "axi_clk", "rgmii_clk", "apb_clk",
                "ref_clk", "ptp_ref";
    resets = <&socrst HSIO_ENET_RESET>;
    reset-names = "enet_rst";

    snps,write-requests = <8>;
    snps,read-requests = <8>;
    snps,txpbl = <4>;
    snps,rxpbl = <4>;
    snps,clk_csr = <2>;
    snps,tso;
    snps,aal;
    //snps,fp;
    snps,force_sf_dma_mode = <1>;

    phy-mode = "rgmii-id";
    phy-handle = <&horizon_ethphy0>;

    mdio {
        compatible = "snps,dwmac-mdio";
        #address-cells = <1>;
        #size-cells = <0>;
        horizon_ethphy0: horizon_ethernet-phy@1 {
            compatible =
                "ethernet-phy-ieee802.3-c22";
            reg = <0>;
        };
    };
}
```

```dts
&horizon_tsn {
	status = "disabled";

	phy-mode = "rgmii-id";                                 // PHY 工作模式为 RGMII
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet &hsio_gpio0_16>;            // 配置复用功能: RGMII 和 复位管脚
	phyreset-gpio = <&hs_gpio0_porta 16 GPIO_ACTIVE_HIGH>; // 配置复位管脚，此处使用 hsio_gpio0_16
};
```

**`horizon_tsn` 节点属性说明**
- `status`: GMAC 驱动使能状态，需确保要使用的节点，其 `status` 值为 `okay`
- `phy-mode`: PHY 工作模式，目前支持 `rmii` `rgmii-id`
- `pinctrl-0`: 管脚复用，此处使用示例
  - `&pinctrl_enet`: 复用为 RGMII 功能管脚，若使用 RMII，需复用为 `pinctrl_enet_rmii`
  - `&hsio_gpio0_16`: PHY 复位管脚，此处使用 `hsio_gpio0_16`，用户以实际使用为准
- `phyreset-gpio`: 复位管脚，此处使用 `hsio_gpio0_16`

**`x5_soc_ethphy0` 节点属性说明**
- `reg`: PHY 地址，0表示使用广播发送，非0表示对应 PHY 地址

注意: PHY 复位管脚需确认复位为 GPIO 功能，有关 GPIO 复用配置的方法，请参考[GPIO调试指南](./10-GPIO_Debug_Guide_zh_CN.md)

#### kernel 驱动源码
kernel GMAC 驱动源码位于 `kernel/drivers/net/ethernet/stmicro/stmmac`

##### 开启 PHY 驱动
PHY 驱动位于 `kernel/drivers/net/phy` 目录，包含各个 PHY 厂商的驱动源码，以 realtek 为例，通过 menuconfig 开启 realtek PHY 驱动。

![phy_driver_realtek.png](_static/_images/15-GMAC_Driver_Debug_Guide/phy_driver_realtek.png)

##### 匹配 PHY ID
以 realtek 为例， `struct phy_driver` 数组是内核用来注册和管理多个 PHY 设备驱动的关键数据结构。它通常用于通过 phy_driver 描述多个支持的 PHY 驱动，并通过数组形式进行注册和处理。
以 RTL8211F 为例  
```C
static struct phy_driver realtek_drvs[] = {
{
    // ...(省略代码)...
    {
		PHY_ID_MATCH_EXACT(0x001cc916),              // PHY ID，可通过 datasheet 获取，驱动通过读取 register 2 和 3 获取
		.name		= "RTL8211F Gigabit Ethernet",   // 驱动名称
		.probe		= rtl821x_probe,
		.config_init	= &rtl8211f_config_init,
		.read_status	= rtlgen_read_status,
		.config_intr	= &rtl8211f_config_intr,
		.handle_interrupt = rtl8211f_handle_interrupt,
		.suspend	= genphy_suspend,
		.resume		= rtl821x_resume,
		.read_page	= rtl821x_read_page,
		.write_page	= rtl821x_write_page,
	},
    // ...(省略代码)...
}
```
当驱动匹配到 PHY ID，将显示如下打印

```
[    5.684946] hobot_gmac 35010000.horizon_tsn eth0: PHY [hobot-mac-mdio-35010000:00] driver [RTL8211F Gigabit Ethernet] (irq=POLL)
[    5.705015] hobot_gmac 35010000.horizon_tsn eth0: mac_config_rx_queues_routing, not support packet mode :
[    5.714742] hobot_gmac 35010000.horizon_tsn eth0: configuring for phy/rgmii-id link mode
```

##### PHY 驱动匹配检查
kernel 可通过 sysfs 检查当 PHY 设备匹配到的驱动。操作如下

**查看系统支持的 PHY 驱动**
系统当前支持的 PHY 驱动在目录 `/sys/bus/mdio_bus/drivers`下，以子目录形式存在。
```
root@buildroot:/sys/bus/mdio_bus/drivers# ls -al
total 0
drwxr-xr-x 24 root root 0 Jan  1 00:00  .
drwxr-xr-x  4 root root 0 Jan  1 00:00  ..
drwxr-xr-x  2 root root 0 Jan  1 00:00 'Generic Clause 45 PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'Generic FE-GE Realtek PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'Generic PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8201CP Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8201F Fast Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8208 Fast Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211 Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211B Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211C Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211DN Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211E Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211F Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8211F-VD Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8221B-VB-CG 2.5Gbps PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8221B-VM-CG 2.5Gbps PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8226 2.5Gbps PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8226-CG 2.5Gbps PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8226B_RTL8221B 2.5Gbps PHY'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8365MB-VC Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL8366RB Gigabit Ethernet'
drwxr-xr-x  2 root root 0 Jan  1 00:00 'RTL9000AA_RTL9000AN Ethernet'
```

**查看系统匹配的 PHY 驱动**

X5 系统 GMAC 驱动在目录 `/sys/bus/mdio_bus/devices/hobot-mac-mdio-35010000:00`，同样是以目录形式存在。其中 `driver` 目录是一个软连接，指向当前系统匹配到的 PHY 驱动，如下所示
```
root@buildroot:/sys/bus/mdio_bus/devices/hobot-mac-mdio-35010000:00# ls
attached_dev  driver  of_node  phy_dev_flags  phy_has_fixups  phy_id  phy_interface  power  statistics  subsystem  uevent
root@buildroot:/sys/bus/mdio_bus/devices/hobot-mac-mdio-35010000:00# ls -al driver/hobot-mac-mdio-35010000\:00/driver
lrwxrwxrwx 1 root root 0 Jan  1 00:04 driver/hobot-mac-mdio-35010000:00/driver -> '../../../../../../../../bus/mdio_bus/drivers/RTL8211F Gigabit Ethernet'
```
可看到 driver 指向 `/sys/bus/mdio_bus/drivers/RTL8211F Gigabit Ethernet` 表示当前系统匹配到的 PHY 驱动是 RTL8211F。


## 使用方法

### uboot 使用方法

#### uboot 设置静态 IP
设置 X5 uboot 为静态IP
```
Hobot>setenv ipaddr 192.168.1.10
```

#### uboot 动态获取 IP
将 X5 网口连接到路由器或 DHCP 服务器，X5 进入 uboot 后设置 DHCP 服务器 IP 地址，并通过 `dhcp` 命令获取动态IP。如下所示:

```
Hobot>setenv serverip 192.168.1.1
Hobot>setenv autoload no
Hobot>dhcp
```

#### uboot 验证 PHY 连通性
uboot下可以通过 ping 命令验证连通性，需要先设置本地 IP 地址
```
Hobot>setenv ipaddr 192.168.1.10
Hobot>ping 192.168.1.11
gmac-tsn@35010000 Waiting for PHY auto negotiation to complete..... done
Using gmac-tsn@35010000 device
host 192.168.1.11 is alive
```
如果打印出 `host 192.168.1.11 is alive` 则表示网络正常

#### uboot 读写 phy 寄存器
在 uboot 下可通过 `mii` 命令集读写 PHY 寄存器

**查看当前 mii 设备列表**
```
Hobot>mii device
MII devices: 'gmac-tsn@35010000'
Current device: 'gmac-tsn@35010000'
```
可以看到当前 uboot 下可用以及选择的 mii 设备是 `gmac-tsn@35010000`

**查看 PHY 寄存器值，并显示每一位状态**

格式 `mii dump <addr> <reg>`，参数说明如下
- `addr`: PHY 地址
- `reg`: 寄存器地址，仅支持[0:5]

**注意: 推荐使用该命令读取 PHY 标准寄存器，可以直观显示每一位状态**

例如：读取寄存器0状态
```
Hobot>mii dump 1 0
0.     (1040)                 -- PHY control register --
  (8000:0000) 0.15    =     0     reset
  (4000:0000) 0.14    =     0     loopback
  (2040:0040) 0. 6,13 =   b10    speed selection = 1000 Mbps
  (1000:1000) 0.12    =     1     A/N enable
  (0800:0000) 0.11    =     0     power-down
  (0400:0000) 0.10    =     0     isolate
  (0200:0000) 0. 9    =     0     restart A/N
  (0100:0000) 0. 8    =     0     duplex = half
  (0080:0000) 0. 7    =     0     collision test enable
  (003f:0000) 0. 5- 0 =     0     (reserved)
```

**读取 PHY 寄存器值**

格式 `mii read <addr> <reg>`

**注意: 可以使用该命令读取 PHY 所有寄存器值，包括标准寄存器和自定义寄存器**

例如：读取寄存器0状态
```
Hobot>mii read 1 0
1040
```


### kernel 使用方法

#### 设置 IP 参数
Linux 网卡通过配置文件 `/etc/network/interfaces` 配置 IP 参数
##### 设置静态 IP
设置 eth0 静态 IP 可参考如下配置
```shell
auto eth0
iface eth0 inet static          # 设置 eth0 为静态 IP
    address 192.168.1.10        # 设置静态 IP 地址
    netmask 255.255.255.0       # 设置子网掩码
    gateway 192.168.1.1         # 设置网关地址
    broadcast 192.168.1.255     # 设置广播地址
    metric 700                  # 设置 metric 值
```
##### 设置动态 IP
设置 eth0 通过 hdcp 动态获取 IP 可参考如下配置
```shell
auto eth0
iface eth0 inet dhcp
```

#### 系统常用命令

##### 查看网卡状态
```
ls /sys/class/net
```
每个网卡以子目录形式存在 `/sys/class/net` 目录下，每个目录下包含其可配置参数文件，用户可通过该目录下的节点，配置或查看网卡的状态。

常用配置文件如下

| 参数文件      | 描述 |
| ----------- | ----------- |
| address | MAC地址 |
| broadcast | 广播地址 |
| carrier | 物理连接状态，1代表已连接，0代表未连接 |
| carrier_changes | 记录网卡连接状态变化的次数 |
| dev_id | 用于系统中网卡设备的唯一标识 |
| duplex | 显示网卡的工作模式，`full` 表示全双工，`half` 表示半双工 |
| mtu | 最大传输单元，单位字节 |
| speed | 网卡速率，单位Mbps |
| tx_queue_len | 网卡的传输队列长度，在网络高负载时，调整该值可以影响发送性能 |
| statistics | 网络接口的详细统计信息，用于诊断网络问题 |


##### 打开/关闭 eth0
```
ifconfig eth0 up         # 打开 eth0
ifconfig eth0 down       # 关闭 eth0
```

##### 配置 eth0 参数
```
ifconfig eth0 192.168.1.10                  # 配置静态 IP
ifconfig eth0 hw ether 00:11:22:aa:bb:cc    # 设置 MAC 地址
ifconfig eth0 netmask 255.255.255.0         # 设置子网掩码
route add default gw 192.168.1.1            # 添加网关
```

#### ethtool
ethtool 用于查询和设置网卡参数的命令行工具。它允许用户查看网卡的配置、运行状态、以及支持的特性，并且可以修改某些设置，如网络速率、双工模式、启用/禁用特性等。ethtool 是一个非常强大的工具，广泛用于网络管理员和开发人员进行网络设备的管理和调试。

##### 查看网卡状态
下面以 eth0 为例，并简单说明下输出信息含义

```shell
# ethtool eth0
Settings for eth0:
        Supported ports: [ TP MII ]
        Supported link modes:   10baseT/Full                  # 当前网卡支持的能力
                                100baseT/Full
                                1000baseT/Full
        Supported pause frame use: Symmetric Receive-only
        Supports auto-negotiation: Yes                        # 支持自动协商
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Full                  # 广播的连接模式
                                100baseT/Full
                                1000baseT/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes                      # 自动协商开启
        Advertised FEC modes: Not reported
        Link partner advertised link modes:  10baseT/Half 10baseT/Full
                                             100baseT/Half 100baseT/Full
                                             1000baseT/Full
        Link partner advertised pause frame use: Symmetric Receive-only
        Link partner advertised auto-negotiation: Yes
        Link partner advertised FEC modes: Not reported
        Speed: 1000Mb/s                # 当前网卡速率
        Duplex: Full                   # 网卡工作模式
        Port: Twisted Pair
        PHYAD: 0                       # PHY 地址
        Transceiver: external
        Auto-negotiation: on
        MDI-X: Unknown
        Supports Wake-on: ug
        Wake-on: d
        Link detected: yes
```

##### 网卡统计信息
`ethtool -S eth0` 显示网卡的详细统计信息，如接收字节数、发送字节数、丢包数、错误数等，有助于网络管理员诊断网络性能、错误和流量问题，常用的统计项如下

**接收统计信息**
- rx_packets：接收到的数据包总数。
- rx_bytes：接收到的字节总数。
- rx_errors：接收过程中发生的错误数量。例如，CRC 错误、帧错误等。
- rx_dropped：接收到的数据包被丢弃的数量。可能因为缓冲区溢出或其他原因导致数据包丢失。
- rx_fifo_errors：接收队列溢出错误的数量。表示接收 FIFO 队列已满，数据包无法处理。
- rx_length_errors：接收数据包的长度错误（如超出最大长度）的数量。
- rx_crc_errors：接收过程中的CRC错误数。表示数据包在传输过程中发生了数据损坏。

**发送统计信息**
- tx_packets：发送的数据包总数。
- tx_bytes：发送的字节总数。
- tx_errors：发送过程中发生的错误数量。例如，校验和错误、设备错误等。
- tx_dropped：发送的数据包被丢弃的数量。通常发生在网络拥堵或设备资源不足时。
- tx_fifo_errors：发送队列溢出错误的数量。表示发送 FIFO 队列已满，数据包无法传送。
- tx_collisions：发生的碰撞次数（在以太网中，只有在半双工模式下可能出现）。
- tx_carrier_errors：发生的载波错误数量，通常与链路层的物理连接问题有关。

##### 设置网卡速率与工作模式
设置网卡速率为 1000Mbps，并启用全双工
```
ethtool -s eth0 speed 1000 duplex full autoneg off
```

#### 网卡速率测试
uboot 没有完整的协议栈，所以速率/模式测试建议在 kernel 下进行。

**注意: 测试速率需要将网卡切换到不同模式，可以调整对端的速率并最终通过协商达到目标速率/模式，也可以通过 ethtool 强制切换指定的速率/模式，并使用 iperf 进行速率测试**

下面使用 1000M 全双工进行速率测试。

- 设置网卡速率为 1000Mbps，并启用全双工
```
ethtool -s eth0 speed 1000 duplex full autoneg off
```

- PC 端启动 iperf3，作为 server 等待板端连接
```
> .\iperf3.exe -s
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
```

- 板端作为 client 进行速率测试
```
# iperf3 -p 5201 -c 192.168.1.11
Connecting to host 192.168.1.11, port 5201
[  5] local 192.168.1.10 port 52942 connected to 192.168.1.11 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   114 MBytes   956 Mbits/sec    0    345 KBytes
[  5]   1.00-2.00   sec   113 MBytes   950 Mbits/sec    0    345 KBytes
[  5]   2.00-3.00   sec   113 MBytes   947 Mbits/sec    0    345 KBytes
[  5]   3.00-4.00   sec   113 MBytes   949 Mbits/sec    0    345 KBytes
[  5]   4.00-5.00   sec   113 MBytes   950 Mbits/sec    0    345 KBytes
[  5]   5.00-6.00   sec   113 MBytes   949 Mbits/sec    0    345 KBytes
[  5]   6.00-7.00   sec   113 MBytes   950 Mbits/sec    0    345 KBytes
[  5]   7.00-8.00   sec   113 MBytes   951 Mbits/sec    0    345 KBytes
[  5]   8.00-9.00   sec   113 MBytes   947 Mbits/sec    0    345 KBytes
```
可以看到速率满足要求

**注意: 其他模式/速率请参考以上方法，此处不做赘述**

## 常见问题
### 网卡问题速查
与 PHY 相关的网络问题主要分为网络不通或丢包严重，可以参考以下方法速查

![phy_error_check.png](_static/_images/15-GMAC_Driver_Debug_Guide/phy_error_check.png)

### 加载网卡提示 "Cannot attach to PHY"
错误信息如下
```
root@ubuntu:~# ifconfig eth0 up
[  222.582785] dwc-eth-dwmac 35010000.gmac-tsn eth0: __stmmac_open: Cannot attach to PHY (error: -19)
SIOCSIFFLAGS: No such device
```
网卡 MDIO 通信失败，可按照以下思路排查
- 网卡供电是否正常
- 复位管脚是否复用成 GPIO，复位时序是否满足 datasheet 要求，一般 PHY 要求复位管脚拉低一定时长才是有效复位
- MDIO 通信是否异常，例如是否有波形，MDC 速率是否满足要求（一般不超过2.5M）

### MAC 复位失败"
uboot 下有如下打印
```
EQOS_DMA_MODE_SWR stuck
```

Kernel 在 link up 网卡时提示 "DMA engine initialization failed
错误信息如下  
![eth0_error_dma_init_failed.jpg](_static/_images/15-GMAC_Driver_Debug_Guide/eth0_error_dma_init_failed.jpg)

原因分析: 一般都是 MAC 复位失败，通常是因为没有 RGMII-RX 时钟导致，可按以下思路分析
- 检查是否有参考时钟，时钟频率、幅值是否满足要求
- 检查 PHY 供电是否正常，检查 PHY 复位管脚
- 检查 PHY datasheet，是否特殊寄存器配置，例如在给出 RGMII-RX 时钟 前需要进行必要的寄存器配置


### 自协商失败"
分析方法
- 通过交叉对比，判断是本地还是对端问题
- uboot 下协商失败，可以尝试延长 timeout 看是否改善
- `ethtool eth0` 查看板端和对端的 PHY 协商能力是否与期望的一致，是否板端或者对端限制了自协商

### uboot / kernel 无法 ping 通
- 使用第三方设备、线缆进行交叉验证，排除对端或者线缆问题，最好是直连测试，不要通过路由器或交换机
- 检查 uboot 是否正确设置了 `ipaddr`，确保和对端在同一网段，同时避免 IP 地址冲突
- 检查 kernel 是否正确设置了 ip、子网掩码，确保和对端在同一网段，同时避免 IP 地址冲突
- 对端进行抓包分析
  - 如果收到板端发出的 ARP 包，但是对端没有回 ARP包，需检查 IP 冲突问题
  - 如果 ARP 包交互正常，可以收到 ICMP 包，但是没有回复 ICMP 包，需排查对端网络配置策略。例如确保 windows 防火墙关闭，是否开启 ICMP 入站规则等等。

![phy_error_check_icmp.png](_static/_images/15-GMAC_Driver_Debug_Guide/phy_error_check_icmp.png)


### 丢包严重或者大量收发报错
分析方法
- 眼图测试信号质量是否满足要求。
- 确认 PHY 是否使能了 clock delay。
- 测量时钟是否稳定。
- `ethtool -S eth0 | grep crc` 可以统计由于 CRC 错误而丢弃的包，如果该值随着时间大量增加，大概率是信号完整性问题。


