net: lan743x: speed-based and user-configurable interrupt moderation
💡 一句话总结
Microchip lan743x PCIe 网卡驱动原先把固定 400us 的中断调制定时器写入全部 per-vector 寄存器,既不随链路速率变化、也无法被用户态配置;本系列(net-next,v1)把定时器改为随协商速率自适应(2.5G→64us、1G→150us、100M/10M→330us),并新增 ethtool -c 的 get/set_coalesce 接口把聚合能力开放给用户态,从而在高吞吐场景压低聚合引入的延迟、在低速率场景获得更有效的中断聚合。
📋 补丁基本信息
| 项目 | 内容 |
|---|---|
| 补丁类型 | 功能增强(interrupt coalescing 支持 + 默认值改进) |
| 状态 | In Review(v1,目标 net-next) |
| 当前版本 | v1 · cover letter / patch 1/2 / patch 2/2 |
| 版本演进 | v1(2026-08-03 首次提交;lore 索引中未见更早版本) |
| 作者机构 | Microchip(Dhanushkalyan G 与 Thangaraj Samynathan) |
| 提交日期 | 2026-08-03 |
| 目标分支 | net-next(PATCH net-next 0/2) |
| 改动范围 | 3 文件 +144/-11(cover letter 自报统计);patch1 +42/-14、patch2 +117/-12 |
| 核心函数 | lan743x_config_int_mod() / lan743x_get_int_mod() / lan743x_ethtool_get/set_coalesce() |
📊 速览卡片
🎯 解决什么问题
"The lan743x driver programs a single fixed interrupt moderation timer into all per-vector INT_MOD_CFG registers at interrupt open, regardless of link speed and with no way for userspace to tune it."即:当前代码在
lan743x_intr_open() 里把单个固定值 LAN743X_INT_MOD (400) 一次性写入全部 10 个 per-vector INT_MOD_CFG 寄存器,之后不再改变;链路速率变了它也不变,用户态没有任何调优入口。
- 2.5G/1G 高吞吐、延迟敏感场景(NVMe-oF/TCP、存储网络、RPC 负载):线速下包间隔仅亚微秒级,固定 400us 的聚合延迟占单包端到端延迟的比例显著,且每批中断的收益与其延迟代价失衡(解读(AI 分析))。
- 100M/10M 低速率场景:400us 偏短,聚合效率一般,中断率仍有压缩空间。
- 需要按工作负载调优的运维:无
ethtool -c接口,无法针对低延迟或低 CPU 场景调整,与其它主流网卡驱动能力不一致。
🧩 核心机制
两枚补丁的职责划分很清晰:Patch 1(Thangaraj Samynathan)把"静态的向量映射"与"按速率的定时器值"解耦,让定时器随链路速率变化;Patch 2(Dhanushkalyan G)在此基础上补上 ethtool 用户接口与自适应/手动两种模式。涉及模块:drivers/net/ethernet/microchip/lan743x_main.c、lan743x_ethtool.c、lan743x_main.h。
- 新增
lan743x_config_int_mod(adapter, int_mod)帮助函数:集中把定时器值写入全部 per-vectorINT_MOD_CFG0-9,并把原来散落在lan743x_intr_open()里的 10 个寄存器写从这里移走。中断打开时只保留一次性的INT_MOD_MAP0/1/2向量映射(静态,不变)。 - 宏从单一
LAN743X_INT_MOD(400)拆成四个按速率的宏:2.5G→64us、1G→150us、100M→330us、10M→330us。 - 在
lan743x_phylink_mac_link_up()中按协商速率写入:链路 up 时根据speed选值并调用lan743x_config_int_mod(),使聚合周期随实际链路速率变化。
- 新增
.get_coalesce/.set_coalesce,并在supported_coalesce_params声明ETHTOOL_COALESCE_USECS | USE_ADAPTIVE_RX | USE_ADAPTIVE_TX(向 ethtool 声明驱动支持"微秒聚合"与"自适应聚合")。 - 引入"自适应"语义(默认开启):
adapter->use_adaptive_mod = true时,定时器继续跟随链路速率(link_up 时按速率重算);关闭时固定为用户rx_coalesce_usecs指定的值。 - 新增速率→值映射
lan743x_get_int_mod(speed)(Patch 1 内联逻辑抽成非 static 函数),供 ethtool 在"重新开启自适应"时立即恢复当前速率对应的值。 - 新增
adapter->int_mod缓存:lan743x_config_int_mod()先判断新值与已编程值是否相同,相同则跳过寄存器写(避免每次 link_up 无谓重写全部 10 个 CSR)。 - 新增
adapter->link_speed记录:link_up 时记录协商速率,供后续 ethtool 自适应请求取值。 - 硬件单值约束的显式校验:硬件所有向量共用一个值,因此
rx_usecs != tx_usecs、或只开单侧自适应,都会用NL_SET_ERR_MSG_MOD报出具体原因并返回-EINVAL。
🔬 关键代码
-#define LAN743X_INT_MOD (400)
+#define LAN743X_INT_MOD_2_5G (64)
+#define LAN743X_INT_MOD_1G (150)
+#define LAN743X_INT_MOD_100M (330)
+#define LAN743X_INT_MOD_10M (330)▲ 单一固定值拆成 4 个速率档位。2.5G 用最短 64us(包到达最快、延迟代价最敏感),100M/10M 用 330us(聚合效率优先)。数值来源为作者设定,未见 datasheet 出处标注。
+/* Program the interrupt moderation timer value into the per-vector
+ * INT_MOD_CFG registers. Only the timer value is written here; the vector
+ * mapping (INT_MOD_MAP) is static and is set once at interrupt open.
+ */
+static void lan743x_config_int_mod(struct lan743x_adapter *adapter, u32 int_mod)
+{
+ if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
+ lan743x_csr_write(adapter, INT_MOD_CFG0, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG1, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG2, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG3, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG4, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG5, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG6, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG7, int_mod);
+ if (adapter->is_pci11x1x) {
+ lan743x_csr_write(adapter, INT_MOD_CFG8, int_mod);
+ lan743x_csr_write(adapter, INT_MOD_CFG9, int_mod);
+ }
+ }
+}▲ 注意 LAN743X_CSR_FLAG_IS_A0 判断:A0 硅片版本不写调制寄存器(驱动既有约束)。is_pci11x1x 的芯片多 2 个向量寄存器(CFG8/CFG9),其余 8 个一致。
mac_cr &= ~(MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
- if (speed == SPEED_2500)
+ if (speed == SPEED_2500) {
mac_cr |= MAC_CR_CFG_H_ | MAC_CR_CFG_L_;
- else if (speed == SPEED_1000)
+ int_mod = LAN743X_INT_MOD_2_5G;
+ } else if (speed == SPEED_1000) {
mac_cr |= MAC_CR_CFG_H_;
- else if (speed == SPEED_100)
+ int_mod = LAN743X_INT_MOD_1G;
+ } else if (speed == SPEED_100) {
mac_cr |= MAC_CR_CFG_L_;
+ int_mod = LAN743X_INT_MOD_100M;
+ } else {
+ int_mod = LAN743X_INT_MOD_10M;
+ }
lan743x_csr_write(adapter, MAC_CR, mac_cr);
+ lan743x_config_int_mod(adapter, int_mod);
+
lan743x_ptp_update_latency(adapter, speed);▲ 原来 link_up 只配 MAC 速率位(MAC_CR_CFG_H_/L_),现在同一处把调制值也一起更新——调制周期与链路速率在同一路径上原子更新,避免"速率已变、聚合周期未变"的窗口。
+static int lan743x_ethtool_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ /* The driver programs the same value into every per-vector
+ * INT_MOD_CFG register, so RX and TX moderation share one value;
+ * report it for both.
+ */
+ ec->rx_coalesce_usecs = adapter->int_mod;
+ ec->tx_coalesce_usecs = adapter->int_mod;
+ ec->use_adaptive_rx_coalesce = adapter->use_adaptive_mod;
+ ec->use_adaptive_tx_coalesce = adapter->use_adaptive_mod;
+
+ return 0;
+}▲ 读取侧:因为硬件单值,RX/TX 报同一值;自适应标志也同步报出。返回的是当前已编程的 adapter->int_mod(即实际生效值)。
+ /* RX and TX share a single moderation value, so adaptive mode must be
+ * enabled or disabled for both together.
+ */
+ if (ec->use_adaptive_rx_coalesce != ec->use_adaptive_tx_coalesce) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "adaptive-rx and adaptive-tx must match");
+ return -EINVAL;
+ }
+
+ if (ec->use_adaptive_rx_coalesce) {
+ /* Resume speed-adaptive moderation and apply the value for the
+ * current link speed right away.
+ */
+ adapter->use_adaptive_mod = true;
+ int_mod = lan743x_get_int_mod(adapter->link_speed);
+ } else {
+ if (ec->rx_coalesce_usecs != ec->tx_coalesce_usecs) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx-usecs and tx-usecs must be equal");
+ return -EINVAL;
+ }
+ if (ec->rx_coalesce_usecs > LAN743X_INT_MOD_MAX) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "coalesce value exceeds maximum");
+ return -EINVAL;
+ }
+ adapter->use_adaptive_mod = false;
+ int_mod = ec->rx_coalesce_usecs;
+ }
+
+ lan743x_config_int_mod(adapter, int_mod);
+
+ return 0;
+}▲ 三条硬约束全部用 NL_SET_ERR_MSG_MOD 给出可读原因:自适应必须 RX/TX 同时开;手动模式 RX 必须等于 TX(硬件单值);上限 LAN743X_INT_MOD_MAX (8191)(13-bit 定时器字段)。
+ /* Nothing to do if the value is already programmed in hardware. */
+ if (int_mod == adapter->int_mod)
+ return;
+
if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
lan743x_csr_write(adapter, INT_MOD_CFG0, int_mod);
lan743x_csr_write(adapter, INT_MOD_CFG1, int_mod);
@@ -3049,6 +3068,7 @@ static void lan743x_config_int_mod(...)
lan743x_csr_write(adapter, INT_MOD_CFG8, int_mod);
lan743x_csr_write(adapter, INT_MOD_CFG9, int_mod);
}
+ adapter->int_mod = int_mod;
}
}
...
lan743x_csr_write(adapter, MAC_CR, mac_cr);
- lan743x_config_int_mod(adapter, int_mod);
+ /* Track the link speed so a later ethtool request to re-enable
+ * adaptive moderation can restore the speed-based value, and refresh
+ * the timer now when adaptive moderation is active.
+ */
+ adapter->link_speed = speed;
+ if (adapter->use_adaptive_mod)
+ lan743x_config_int_mod(adapter, lan743x_get_int_mod(speed));
lan743x_ptp_update_latency(adapter, speed);
...
+ /* Enable speed-adaptive interrupt moderation by default and program
+ * the timer for the default (1G) value until the link comes up.
+ */
+ adapter->use_adaptive_mod = true;
+ adapter->link_speed = SPEED_UNKNOWN;
+ lan743x_config_int_mod(adapter, LAN743X_INT_MOD_1G);
ret = lan743x_gpio_init(adapter);▲ int_mod 缓存避免值未变时重写全部 10 个 CSR;link_up 只在自适应开启时才重算(手动模式下用户固定值不被链路事件覆盖);hardware_init 把自适应设为默认并预写 1G 值。
📈 性能影响
- 2.5G/1G 场景:聚合延迟从 400us 降到 64us/150us,对延迟敏感负载有利;代价是单包聚合批变小、中断率上升(CPU 开销可能略增)——属于"用中断率换延迟"的再平衡。
- 100M/10M 场景:400us→330us 变化不大;真正收益是用户态可进一步调大或调小。
- 默认值改动有行为面影响:原固定 400us → 默认自适应,对"已经习惯 400us 行为"的存量部署属静默行为变化。
- 以上均为方向性推断,未经验证,需实测才能定量。
🔄 方案演进
⚠️ 风险与局限
-EINVAL)。对需要"RX 低延迟、TX 高聚合"不对称调优的用户不可用。这是硬件能力限制,驱动层面只能拒绝而非支持(解读(AI 分析):代码注释明确说明寄存器同值写入,属客观约束)。
- 默认从固定 400us 变为自适应:存量行为变化,可能影响对延迟/中断率敏感的既有部署。
- A0 硅片无效:
LAN743X_CSR_FLAG_IS_A0分支不写调制寄存器,此功能在 A0 版本硬件上不生效(既有约束,非本系列引入)。 - 链路未 up 时开启自适应:
adapter->link_speed初始为SPEED_UNKNOWN,此时开启自适应会落到lan743x_get_int_mod()的 default 分支 → 330us(10M 档),直到下次 link_up 才纠正。属轻微边缘行为。 - 默认值缺少出处:64/150/330 三个数值未标注 datasheet/测试依据,review 时可能被追问。
- 无性能数据:v1 未附 benchmark,合入前可能被 netdev 维护者要求补充。
🔗 交叉引用
- ethtool 标准接口:
ETHTOOL_COALESCE_USECS/USE_ADAPTIVE_RX/USE_ADAPTIVE_TX是内核 ethtool 对网卡聚合能力的标准声明,本系列让 lan743x 与该标准对齐。 - 自适应聚合先例:Intel e1000e/igc/ice、Broadcom bnxt 等驱动早已支持 adaptive coalescing,本系列把 lan743x 带入同类能力。
- 驱动现状(本次核查):本地内核 master 工作树(SHA c98e10d9)中 lan743x 仍为补丁前状态——
lan743x_intr_open()写入固定LAN743X_INT_MOD(400)到全部INT_MOD_CFG0-9(寄存器 0x7C0-0x7E4),link_up()只配MAC_CR速率位不更新调制值。与本系列 cover letter 描述一致。 - 相关讨论:因 lore 检索服务本次不可用,未能获取本系列所在邮件线索的回复(详见方案演进节)。
✅ 关键洞察
- 本质:这不是一个"换更快的代码",而是一个"把硬件能力暴露给用户 + 让默认值更合理"的功能补全——把固定 400us 拆成随速率的 64/150/330us,并补上 ethtool -c 接口。
- 设计亮点:对硬件"单值共享"约束采用显式拒绝 + extack 可读报错,而非静默忽略;
adapter->int_mod缓存避免 link_up 时无谓重写 10 个 CSR,是干净的微优化。 - 结构:两枚补丁职责分明(先解耦/速率化,后加用户接口),提交粒度合理,便于 review 与回退。
- 短板:无任何性能数据,默认值(64/150/330)缺出处,A0 硅片不支持——这三项是合入 net-next 前最可能被维护者追问的点。
- 后续关注:v2 是否补充 benchmark、是否调整默认值、review 讨论中是否有对"自适应默认开启"这一行为变化的异议(解读(AI 分析))。
本站内容均由 AI 基于公开知识辅助生成,仅供学习参考,请勿直接引用作为依据。作者不对信息的准确性、完整性及适用性作保证,亦不对因使用本站内容产生的任何损失承担责任。