mdio-tool 简介:源码获取、编译安装、基本命令格式解析

咱们做嵌入式调试,最常打交道的就是 PHY 芯片了。驱动挂不上、link 起不来、协商模式不对……调 PHY 寄存器几乎是每天的家常便饭。这时候如果手边有把趁手的工具,效率能高不少。

mdio-tool 就是这么一个小工具。它不花哨,但很实用——直接通过 MDIO 总线读写 PHY 寄存器,省得你每次插网线、再跑一堆 ethtool 看半天。我个人习惯在移植新板子时,第一件事就是把 mdio-tool 装好,然后一个个读 PHY 的 ID 寄存器,确认硬件通了再碰驱动。

这一节咱们就把它搞到手,装好,再学会最基本的命令格式。

源码获取

mdio-tool 的代码在 GitHub 上有好几个版本,我个人用的是下面这个(长期维护,跟内核小版本兼容性比较好):

git clone https://github.com/wtarreau/mdio-tool.git
cd mdio-tool

为什么推荐这个版本?因为它对较新内核(4.x ~ 6.x)的 /sys/class/mdio_bus 接口适配得最好。我曾在某项目里用过另一个 fork,结果 5.10 内核下怎么都读不到寄存器,折腾了一下午才发现是路径硬编码的事——换个版本就解决了。

你拿到代码后,可以先看一眼 README,里面通常会说明依赖的内核配置选项(比如 CONFIG_MDIO_DEVICE、CONFIG_PHYLIB)。如果你的内核没开这些宏,那后面就算编译通过,运行时也会报 No such device。

建议在获取源码前,先确认目标内核版本。uname -r 看一眼,再根据 README 的提示选择合适的 tag 或分支。

编译安装

编译过程不复杂,但有几个坑。先装好编译依赖:

sudo apt install build-essential linux-headers-$(uname -r)   # Debian/Ubuntu
sudo yum install gcc make kernel-devel                       # CentOS/RHEL

接着直接 make:

make
sudo make install   # 默认装到 /usr/local/bin

如果只编译不安装,二进制在当前目录下,叫 mdio-tool。我个人习惯先用 ./mdio-tool -h 测试一下,确认可执行后再装到系统路径。

我曾经在一个嵌入式板子上编译时卡了很久,原因是内核头文件路径不对。交叉编译环境下,linux-headers 的路径跟本地机器不一样,你得手动指定 KERNEL_DIR:

make KERNEL_DIR=/path/to/your/kernel/build

否则编译时就报 linux/mdio.h: No such file or directory。嗯,这个头文件其实就在内核源码里,不是系统库。

交叉编译时,务必确认 KERNEL_DIR 指向的是已配置过的内核源码目录(且 include/generated/autoconf.h 存在)。否则 mdio-tool 可能缺少 CONFIG_ 宏定义,运行时会找不到 mdio 总线节点。

基本命令格式解析

装好后,咱们来看看怎么用它。基本命令格式非常简洁:

mdio-tool [options] <phy_addr> <reg_addr> [value]
  • phy_addr:PHY 芯片的 MDIO 地址,通常是 0~31。这个地址由 PHY 芯片的硬件引脚(如 ADDR0~ADDR4)决定,也可能是片选后的映射地址。
  • reg_addr:寄存器地址,范围 0~31(标准 IEEE 802.3 寄存器),或者 0~0x1F(扩展寄存器)。
  • [value]:写操作时指定的值,16 位。如果省略该参数,则执行读操作。

常用选项如下表:

选项 说明 示例
-r 读操作(默认模式,可省略) mdio-tool -r 0 1
-w 写操作 mdio-tool -w 0 0 0x1140
-v 详细输出,显示总线路径等信息 mdio-tool -v -r 0 1
-b <bus> 指定 MDIO 总线设备(默认查找第一个) mdio-tool -b mdio@ffe24000 -r 4 2
-h 显示帮助 mdio-tool -h
记住一个原则:读不加 -w,写必须加 -w 且给出 value。不然工具会默默认为你想读,然后给你一堆 0xffff——你想想看,这要是写错了,PHY 配置就飞了。

举个完整的读例子,读取 PHY 地址 2 的寄存器 0(BMCR,基本控制寄存器),看看当前是否处于软件复位状态:

mdio-tool -r 2 0

输出可能像 0x1140。如果你想把它软复位一下,写值 0x8000(bit15 置位):

mdio-tool -w 2 0 0x8000

之后再读一次,确认 bit15 是否自动清除了。正常情况下 PHY 复位完成后会清掉该位。

为什么建议用 -v 跑一次?因为它会打印出工具实际使用的 sysfs 路径,比如 /sys/class/mdio_bus/mdio@.../。我曾在 SPI 转 MDIO 的板子上用默认参数死活读不到东西,加 -v 一看才发现总线名称是 spi_mdio,不是 mdio@...,只能手动 -b 指定——差了一个字母,结果大不相同。

下面这张图帮你快速理解 mdio-tool 的数据流向:

mdio-tool 工作流程 用户 (User) mdio-tool sysfs MDIO 总线 PHY 1. 用户调用 mdio-tool;2. 工具通过 sysfs 找到对应 mdio 总线设备;3. 内核驱动通过 MDIO 总线读写 PHY 寄存器;4. 结果沿原路返回。
如果你发现 mdio-tool 读出的寄存器值全为 0xffff,大概率是 PHY 地址不对,或者 MDIO 总线根本没连上。先用 -v 确认 sysfs 路径是否存在,再用示波器抓 MDC/MDIO 引脚看有没有波形。

好了,工具拿到手、装好、基本命令也清楚了。下一小节咱们会深入 MDIO 的协议细节,但你可以先拿手边任意一块开发板,试读 PHY ID 寄存器(地址 2 和 3),看看芯片型号跟你硬件文档是否一致——调试的第一步,永远是确认通信是通的。