尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ADM6996交换机芯片驱动移植与VLAN配置实战指南

ADM6996交换机芯片驱动移植与VLAN配置实战指南 简介这是一份面向ADM6996交换机芯片的驱动源码压缩包适合嵌入式网络设备驱动开发工程师以及需要基于该芯片完成系统适配、交换功能定制或调试相关硬件的中高级技术人员。包内共2个文件ADM6996.c为驱动实现源文件涉及芯片初始化、寄存器读写、数据通路收发等核心逻辑ADM6996.h为配套头文件定义了接口函数、数据结构与常量宏方便上层模块调用或二次封装。压缩包仅1KB代码虽精简但完整呈现了驱动的基本骨架便于逐行阅读、移植或整合进现有内核模块。已有229人学习下载使用时可结合ADM6996数据手册理解寄存器布局并配合EEPROM配置信息完成芯片启动参数烧写确保交换机正确运行。开发者可借此掌握的不仅是ADM6996的软件接口更是一套网络交换设备驱动的编写与排错思路在此基础上继续扩展VLAN、端口管理、中断处理等功能时也有迹可循。1. adm6996.tar.gz 里装的是什么老交换机芯片的“后悔药”和入门钥匙拆过老旧网络设备的人大多遇到过这种场面板子上躺着一颗 ADM6996丝印清晰但厂商提供的驱动要么是闭源二进制、要么是一个解压后不知道从哪里下手的 tar.gz。这颗芯片是多年前很常见的五口百兆交换芯片出现在各种 SOHO 路由器、工业交换机、物联网网关的网口背板上。你手上的 adm6996.tar.gz 通常是一套 Linux 下的驱动源码包里面包含芯片初始化、PHY 管理、VLAN 表配置和端口镜像这几块代码。它能解决的核心问题只有一个让板子上这颗交换芯片从“上电即通”的傻瓜模式变成你可以控制 VLAN 隔离、端口镜像和 QoS 的网络设备。适合的是拿到板子想让网口真正按业务转发、而不是只会插上就亮的嵌入式工程师也适合在旧设备上做二次开发和改造的人。2. 认识 ADM6996先从 tar.gz 里读出芯片的“黑匣子”2.1 解包与文件布局源码里哪几类文件直接决定能否移植成功拿到 adm6996.tar.gz 之后不建议急着丢进交叉编译链里跑先解包看目录结构。常见的做法是放到工作目录下先列一遍文件类型搞清楚里面是完整驱动还是只有寄存器头文件和示例。mkdir -p ~/work/adm6996 cd ~/work/adm6996 tar xzvf /path/to/adm6996.tar.gz file * | grep -E text|source|script | head -20 find . -maxdepth 2 -type f | sort解包后重点找三类文件带_reg.h或_def.h后缀的寄存器定义头文件、带adm6996_main.c或adm6996_mdio.c的驱动主体、以及 README 或 INSTALL 文本。file命令能快速确认哪些是真正的 C 源码哪些可能是换行符被改坏的文本文件。这个步骤的价值在于判断源码包的完整度如果连寄存器定义头文件都缺说明这个包拿到手就是残缺的后边所有工作都要从逆向寄存器开始工时预算要重新评估。多数情况下驱动主体会以mii.c或platform_driver的形式挂在 mdio 总线上通过读写 MDIO/MDC 引脚访问芯片内部寄存器。源码包里往往还会带一个adm6996_switch.c这样的文件里面实现了switchdev或procfs接口的封装。解包后先确认有没有struct platform_driver和struct mii_bus这两个关键结构体定义它们决定了你后续编写的设备树节点和板级初始化代码长什么样。2.2 看懂寄存器地图VLAN、镜像与 QoS 的落点ADM6996 的寄存器空间分两段前 32 个是 PHY 寄存器后面是 Switch Control Registers。驱动里所有功能最终都是写这几个寄存器实现的。不要试图记住每个寄存器的地址重点记住三类全局控制寄存器、VLAN 表寄存器、端口映射寄存器。grep -n VLAN\|PORT_MAP\|MIRROR\|QOS adm6996_reg.h | head -40输出里会看到类似ADM6996_VLAN_TABLE、ADM6996_PORT_MAP这样的宏定义。这些宏的偏移量和解包前的数据手册寄存器地址一一对应。读懂这张寄存器表之后你要明白几个关键逻辑ADM6996 端口编号通常从 0 开始端口 4 或 5 可能被设计成 CPU 口接 SoC 的 MACVLAN 表是按哈希索引组织的查表结果是端口位图端口镜像的本质是把源端口收到的报文复制一份从镜像端口发出去硬件上通过一个 mirror 控制寄存器开关。这些理解决定了你后边写配置工具时是直接写寄存器还是调用驱动已有的 API。3. 把解出来的驱动跑在目标板上从交叉编译到最小配置3.1 编译前必改的三个地方Makefile、芯片型号选择与 PHY 地址源码包解出来后直接make大概率会失败因为 Makefile 里的交叉编译前缀和目标架构是写给作者自己的板子用的。常见需要改的是三处CROSS_COMPILE、ARCH、以及CONFIG_ADM6996_PHY_ADDR。如果你把驱动编进内核而不是作为模块还需要确认KERNELDIR指向你正在使用的内核源码树。CROSS_COMPILE : arm-linux-gnueabihf- ARCH : arm KERNELDIR : /home/user/kernel/linux-4.14 obj-m : adm6996_drv.o adm6996_drv-objs : adm6996_core.o adm6996_mdio.o adm6996_vlan.o all: $(MAKE) -C $(KERNELDIR) M$(PWD) ARCH$(ARCH) CROSS_COMPILE$(CROSS_COMPILE) modules宏CONFIG_ADM6996_PHY_ADDR如果不确定可以先不定义很多驱动会在probe时通过读取芯片 ID 寄存器自动识别 PHY 地址。mii-tool或phy_read能读到的典型 ID 寄存器的值与数据手册中ADM6996_ID的定义做比对。交叉编译前缀一定要和你的工具链一致arm-linux-gnueabihf-是常见的硬浮点版本如果你的根文件系统是软浮点编的带上-mfloat-abisoftfp可能反而引发内核模块和你用户态库的 ABI 不匹配。模块方式编译时建议先make -C $(KERNELDIR) modules_prepare确认内核源码已经配置过否则会出现一堆找不到generated/autoconf.h的报错。3.2 注册成 MII 设备的最小路径平台设备 mdio 总线编译通过只是第一步真正麻烦的是让内核在启动时找到这颗芯片。ADM6996 走的是 mdio 总线SoC 的 MAC 控制器会注册一个mii_bus交换芯片挂在某个 PHY 地址上。驱动需要做的是在这个 mii_bus 上扫描并绑定 ADM6996而不是直接注册一个平台设备。但很多源码包默认是平台设备模型这时需要做一层适配。static struct plat_adm6996_data adm6996_plat_data { .phy_addr 0x01, .cpu_port 0x04, .vlan_enable 1, }; static struct platform_device adm6996_device { .name adm6996, .id -1, .dev { .platform_data adm6996_plat_data, }, }; static int __init adm6996_board_init(void) { return platform_device_register(adm6996_device); } arch_initcall(adm6996_board_init);这段代码的关键在于phy_addr与cpu_port两个参数。phy_addr是芯片在 mdio 总线上的地址一般由板级原理图决定常见取值是 0x00 到 0x1Fcpu_port是连接 SoC 网口的端口号如果接错后面所有 VLAN 转发测试都会失败。arch_initcall保证它在网卡驱动注册之前被调用否则可能出现 mdio 总线还没注册导致 probe 失败的情况。编译进内核时还要在 Kconfig 里增加对应的配置项或者直接把这个文件的initcall改成module_init并用 insmod 加载这样调试时可以快速改参数重载。3.3 上电后的首个自检命令看芯片是否被正确锁定驱动加载成功后第一件事是查看网络接口是否出现。因为 ADM6996 通常接到 SoC 的 MAC 上所以你会看到 eth0或 eth1的 link 状态变为 UP。注意这个 link 不代表整个交换芯片已经工作了它只是 MAC 到 PHY 之间的链路握手成功。ifconfig eth0 up mii-tool eth0 cat /sys/class/net/eth0/phy_link_speed dmesg | grep -i adm6996如果mii-tool输出negotiated 100baseTx-HD之类的结果说明 PHY 通信正常。如果输出no link则要检查 PHY 地址对不对常见做法是用mdio-tool或者直接写一个读取 PHY ID 寄存器的小工具把 0x000x1F 地址全扫一遍看哪个地址能读回0x0290或源码头文件里定义的厂商 ID。dmesg里如果出现adm6996 detect failed基本可以断定 PHY 地址或 MII 总线号写错了。4. 调通交换机的“本职工作”VLAN、端口隔离与镜像的实际参数4.1 配置 VLAN 的最小寄存器写序列很多拿到源码包的人第一个疑问是为什么默认状态下所有端口互通配置 VLAN 之后反而全都不通了。这里要理解 ADM6996 的 VLAN 表工作方式它是基于哈希查找的端口映射表CPU 口默认不在任何 VLAN 里一旦你把业务端口划进某个 VLANCPU 口也必须加进去否则 SoC 发出的报文无法被交换芯片识别表现为“可以收到外部包但 ping 不通网关”。static void adm6996_vlan_add(u16 vid, u8 port_mask) { u32 reg_val; /* 禁止 VLAN 表更新期间查表 */ adm6996_write_reg(ADM6996_VLAN_CTRL, 0x02); reg_val (vid 16) | (port_mask 8) | 0x01; adm6996_write_reg(ADM6996_VLAN_TABLE_REG, reg_val); /* 先读后写确保本次修改生效 */ reg_val adm6996_read_reg(ADM6996_VLAN_TABLE_REG); adm6996_write_reg(ADM6996_VLAN_CTRL, 0x00); }上面代码里0x02是置位 VLAN 表更新模式0x01是触发一次表项写入。vid是 VLAN IDport_mask的每个 bit 对应一个物理端口比如 0x13 表示端口 0、1、4 在同一个 VLAN。不同源码包对ADM6996_VLAN_TABLE_REG偏移的定义可能不一致常见命名是ADM6996_VLAN_TABLE0到TABLE3。业务上一定要把 CPU 口算进 mask 里这是几乎所有初次接触的人都会踩的坑。配置完 VLAN 后验证方式很简单两个业务口互 ping 通、和 CPU 互 ping 通但跨 VLAN 互 ping 不通。如果全部 ping 不通优先检查 port_mask 的位顺序是否和芯片默认端口编号一致有的版本端口 0 对应最靠近电源灯的网口有的反过来。4.2 端口镜像让抓包器看到另一个口端口镜像常用于故障排查和流量审计。ADM6996 支持把一个或几个源端口的流量复制到镜像端口但镜像端口本身不能承载业务流量否则会出现帧风暴。static int adm6996_set_mirror(int src_port, int mirror_port) { u32 val; if (src_port mirror_port) { pr_err(src and mirror port must be different\n); return -EINVAL; } /* 设置镜像端口和源端口 */ val (mirror_port 8) | (1 src_port); adm6996_write_reg(ADM6996_MIRROR_REG, val); /* 使能镜像功能 */ val adm6996_read_reg(ADM6996_MIRROR_CTRL); val | 0x80; adm6996_write_reg(ADM6996_MIRROR_CTRL, val); return 0; }src_port作为 bit 位放进低 8 位mirror_port放进高字节。使能位是0x80表示镜像功能开启。镜像口一般选择接一个不带 VLAN 的独立网口用笔记本电脑抓包。查问题时常见的困惑是为什么 mirror 口只能抓到广播包抓不到单播包——这通常是因为源端口和镜像端口必须在同一个 VLAN 域里ADM6996 的镜像实现是查表复制VLAN 不匹配直接丢弃副本。另一个常被忽略的地方是镜像方向这个寄存器通常同时控制 RX 和 TX无法单独镜像一个方向如果你只需要看上行流量必须在应用层过滤。4.3 和现有网络设备对接时的兼容性设置在实际组网中ADM6996 所在的设备经常要接到别的交换机上比如接到 H3C 或华为的接入交换机的 trunk 口。这种情况下 ADM6996 侧的 VLAN 设置要特别注意帧格式。如果对端交换机 trunk 口封装的是 802.1Q你这边端口必须是 tagged 模式否则对端会直接丢弃帧现象就是灯亮着但 ping 不通。# 在 Linux 侧创建带 VLAN 的接口 ip link add link eth0 name eth0.100 type vlan id 100 ip link set eth0.100 up ip addr add 192.168.100.2/24 dev eth0.100常见做法是把 ADM6996 的 CPU 口设成 tagged业务口设成 untagged。Linux 侧再用ip link创建对应的 VLAN 子接口。如果对端设备是华为或锐捷还要注意链路两端的协商模式ADM6996 这边固定成 100M 全双工对端如果设置成自协商可能会出现协商失败变成半双工性能断崖式下降。遇到这种无法协商的情况可以在对端交换机上强制端口速率或者在 ADM6996 驱动初始化时直接把自动协商关掉写死速度和双工模式。5. adm6996 常见问题与避坑功耗、镜像、自协商与环路的现场排查5.1 现象驱动加载正常但两个业务口互相不通板子上电dmesg 里也看到了adm6996 driver initialized两个端口插上电脑灯都亮但互 ping 不通。从原理上看问题基本出现在端口映射寄存器没有初始化。很多源码包默认把端口映射表清零了意味着每个端口不在任何 VLAN 里交换芯片不知道把帧往哪转发。解决方法是重新初始化所有端口的默认转发位图端口 0 应该发给端口 1、2、3、4、5端口 1 发给 0、2、3、4、5依此类推。有的驱动把这个放在adm6996_reset_switch()里有的放在init_port_map()里如果没执行整个芯片就是一个空壳。在probe函数最后打一条日志确认port_map寄存器读回的值不是 0。5.2 现象打开镜像后业务口的吞吐量骤降抓包需求很多但开了镜像口之后原来能跑满 100M 的业务口变成只有 30M。原因是 ADM6996 的镜像实现会把所有流量从 mirror 口复制一份如果 mirror 口以半双工模式连到分析设备复制过程会消耗内部带宽。这个不是 bug是芯片设计的硬限制。我的习惯是镜像功能只在排障时临时开调完立刻关掉不要做成常开功能。如果你的业务就是需要做流量审计那就得换带独立镜像处理能力的交换芯片别在 ADM6996 上死磕。5.3 现象反复重启后配置丢失设备断电重启VLAN 设置全部没了又回到所有端口互通状态。这是因为 ADM6996 内部寄存器是易失性的所有配置都在 RAM 里掉电即失。源码包里的驱动如果没做配置持久化重上电后只有probe里的默认值。解决思路有两种如果用的是 Linux在用户态写一个启动脚本通过驱动导出的 sysfs 节点或 ioctl 重新下发 VLAN 配置如果用的是 RTOS就要在初始化函数里把配置表放到 Flash 里上电时先读 Flash 再写寄存器。很多源码包确实带一个adm6996_config.c文件里面定义了默认配置数组你要做的就是确认这个数组的内容符合你的业务需求。5.4 现象接到原有的交换机上后整个网络时通时断把 ADM6996 的设备接到现网的交换机后整个链路不稳定Ping 延迟忽高忽低。优先看网线对端交换机的端口日志八成是协商成了 10M 半双工或者对端端口做了风暴控制把这台设备发的未知单播帧误判成广播风暴给丢弃了。解决方法是对端交换机端口配置undo negotiation auto华为或 H3C 指令场景强制 100M 全双工或者在本侧驱动里关闭自协商。另一种可能性是环路ADM6996 的默认配置不参与 STP如果你的组网里出现了冗余链路广播帧会无限循环直接导致整个局域网瘫痪。排查时拔掉一根网线测试即可确认。5.5 现象同一版本源码换一批板子后 PHY 地址读不到了原来的板子 PHY 地址是 0x01新打样的板子驱动加载失败。原因是硬件改版把 ADM6996 的 PHY 地址引脚电平改了MDIO 地址从 0x01 变成了 0x05。这类问题在量产时经常遇到属于典型的“硬件改版、软件滞后”事故。常见做法是不要写死 PHY 地址而是让驱动在probe阶段扫描整个 MDIO 地址空间通过读芯片 ID 寄存器来确认是不是 ADM6996。扫描代码很少但能省下大量硬件和软件联调的沟通成本。6. 把“不通”变成“预期内”留好读回接口和验证脚本先给驱动加一个简单的寄存器读回接口我一般喜欢暴露成/sys/kernel/debug/adm6996/reg这样的 debugfs 节点。读回的价值在于写寄存器人人会读寄存器才能确认硬件真的按你的意思工作了。下面这组命令可以作为每次调整后的标准验证流程# 打印所有端口 link 状态 cat /sys/kernel/debug/adm6996/link_status # 读取 VLAN 表前 4 项 echo 0 /sys/kernel/debug/adm6996/vlan_index cat /sys/kernel/debug/adm6996/vlan_table # 读取端口映射寄存器 cat /sys/kernel/debug/adm6996/port_map配合 tcpdump 做转发验证时将笔记本插到镜像口执行tcpdump -i eth0 -e -n vlan 100观察抓包内容里是否出现业务口的 MAC 和目标 MAC。如果抓到的全是广播帧没有源端口发来的单播帧那就回到第 4 章检查 port_mask。链路吞吐的验证不建议直接用 iperf老芯片的收发缓存很小大包小包混杂时候会掉包相对可靠的做法是用ping -s 1400 -c 200看丢包率再配合netstat -i查看 RX-DRP 和 TX-DRP 计数。如果ping -s 1400不丢但ping -f丢包严重优先级队列配置就要单独调。有一件事我吃过亏调试完直接把方案移交结果一个月后现场反馈“交换机偶尔死机”。后来发现得意忘形地忽略了板子上的散热设计ADM6996 在全速转发时发热明显寄存器温度超过阈值后芯片内部锁相环失锁导致转发异常。从那以后我的习惯是每次拿到新方案先让它满负荷跑 24 小时中途人工断几次电模拟现场误操作。这套验证流程看起来不聪明但确实帮我减少了百分之八十的售后往返。希望帮到你。本文还有配套的精品资源点击获取
返回列表