用户工具

站点工具


hacking:i:bce_excessive_interrupts

bce(4) 产生大量中断问题的修正

–delphij

说明

本文介绍的是一个个案:由于一个较大的变动集引入了一个不太容易被注意到的问题,随后在大约一个月之后被人发现,以及其中测试、查找并修正问题的过程。个人认为这个过程(在缺少注释、datasheet、有效的变动集的情况下缩小问题范围并最终加以解决的调试过程)对于类似的问题具有一定的参考意义。

背景

Broadcom NetXtreme II 系列(DragonFlyBSD和FreeBSD称为bce,OpenBSD称为bnx,Linux称为bnx2)是Broadcom公司最近几年来推出的一系列千兆以太网控制器,与早期的NetXtreme系列相比,增加了包括TCP/IP/UDP校验和offload、2.5Gbps介质支持等能力。FreeBSD的驱动 bce(4) 由 Broadcom 的 David Christensen 撰写和维护。

今年 bce(4) 进行了一系列改进而没有合并到 7-STABLE 中,因此在 7.1-RELEASE 的发布版本准备过程中,我向 re@ 提议将适用的变动全部合并到 7-STABLE 分支。这个变动集(184826)于UTC时间2008年11月10日22:40:16提交到svn,包含了-HEAD分支的变动集176448、178132、178853、179436、179695、179771和182293;随后,根据用户之前的反馈,又进一步增加了185082(合并为185161)。

问题

第一个变动集commit后大约一个月,有细心的用户发现中断异常,即,每个bce设备每秒钟会产生4-5万个中断,无论是否真的有流量。

初步查找

因为一时没有头绪,我们首先尝试将问题尽量缩小和简化。由于 7.0-RELEASE 上面正常,而最近对 bce(4) 驱动做过修改,尽管系统的其他组件也做过改动,但是单纯将 bce(4) 回退,如果问题消失,就可以知道是否是新版 bce(4) 引入的回归问题。首先,我們回退 185161 和 184826,问题消失(我們将这个版本记为7-STABLE,-185161,-184826)。185161是一个很容易理解的修正逻辑问题的补丁,而184826则是一个多达两万六千多行增删的大型patchset,因此它的嫌疑较大。测试7-STABLE-185161发现问题依然存在,那么,至少184826是非常可能有问题的:

版本状态
7-STABLE有问题
7-STABLE, -185161有问题
7-STABLE, -185161, -184826无问题

继续查找

184826是一个大型patchset,包含了176448、178132、178853、179436、179695、179771和182293的积累结果。其中,179771是最大的一个patchset,这次commit改掉了两万多行代码。

想要单纯通过比对来找到这么大的changeset中的问题是很麻烦的,因为手头没有资料,在死磕代码之前,首先试试看屏蔽一部分变动。将新增的 BCE_USE_SPLIT_HEADER 特性禁止掉,发现问题依然存在。

DragonFlyBSD 的 sephe@ 对 bce(4) 的一些参数进行了修改,对FreeBSD而言,这些参数位于if_bce.c 927行开始的bce_tx_quick_cons_trip_int等,修改这些参数并重启,观察vmstat -i发现中断数量明显减少。由于这些参数决定了收发包时产生中断的频率,因此,直觉上看,问题应该与中断处理函数有一些关系。

比对代码

在 bce_intr 中发现:

               /* Was it a link change interrupt? */
               if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
                      (sc->status_block->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE))
                       bce_phy_intr(sc);

下面新增了一段代码:

               /* Clear any transient status updates during link state change. */
               REG_WR(sc, BCE_HC_COMMAND,
                       sc->hc_command | BCE_HC_COMMAND_COAL_NOW_WO_INT);
               REG_RD(sc, BCE_HC_COMMAND);

从注释上看,这个操作只有在发生了链路状态变化的时候才应该进行。增加一对 { },改为:

                /* Was it a link change interrupt? */
                if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
                        (sc->status_block->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) {
                        bce_phy_intr(sc);
 
                        /* Clear any transient status updates during link state change. */
                        REG_WR(sc, BCE_HC_COMMAND,
                                sc->hc_command | BCE_HC_COMMAND_COAL_NOW_WO_INT);
                        REG_RD(sc, BCE_HC_COMMAND);
                }

联编并测试,果然,大量中断的现象消失了。

(说明:从公开的资料看,执行这个操作不应产生新的中断。由于没有 datasheet,因此这个问题还需要继续研究。)

/data/vhosts/wiki-data/pages/hacking/i/bce_excessive_interrupts.txt · 最后更改: 2008/12/24 09:56 由 delphij