十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RTL8306MB交换芯片驱动开发实战:RMII接口调试陷阱与寄存器配置指南

RTL8306MB交换芯片驱动开发实战:RMII接口调试陷阱与寄存器配置指南 去年一个网关项目用了 RTL8306MB 做五口百兆交换芯片主控和它之间走 RMII 接口。当时想的是这颗料很成熟驱动无非就是 MDIO 读写寄存器、配一下 VLAN半天怎么也能跑通。结果真正调起来才发现RMII 这个口才是整个方案最容易翻车的地方。前前后后折腾了三天最后定位到的问题说穿了都是些“寄存器里藏着的小开关”和“电路设计时的隐性约束”但如果没有踩过一遍光靠看 datasheet 很难一次定位准。这篇文章就把这次 RTL8306MB 驱动开发过程里的关键环节和真实踩坑记录整理出来。不管你是正在用这颗芯片做 Linux 驱动开发还是在嵌入式 RTOS 环境下做交换芯片适配甚至是做 LiteOS、RTOS 这类轻量系统的驱动移植RMII 接口的调试逻辑都是相通的。看完之后至少能帮你省下两天查资料、翻手册、抓波形的时间。1. 项目背景与整体架构1.1 RTL8306MB 是什么样的芯片RTL8306MB 是瑞昱Realtek一颗面向百兆接入的交换芯片典型配置是 5 个端口其中包含内置的 PHY。也就是说外接网口的物理层收发器已经集成在芯片内部了外围电路比“MAC 独立 PHY”的方案要简洁不少。和常见的 RTL8306M、RTL8305N 相比8306MB 最大的特点是支持通过 RMII 接口和外部 CPU 相连芯片内部会有一个 CPU 端口用于和主控之间交换数据。这颗芯片在市场上使用范围很广比如工业路由器、物联网网关、带多网口的小型终端设备经常能看到它的身影。原因也很直接五口百兆带交换功能成本不高驱动做熟之后稳定性也还行。但它毕竟不是那种“上电就能用”的消费级芯片至少 CPU 口和内部 PHY 之间默认处于什么状态以及外部的 RMII 接口需要怎么初始化这些都需要驱动代码明确去配置。1.2 为什么选择 RMII 接口板子主控本身自带以太网 MAC型号是某家国产 SoC支持 RMII 接口。当时选 RMII 而没有选 MII主要考虑两个因素。一是引脚数量少。MII 接口需要 16 根左右的信号线RMII 只要 9 根左右PCB 布线上省了很多事对于一款小尺寸网关板卡来说少一组信号线就意味着可以少打一层板或者降低布线密度。二是主控侧只有 RMII 接口硬件上没有选择余地。RMII 的通信机制可以理解为“用普通速率一半的时钟跑出同样的带宽”。以太网 100Mbps 时MII 用的是 25MHz 时钟、4 位数据位宽RMII 把数据位宽减半变成 2 位为了保持同样带宽时钟频率翻倍到 50MHz。所以你在 RMII 接口上看到的 REF_CLK 永远是 50MHz10Mbps 模式下它还是 50MHz只是收发逻辑按比例做了分频处理。1.3 系统连接方式和驱动整体框架从整体链路看主控 SoC 的 MAC 通过 RMII 信号线连接到 RTL8306MB 的 CPU 端口交换芯片负责剩下的 LAN 端口和 WAN 端口数据交换。驱动初始化时主控需要通过 MDIO/MDC 两根线去访问 RTL8306MB 内部寄存器。比较特殊的是RTL8306MB 实际上是把整个交换芯片的核心寄存器空间映射到了某个 PHY 地址下面访问方式还是标准的 MDIO 协议。驱动层面的工作大致分为三块初始化 MDIO 访问通道确保能稳定读写芯片寄存器配置 CPU 端口的 RMII 模式、速率、双工模式以及 CPU 口和其他端口之间的转发关系配置 VLAN、端口隔离、LED 等业务相关功能。听起来不复杂但调试时牵扯到的细节非常多。比如 RMII 信号线上时序稍微有点偏差表现出来就是芯片能 link 上、寄存器也能读但收包收不到或者收包全是 CRC 错。这类问题光看代码看不出毛病必须结合硬件设计去排查。提示如果你是在 Linux 内核下做驱动建议把 MDIO 访问封装成独立的读写函数初始化流程里每一步都加打印。后续排查寄存器配置问题会节省大量时间。2. RMII 接口的核心技术要点2.1 逐条梳理 RMII 信号线和作用很多第一次接触 RMII 的工程师容易把注意力都放在寄存器配置上结果硬件上信号接错了还浑然不知。RMII 接口相比 MII 精简了不少信号线但每一条都有自己的脾气。先列出核心信号TXD[1:0]发送数据线双位宽。100M 模式下每个 REF_CLK 周期发送 2 bit。TX_EN发送使能。MAC 向交换芯片发送数据时拉高空闲时拉低。注意有些方案里也要求 TX_EN 在发送结束后有一个延迟释放的过程这个细节会和后面的吞吐量问题有关。RXD[1:0]接收数据线同样双位宽。CRS_DV载波侦听和数据有效指示。RMII 协议里这个信号既表示链路忙也负责在接收数据时指示数据有效。部分 PHY 芯片支持 CRS_DV 复用为 RX_DV具体要看对接芯片的信号定义。REF_CLK50MHz 参考时钟所有信号都对齐这个时钟。MDC/MDIO管理接口用来读写寄存器。这里有一个容易踩的坑MDIO 和 MDC 虽然是管理接口但因为 RMII 所有信号都和 REF_CLK 建立时序关系所以 MDC 的频率不能想设多高就设多高。规范建议 MDC 不要超过 2.5MHz有些主控默认配置跑十几兆也能用但实际测试中会偶发读写异常尤其是长时间高低温下问题更容易冒出来。2.2 REF_CLK 时钟源方案的选择RMII 接口的 REF_CLK 是整个链路能否正常工作的前提。你首先要确认的一件事是50MHz 时钟到底由谁产生、从哪根线进来。常见的方案有三种外部有源晶振直接给 MAC 和交换芯片同时供时钟主控 MAC 作为时钟源输出 50MHz 给交换芯片交换芯片作为时钟源输出 50MHz 给主控 MAC。RTL8306MB 这颗芯片CPU 端口的 RMII 时钟既可以自己向外输出也可以接受外部输入具体由相关引脚的上拉/下拉状态决定。设计硬件时一般会固定选择一种方式但驱动调试时最好先确认清楚因为这个配置错了表现出来的现象就是完全不 link而且不会有人告诉你问题出在时钟方向。我当时用的方案是主控输出 50MHz 给交换芯片作为 REF_CLK。这样做的好处是主控对时钟的相位可控性更强但代价是必须在 MAC 侧开启时钟输出功能并且在设备树或驱动初始化里配置对应的时钟管脚复用。2.3 RX 路径上的建立保持时间和内部延迟RMII 之所以会成为调试陷阱的重灾区根源在于它的时序余量非常紧。数据位宽只有 2 bit50MHz 时钟一个周期 20ns数据要在这么窄的时间窗口内被正确采样。如果 PCB 走线长度差异导致 TX 数据和 REF_CLK 之间的延时变大或者芯片内部的采样点设置不合适就会出现数据采错的问题。具体表现就是链路能起来发送也能发出去但接收方向丢包极其严重或者收到的报文 CRC 错误。RTL8306MB 内部提供了一个 RX 延迟调整的寄存器位用来决定采样点相对时钟边沿的位置。有些版本还支持 TX 路径的延迟补偿。这个问题的调试方法是先用示波器量 REF_CLK 和 RXD 数据线上信号的建立保持关系判断是整体走线等长做得不够还是芯片内部采样点问题如果是采样点问题调整芯片内部 RX 延迟寄存器反复发包测试错误包比例。一个直接可用的判断标准是正常 100M 带宽下从 CPU 口向 LAN 口 ping 大包比如 1400 字节以上连续 ping 几百个包不应该有超过万分之一的丢包。如果丢包明显有规律性基本就是采样时序问题。2.4 MAC 侧和 PHY 侧的工作模式对齐RMII 接口还有一个隐藏属性MAC 侧和 PHY 侧必须工作在同一速率和双工模式。这个说法听起来像是废话但 RTL8306MB 的特殊之处在于它的 CPU 口可能默认不自适应也不会主动和 MAC 协商。调试时先在 PHY 状态寄存器里确认当前 PHY 是否工作在 100M 全双工再在主控 MAC 侧确认同样的参数。两边参数不一致时尤其是主控 MAC 被配置为 100M 半双工而 PHY 是 100M 全双工表现就是流量有一点但断断续续吞吐极低ping 还能通传大文件必失败。我当时就遇到过这种问题一开始还怀疑是 DMA 描述符配置出了问题折腾了好一阵才想到去核对两边的双工模式。3. 驱动开发完整流程与寄存器配置3.1 MDIO 访问通道的软件实现RTL8306MB 的寄存器空间访问依赖标准 MDIO 协议主控通过 MDC 时钟线向 MDIO 数据线写入地址和数据。如果你的主控自带 MDIO 控制器那直接用内核提供的 PHY 读写接口就行。但如果主控没有专门控制器或者你想提高排障灵活性用 GPIO 模拟 MDIO 协议是最快的办法。下面是一个基于 GPIO 位操作的 MDIO 读写核心实现我把它贴出来供参考static void mdio_phy_write(unsigned int addr, unsigned int reg, unsigned int val) { int i; // 发送前确保 MDIO 和 MDC 均为低 mdio_set_dir(MDIO_OUT); /* 32 位前导码MDIO 规定以 32 个 1 开始 */ for (i 0; i 32; i) { mdio_send_bit(1); } /* 起始码 01 */ mdio_send_bit(0); mdio_send_bit(1); /* 操作码: 01 表示写 */ mdio_send_bit(0); mdio_send_bit(1); /* PHY 地址 */ for (i 4; i 0; i--) mdio_send_bit((addr i) 1); /* 寄存器地址 */ for (i 4; i 0; i--) mdio_send_bit((reg i) 1); /* 写操作后续 2 位 TA先发一个高阻位再发 0 */ mdio_set_dir(MDIO_OUT); mdio_send_bit(1); mdio_send_bit(0); /* 16 位数据 */ for (i 15; i 0; i--) mdio_send_bit((val i) 1); /* 释放总线 */ mdio_set_dir(MDIO_IN); }读操作的原理类似只是操作码换成 10TA 段总线转为输入方向。实际用 GPIO 模拟时唯一需要注意的就是 MDC 时钟翻转不能太快在低速主控上没关系但如果你用较高的主频直接翻转 GPIO有些交换芯片会受不了。3.2 初始化流程和关键寄存器配置RTL8306MB 驱动初始化的顺序很重要我建议按这个流程执行第一步先读芯片的 Device ID 寄存器确认 MDIO 访问通路是好的。如果读不到 ID先别急着配寄存器而是去查硬件连接和时钟输出。第二步是软件复位芯片。复位完成后等待几十毫秒确保内部状态机就绪。第三步是配置 CPU 端口。这里面要关注端口控制寄存器中的接口模式位把 CPU 口设置为 RMII 模式。同时设置速率和双工模式为 100M 全双工。第四步是配置转发表项。RTL8306MB 内部有一张地址学习表正常情况下它会自动学习 MAC 地址并完成转发。但如果初始化时把某个端口配置为隔离状态CPU 口和 LAN 口之间就不通。这时候需要在端口控制寄存器里把隔离位关掉。第五步是检查 LED 和中断引脚的状态如果系统不用这些功能最好在初始化时关闭相关中断使能避免脏中断反复打扰 CPU。初始化之后主控侧再启动网络接口正常情况下就能通过 RMII 链路和交换芯片通信了。3.3 VLAN 和端口隔离的基础设置RTL8306MB 支持 802.1Q VLAN端口可以设置为 trunk 口或者 access 口。做网关类产品时常用的一种配置是WAN 口独立一个 VLANLAN 口共享一个 VLANCPU 口以 trunk 方式同时透传两个 VLAN。寄存器层面其实就是在 VLAN 表里配置端口成员关系和默认 VLAN ID。需要注意的事情有两点VLAN 表配置要遵守“先写后使能”的顺序否则中间状态可能导致网络瞬时不通如果只做了端口隔离而没有正确配置 VLANCPU 口发出的广播包不会按预期转发到 LAN 口。我在实际项目里就遇到过广播风暴的问题。当时 CPU 口和 LAN 口默认不在同一个广播域看起来所有端口都 link 了但 PC 接上 LAN 口就是无法获取 IP 地址。排查到最后才发现是端口隔离位默认是开启的驱动初始化时没有主动去清除。4. RMII 接口调试陷阱实录这一章是全文的核心我把这次调 RTL8306MB 过程中踩过的几个典型问题都写出来。每一个问题都附上排查思路和最终解决办法方便你以后遇到同类问题直接对照。4.1 陷阱一RX 内部延迟位没开启接收方向大面积丢包现象板卡上电后主控 MAC 和 RTL8306MB 都成功 link寄存器也能正常读写。从主控 ping 接在 LAN 口上的 PC小包能通但一旦 ping 大包比如 1200 字节以上丢包率超过一半。用 iperf 测试 TCP 带宽只有不到 10Mbps。排查过程先怀疑是 PCB 走线问题。RMII 数据线在板子上走了大概 3 厘米REF_CLK 到两个芯片的走线虽然没做严格的等长要求但差分做了短线处理看起来不至于差到这么严重。用示波器抓 RXD 数据线上的波形发现数据采样窗口确实偏窄但建立时间还有几个纳秒的余量理论上不应该丢包这么严重。后来查 RTL8306MB 的寄存器手册发现 RX 路径内部有一个延迟配置位默认值是把采样点设在时钟边沿附近当年的测试条件比较理想但实际布局布线后星型连接导致电容负载变大采样点就对不上了。解决方案把对应寄存器中的 RX 延迟位从默认值修改为增加延时的档位。改完后反复 ping 大包丢包率降到零iperf 测试带宽也恢复了正常。从经验上说RMII 模式下如果遇到“小包能通、大包丢包”的情况优先检查 RX 采样延迟和 TX 延迟配置这个优先级比检查 DMA 或者中断要高得多。注意RTL8306MB 不同批次的芯片默认延迟档位可能有差异。同一套驱动在这种板子上没问题换一批芯片可能又要重新调。建议把延迟档位做成可以动态修改的变量调试时通过命令调试接口快速切换不需要编译固件就能测试出最优档位。4.2 陷阱二MDIO 读不到 Device ID怀疑芯片损坏现象上电后读 RTL8306MB 的 Device ID 寄存器返回全 F也就是 0xffff。换一颗芯片问题依旧。用示波器抓 MDC 和 MDIO 波形发现 MDC 有时钟MDIO 读操作时也有数据返回不是一直拉高。排查过程这里容易陷入一个误区读不到 ID 不是 MDIO 协议本身的问题而是芯片的 MDIO 访问还没有被激活。RTL8306MB 有一个专门的模式配置引脚用于决定芯片工作在“MDIO 可访问”还是“直接 EEPROM 配置”模式。如果硬件上这个引脚的状态不对MDIO 接口是接收不到正确的地址映射的。还有一个原因是复位引脚没有正确释放。芯片复位后需要等待一段时间寄存器才稳定但这个时间通常只有几十毫秒不会导致完全读不到。真正棘手的还是模式引脚。解决方案核对硬件原理图发现模式配置引脚接了一个上拉电阻而在另一版参考设计里这个引脚是下拉到地的。调整成和参考设计一致的接法后再读 Device ID就正常了。这个事情给我一个教训调试交换芯片时如果 MDIO 读不到 ID第一反应不应该是软件问题而是去核对硬件上的模式配置引脚。这类引脚在原理图里往往看起来不起眼但它们决定了芯片会不会把寄存器空间映射到 MDIO 协议上。4.3 陷阱三MAC 和 PHY 双工模式不匹配现象系统启动后网络接口 link 状态正常ping LAN 口电脑也能通但吞吐量奇低只有几 Mbps。测试 TCP 传输时界面上的速度跳动非常大还会频繁出现接收窗口减小的告警。排查过程先用 ethtool 查看主控 MAC 的配置显示 100M full duplex。再通过 MDIO 读 RTL8306MB 的 PHY 状态寄存器发现 CPU 口状态是 100M half duplex。两边一个全双工一个半双工形成冲突。原因是我在初始化时只设置了速率没有单独设置双工模式。有些 PHY 会自动检测但 RTL8306MB 的 CPU 口并不会根据 MAC 侧状态自动匹配双工必须把双工模式明确写进寄存器。解决方案在初始化代码里把 CPU 端口的双工模式寄存器也一并配置为全双工。重新加载驱动后ethtool 显示两边都是 100M full吞吐量恢复正常。调试这个问题的关键点是不要只看 link 亮没亮还要分别确认 MAC 和 PHY 的状态寄存器。两者不一致时系统通常还处于“能通但通不好”的状态很容易误导排查方向。4.4 陷阱四发包后 TX_EN 拉高时间异常导致的半双工重传现象有一个版本的固件在配置 RMII 接口后TCP 下载方向速率正常但上传方向经常出现超时重传。在局域网内两台设备之间传文件上传速度只有下载速度的一半不到。排查过程用逻辑分析仪抓 TX_EN 和 TXD 波形发送一个完整的以太网帧时发现 TX_EN 在最后一个数据周期结束后立刻拉低紧接着下一个帧的 TX_EN 又重新拉高。理论上这个波形是正常的但 RTL8306MB 内部对 TX_EN 释放边沿有一个最小时间要求频繁背靠背发包时容易触发内部的 carrier 冲突检测导致交换芯片认为发送过程中发生了冲突从而丢弃部分数据包。解决方案在驱动初始化中找到 TX_EN 延迟释放相关的配置位把释放延时设为规范要求的最小值以上。重新调试后上传方向的吞吐量恢复正常。这个问题在普通流量压力不大时几乎不会被发现但一旦做长时间恒速压测问题就会以“偶发性重传”的形式暴露出来。排查网络问题时容易被误判为线缆质量或者 CPU 中断负载过高。4.5 陷阱五设备树里时钟频率配置错误导致 REF_CLK 没有输出现象系统启动后主控侧 ifconfig 能看到 eth0但状态一直是 down强制 up 之后也只能看到 carrier 不存在RTL8306MB 侧也一直无法 link。排查过程先用示波器量主控输出的 REF_CLK发现这个引脚的时钟信号根本没有输出。进系统查看设备树发现 RMII 时钟在设备树里被配置成了 25MHz。主控在初始化 MAC 时根据设备树配置去设置时钟分频结果 50MHz 的 REF_CLK 自然不在预期状态。解决方案把设备树里的 RMII 时钟频率配置改为 50000000即 50MHz重新编译烧录后REF_CLK 正常输出链路也起来了。这个问题对于熟悉 Linux 设备树的人来说不算难但如果你的驱动代码直接在寄存器里配置了 RMII 模式却漏掉了设备树里的时钟频率设置排查起来会很绕。嵌入式的驱动开发经常会遇到这种“寄存器配置没问题但设备树已经把默认参数悄悄改掉”的情况。5. 常见问题速查表与排查技巧5.1 问题速查表我把这次调试中遇到的和朋友项目里反馈过的问题整理成一个速查表方便你对照排查。现象可能原因排查方法解决措施完全无法 linkREF_CLK 没输出或频率不对示波器量时钟引脚核对设备树时钟频率检查模式引脚MDIO 读不到 Device ID模式配置引脚错误或复位未释放核对硬件原理图复位时序调整模式引脚电平延长复位等待时间小包通、大包丢RMII RX 采样延迟设置不匹配抓 RXD 波形调整延迟档位修改 RX 延迟寄存器反复 ping 大包验证链路通但吞吐极低MAC 和 PHY 双工模式不一致检查两端状态寄存器明确配置双工模式为一致长传大量重传TX_EN 释放时序不当逻辑分析仪抓发包波形配置发送使能延迟释放时间端口间无法通信VLAN/端口隔离配置错误检查端口寄存器配置清除隔离位重新配置 VLAN 表CRC 错误包极多REF_CLK 抖动大或走线过长测试时钟抖动检查走线等长调整时钟源优化 PCB 走线5.2 高效的 RMII 问题定位顺序根据这次调试的经验我总结了一个比较高效的排查顺序遇到问题先按这个顺序来基本可以少走弯路。第一步确认时钟。没有正确的 REF_CLK后面全是空谈。先量频率再看幅度最后看波形是否干净。第二步确认 MDIO 通路。读取芯片的 Device ID 和关键状态寄存器确保能控制芯片。第三步确认 RMII 信号线是否存在采样时序问题。通过 ping 大包和 iperf 做压力测试一旦出现规律性丢包优先怀疑内部延迟配置。第四步确认 MAC 和 PHY 的参数对齐。重点看速率和双工模式。第五步再去看业务相关的 VLAN、端口隔离、广播域等配置。很多工程师习惯先怀疑驱动逻辑再怀疑硬件。但对于 RMII 这种接口来说顺序应该反过来先确认硬件电气状态再回头查代码。5.3 调试工具和辅助手段现场排障时示波器和逻辑分析仪是必备的。示波器主要用于量 REF_CLK 的频率和波形质量以及查看 RXD、TXD 数据线上的建立保持时间。逻辑分析仪则适合抓协议的交互过程比如发包时 TX_EN 和 TXD 的配合时序、MDIO 的读写帧格式等。如果没有示波器也可以通过软件手段做初步判断。比如在驱动中加入检测逻辑周期统计接收方向的 CRC 错误包数量或者通过 ethtool 读取 MAC 侧的错误计数器。这些数据虽然不如示波器直观但能帮你缩小问题范围。如果条件允许建议准备一台能抓包的 PC接在 RTL8306MB 的某个 LAN 口上配合 tcpdump 或者 Wireshark可以快速确认收发包是否正常、报文是否有 CRC 错误标记。这个方案成本低、见效快比直接上示波器更容易定位问题。6. 一点个人体会这次调 RTL8306MB最大的体会是RMII 接口的“坑”不在协议本身有多复杂而在它留给芯片设计和 PCB 布局的裕量很小。同一个驱动在这块板子上正常换一块布局不同的板子可能就会出丢包问题同为 RTL8306MB不同批次的芯片内部延迟特性也可能有细微差别一劳永逸的驱动是不存在的。后来我再调新的交换芯片会在一开始就把 RX 延迟、TX 延迟、双工模式、时钟配置这些参数全部做成可调变量并且在驱动里加一个 debugfs 接口可以在运行状态下动态修改寄存器值。这样板子到手后不用反复编译固件就能完成时序调优和参数确定。如果你手头也在做类似的项目建议拿到板子后先不要急着写完整的业务驱动先花半天时间把 RMII 接口的底层链路调通重点确认时钟、MDIO、收发通路这三个基本点。底层链路扎实了后面配置 VLAN、做业务功能就是水到渠成的事。
返回列表