ARTICLE DETAIL

资讯详情

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

RTL8367 DSA移植的10个坑:设备树、tag与Kconfig全解析

RTL8367 DSA移植的10个坑:设备树、tag与Kconfig全解析 去年做一块新板子时我在内核里第一次往DSA框架上接RTL8367当时以为这不就和PHY驱动一样把MDIO接上、配置好速率就完事。结果设备树加了一坨内核配置改了又改功能始终差一步要么lan口不出现要么出现后ping不通。后来仔细把DSA的tag协议、Kconfig依赖链、以及这颗芯片的SMI控制总线串起来才发现市面上能搜到的资料大多只讲了“怎么编译”很少讲“为什么会错”。这篇文章就打算把我踩过的和帮别人查过的10类典型错误整理出来一次性说透。这篇文章适合正在把RTL8367/RTL8367S这类芯片往Linux DSA框架里移植的BSP工程师也适合在路由器、工控板、开发板上调“多口交换芯片”的朋友。只要你需要让内核同时管理多个lan口并让数据在CPU和交换机端口之间正确转发下面这些坑你大概率都会碰到。1. RTL8367 DSA移植的核心设备树、tag协议和Kconfig为什么是一个三重锁1.1 RTL8367不是普通PHYDSA驱动也不是普通驱动很多第一次接触RTL8367的人潜意识里把它当成一颗“多口PHY”。这是最大的认知误区。RTL8367是一颗带管理功能的交换芯片内部有自己的地址学习表、VLAN表、端口隔离、QoS和镜像寄存器。它和CPU之间的连接也不只是简单的MII/RGMII数据总线还有一个用于配置芯片内部寄存器的SMI/MDIO控制口。如果用传统PHY驱动的思路去写RTL8367你会发现自己面对的是一堆“看起来不该存在”的问题芯片只有通过SMI读写寄存器才能管理端口up/down事件又需要通过中断或轮询上报数据帧从某个lan口进入后如果不打标签CPU根本不知道这个包是从哪个端口来的。DSA框架就是为解决这个问题而生的。它把“SoC上的一个以太网MAC”和“一颗外接交换芯片”组合成一个整体对外表现为多个网络接口。每个物理lan口对应一个DSA用户端口CPU口则专门负责和SoC的MAC对接。数据流的方向是某个lan口收包 → 交换机打上DSA tag → 从CPU口发给SoC的MAC → SoC根据tag去掉头部并交给协议栈。发包方向则完全相反。所以移植RTL8367驱动的本质不是“写一个PHY驱动”而是“让DSA框架认识这颗芯片并告诉它如何收发tag”。这也是为什么设备树、tag协议和Kconfig三者缺一不可设备树决定驱动会不会被加载tag协议决定数据能不能被识别Kconfig决定这些代码到底有没有编进内核。1.2 移植前必读的几页芯片手册在我详细列错误之前想先提个建议先把RTL8367的datasheet里这几页读透否则后面排障会非常痛苦。第一是芯片ID寄存器。不同批次、不同后缀的RTl8367系列芯片ID寄存器的地址和默认值可能不一样。这个值在你调试SMI通路时是第一个验证点读不到正确的ID后面就不用谈了。第二是端口控制寄存器里面包含link状态、速率、双工、流控等位域DSA驱动的adjust_link或phy_read最终都要落到这些寄存器上。第三是VLAN和端口隔离寄存器DSA驱动在setup阶段会做默认初始化如果你不了解默认的VLAN配置后面所有端口相互ping不通时根本无从下手。第四是CPU tag使能寄存器有的版本需要单独开启tag收发功能不开的话交换机上的数据包虽然能从CPU口出去但不带tagDSA无法识别。我第一次移植时跳过了芯片ID自检直接去配置VLAN结果花了整整一天在错误的思路上打转。后来补上了SMI通路的自测问题一下就暴露了我设备树里指定的SMI地址和板子上硬件跳线不一致。2. 设备树阶段的4个高频错误树写对了驱动才肯站起来设备树是DSA移植的第一道关卡。很多人在这个阶段就倒下了因为DSA的设备树结构比普通PHY复杂得多而且同样的错误在dmesg里的表现完全不一样。2.1 错误1compatible对不上驱动直接沉默现象设备树里加了switch节点内核启动后dmesg里没有任何和rtl8367相关的输出ls /sys/class/net/下也看不到新增的lan口。原因compatible字符串和驱动里的of_match_table不匹配。RTL8367在Linux内核里通常由drivers/net/dsa/rtl8366rb.c这个驱动来支持但不同内核版本支持的compatible名称可能不同常见的有realtek,rtl8367、realtek,rtl8367s、realtek,rtl8366rb等。如果你随手从某篇老文章里复制了一个compatible而这个字符串和当前内核源码里的不匹配驱动就不会绑定这个节点。解决方法很简单打开你当前内核源码里的drivers/net/dsa/rtl8366rb.c直接搜of_device_id看看里面到底写了哪些compatible字符串然后复制到设备树里不要凭记忆写。2.2 错误2SMI总线被抢占或者地址不对读不到Switch ID现象驱动确实probe了但dmesg里出现类似“failed to read switch ID”的报错或者读回来的寄存器全是0xffff、0x0000。原因RTL8367的SMI控制口需要两个GPIO一个MDC、一个MDIO这两根线如果被其他外设复用或者设备树里的gpio编号和实际原理图对不上SMI通信就会失败。更隐蔽的是SMI地址。RTL8367的SMI地址通常由芯片外部引脚的上下拉决定常见地址是0x29、0x2c等如果你设备树里reg属性写错驱动按错的地址去读自然什么都读不到。排查建议先用cat /sys/kernel/debug/gpio确认MDC/MDIO两个GPIO没有被占。对照原理图确认SMI地址的上下拉电阻是否和你设备树里的reg一致。如果驱动支持可以在probe阶段打印读取到的raw value用这个值反推地址是否正确。2.3 错误3CPU端口的fixed-link和phy-mode前后矛盾现象DSA可以注册出lan口但CPU口或者所有口都up不起来。ethtool eth0看到的link是down或者link是up但一ping就丢包。原因DSA的CPU端口通常直接连接到SoC的MAC这里没有传统意义上的PHY芯片所以必须用fixed-link来固定速率和双工模式。但很多人会在设备树里只写fixed-link忽略了phy-mode或者把phy-mode写成了rgmii而SoC那边实际上需要rgmii-id由硬件自动插入delay。RGMII的delay配置非常容易踩坑。有些SoC的MAC默认加了TX delay有些则不加RTL8367的CPU端口也有自己的delay配置。如果两端模式不一致信号时序就对不上表现为link时好时坏或者速率上到1000M就丢包、降到100M反而正常。我记得一块板子的现象特别典型SoC的MAC配置成rgmii-id但RTL8367端没有关闭delay结果两边都插入delay根本不通。最后把RTL8367的CPU端口delay关闭、让SoC负责全部delay问题才解决。2.4 错误4中断引脚没配置链路状态“爱答不理”现象所有端口都能up但插拔网线时链路状态不变化。ip link里看不到link up/down或者在dmesg里非常滞后。原因RTL8367支持通过一个中断引脚主动上报端口事件包括link变化、流量统计等。DSA驱动一般会注册这个中断来实现快速事件通知。如果设备树里没有interrupt-parent和interrupts驱动要么完全不监听要么退化成轮询逻辑链路状态自然不准确。解决方法是把中断引脚在设备树里补上。以常见的GPIO中断为例switch29 { compatible realtek,rtl8367; reg 29; interrupt-parent gpio0; interrupts 17 IRQ_TYPE_LEVEL_LOW; ... };注意中断触发方式一定要看芯片手册。RTL8367的中断引脚一般是低电平有效配成IRQ_TYPE_LEVEL_LOW通常会比较稳。如果你配成上升沿或下降沿可能会丢失中断事件。3. 内核配置与编译阶段的3个绊脚石代码没编进去谈何调试设备树搞定后很多人会直接卡在内核配置这一关。而且这个阶段的报错往往不是编译错误而是“选项根本不存在”或“编了但没生效”非常打击人。3.1 错误5Kconfig依赖链没打通驱动“隐身”了现象在make menuconfig里输入RTL8367搜不到任何相关选项。或者你直接在.config里手动加了CONFIG_NET_DSA_RTL8366RBy但编译之后发现代码根本没被编进去。原因DSA驱动的Kconfig有严格的依赖链。RTL8366RB驱动依赖于CONFIG_NET_DSA和CONFIG_NET_SWITCHDEV而CONFIG_NET_DSA又依赖于CONFIG_NET_SWITCHDEV。如果你没有先打开这些上层选项后面的具体驱动选项根本不会出现在menuconfig里。正确路径是Device Drivers → Network device support → [*] Distribution Switch Architecture (DSA) support [*] Net DSA [*] Net DSA Tagging for Realtek RTL4A tag [*] Realtek RTL8366RB/S support对应的.config片段大体是CONFIG_NET_SWITCHDEVy CONFIG_NET_DSAy CONFIG_NET_DSA_TAG_RTL4_Ay CONFIG_NET_DSA_RTL8366RBy如果你用的是非常老的内核选项名可能略有不同但依赖关系是类似的。建议用make olddefconfig把默认配置刷新一遍再确认这三个宏都在。还有一个容易忽略的点如果RTL8367驱动被编译成模块那么依赖它的DSA tag和mdio相关模块也必须一起编译并同步到目标板的根文件系统里。很多人只拷贝了rtl8366rb.ko忘了拷贝dsa_core.ko和tag模块导致modprobe时提示符号找不到。3.2 错误6DSA tag protocol没有使能数据帧进来了但没人翻译现象驱动加载正常端口也能up但插上lan口就是ping不通。在CPU口用tcpdump抓包能看到ARP请求进来但内核没办法把包正确关联到对应端口或者发出的包没有任何tag。原因RTL8367的数据帧在CPU口上默认携带一个RTL4A格式的DSA tag。内核必须知道这个tag格式才能在收包时剥离tag发包时插入tag。这个功能对应CONFIG_NET_DSA_TAG_RTL4_A。如果没开启DSA框架可能会使用默认的DSA tag或者根本不启用tag导致协议栈和交换机之间无法正确交换数据。除了内核配置还要看驱动代码里的get_tag_protocol回调。RTL8366RB驱动的实现里通常会返回DSA_TAG_PROTO_RTL4_A但如果你的驱动是从其他芯片改过来的这里可能会残留别的tag协议比如DSA_TAG_PROTO_DSA那也会出问题。排查时可以直接看dmesg或驱动日志有的内核会打印“Using tag protocol ...”。也可以在驱动里加一行dev_info把get_tag_protocol的返回值打出来确认是RTL4A而不是其他协议。3.3 错误7模块依赖和装载顺序不对反复insmod失败现象手动insmod rtl8366rb.ko时报错“Unknown symbol”或者“module is not found”。放在开机脚本里加载有时成功有时失败依赖的模块没有先加载。原因RTL8366RB驱动依赖mdio、regmap、DSA core等多个模块如果你把它们都编成模块就必须保证装载顺序。手动insmod时最容易漏依赖。解决方法是不要手动维护顺序而是把模块放到目标板的/lib/modules/$(uname -r)目录下先执行depmod -a之后用modprobe rtl8366rb自动加载。modprobe会解析modules.dep文件自动处理依赖顺序。如果目标板根文件系统空间有限我更建议直接把DSA相关功能编译进内核而不是编译成模块。对于路由器、工控板这类固定硬件场景模块化没有太大意义反而多了文件系统同步的麻烦。4. 驱动代码里的三个“隐形炸弹”从GPIO到regmap再到ops如果你过了设备树和内核配置两关驱动应该已经能跑起来了。但接下来才是深水区因为有些错误不是“跑不起来”而是“跑起来但行为诡异”。4.1 错误8把RTL8367挂成普通PHY只有CPU口能用现象设备树里把RTL8367的节点写成了PHY节点比如放在mdio总线下面并使用phy-handle去引用它。结果是系统只识别出一个网口也就是SoC的MAC口其他lan口完全没有对应的netdev。原因RTL8367内部虽然有PHY但它是一个交换机芯片必须用DSA框架来管理多个端口。如果把它注册成普通PHY内核对它的认知就只是“一颗外挂PHY”自然只暴露一个端口芯片内部的其余端口根本没有机会被枚举出来。这种错误在从旧代码或者参考设计复制设备树时特别容易出现。判断方法很简单如果你的交换芯片节点在mdio或mdio1节点下面且被phy-handle引用那就要怀疑是不是这里出了问题。正确的做法是使用带ports子节点的DSA结构并在port0里用ethernet属性指向SoC的MAC而不是用phy-handle去引用switch节点。4.2 错误9寄存器读写绕过regmap读回来全是F现象驱动在setup阶段能执行但读写寄存器时读回来的值要么全是0xffff要么导致系统卡死。你可能会怀疑硬件有问题但实际上是你访问寄存器的方式不对。原因RTL8367的控制口是SMI类似于MDIO但又不完全相同。DSA框架下的官方驱动会通过regmap或mdio总线封装来读写芯片寄存器而不是直接ioremap一个物理地址。有些移植者从老的非DSA驱动里抄来一段直接操作CSR的代码或者用用户态工具去读写寄存器结果和内核里的SMI总线访问产生冲突。正确做法是找到驱动里现成的read_register/write_register函数或者regmap_config结构体所有寄存器访问都走这套接口。如果你要在用户态验证硬件也务必在驱动不加载的时候做避免两边同时占用SMI总线。4.3 错误10dsa_switch_ops回调不完整内核说“操作不支持”现象驱动probe之后DSA框架注册端口时报错常见log有“Operation not supported”或“dsa switch does not implement xxx”。端口可能注册了一半有的口出现有的口没有。原因DSA框架要求驱动的dsa_switch_ops结构体里实现一组必须的回调。不同内核版本要求不完全一样但setup、get_tag_protocol、phy_read、phy_write这几个几乎都是必填的。有些人从网上抄了一份精简驱动只实现了setup和get_tag_protocol其他回调为NULLDSA框架在特定路径调用对应函数时就失败了。解决方法是参考内核里原版RTL8366RB驱动对照它的dsa_switch_ops实现清单把自己缺的回调补齐。特别是phy_read和phy_write这类和PHY层交互的函数很多老驱动里已经写好了直接搬过来通常不会有大问题。补齐后重建内核端口大概率就能完整注册出来了。5. 移植成功后的最后一公里调试命令、日志定位和VLAN坑驱动跑通、端口全部出现之后真正的工作才算开始。后面还会有各种网络行为不对的问题尤其是VLAN、桥接和tag之间的冲突。这里分享一套我常用的定位流程以及一个几乎每个移植者都会踩的VLAN坑。5.1 dmesg和/proc是第一位老师我先看dmesg里有没有DSA相关的关键日志dmesg | grep -E dsa|rtl|switch|lan正常情况下应该能看到类似“DSA: switch 0 probe”或者端口注册的日志。如果什么都没有先检查设备树是否被正确解析最简单的方式是ls /sys/firmware/devicetree/base/soc/ethernet/switch29/如果你的switch节点存在访问/sys/firmware/devicetree/base/下的对应路径应该能看到名字。如果这里都找不到说明设备树文件根本没有被编译进去。端口都注册好之后用ip link show和ethtool验证实际链路形态。5.2 ethtool、bridge和tcpdump的组合拳我常用的排查表格是这样的现象命令期望结果端口没upip link show能看到lan1-lan5等物理链路状态ethtool lan1Speed/Duplex与预期一致端口是否在桥内bridge link show端口master为br0VLAN配置是否正确bridge vlan showlan口的PVID和tagged状态正确数据是否走到CPU口tcpdump -i eth0能看到ARP或ICMP报文有时候还会用到/sys/class/net/lan1/phydev来确认端口和PHY层是否绑定。RTL8367内部的PHY在DSA框架下通常每个用户port都会有一个独立的phy驱动实例如果你发现某个port下没有phydev说明这个口的PHY配置有问题可能是phy-mode或phy-handle没配对。5.3 一个典型的VLAN坑所有lan口相互ping不通我之前在板子上把lan1-lan4统统加入br0然后插上两台电脑结果两台电脑能分别ping通路由器但互相之间不通。查了半天最后用bridge vlan show发现四个端口的PVID虽然都是1但它们没有把vid 1标记为“untagged”而RTL8367内部默认的端口VLAN配置又很激进导致交换芯片在硬件层做了隔离。DSA驱动在setup阶段一般会把每个端口初始化为独立VLAN这样做的目的是防止端口间私通保证从CPU口出来的报文可以正确隔离。但这个初始状态并不适合“把所有lan口当一个普通交换机用”的场景。解决方法很简单把它们统一纳入bridge并明确VLANip link set lan1 master br0 ip link set lan2 master br0 ip link set lan3 master br0 ip link set lan4 master br0 bridge vlan add vid 1 dev lan1 pvid untagged bridge vlan add vid 1 dev lan2 pvid untagged bridge vlan add vid 1 dev lan3 pvid untagged bridge vlan add vid 1 dev lan4 pvid untagged做完这步端口间的二层转发就正常了。这个坑特别隐蔽因为表面上看链路状态、驱动日志都没有异常唯一线索就是bridge vlan show里PVID和untagged状态不符合预期。最后再分享一点个人经验DSA框架下的RTL8367移植90%的问题都可以归结为“三重锁没同时打开”——设备树的拓扑关系、内核的Kconfig/tag配置、驱动里的ops/寄存器访问三者必须全部正确。如果你的板子现在还在某个坑里没出来可以按照本文的顺序从设备树到内核配置再到驱动代码逐项排查大概率在某一章节能找到对应的错误。
返回列表