news 2026/8/29 11:40:19

Linux GICv3 ITS 翻译表:从 DeviceID 到 LPI 的一次完整走读

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux GICv3 ITS 翻译表:从 DeviceID 到 LPI 的一次完整走读

Linux GICv3 ITS 翻译表:从 DeviceID 到 LPI 的一次完整走读

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

一块 NVMe 盘开满 8 个队列需要 8 个 MSI 向量,而 SPI 中断号最多只有 992 个,且路由基本绑死在固件上;设备一多、队列一开,中断号就不够分了。Linux 内核里 GICv3 的 ITS(Interrupt Translation Service,中断翻译服务)就是为此设计的:它把每条 MSI 消息翻译成 LPI(Locality-specific Peripheral Interrupt),并动态路由到目标 CPU。下面按"翻译原理 → 内核关键路径 → 设备树 → 运行时调优"的顺序,把 Linux GICv3 ITS 从头到尾讲一遍,读完你可以直接对照自己的设备树和源码排查问题。

📌 问题:为什么 SPI 撑不住了

GICv3 本身支持四类中断:

  • SGI(Software Generated Interrupt,软件生成中断):CPU 之间互发,编号 0–15
  • PPI(Private Peripheral Interrupt,私有外设中断):每个 CPU 一份私有
  • SPI(Shared Peripheral Interrupt,共享外设中断):外设共享,编号 32–1023
  • LPI(Locality-specific Peripheral Interrupt):靠 MSI 消息触发,从 8192 起步

LPI 的存在本身就是答案。旧方案和它的对比一目了然:

传统 SPI 路由ITS + LPI
可用中断编号992 个(32–1023),全系统共享从 8192 到 2^32-1,规模由硬件 IDBITS 字段决定
中断到 CPU 的绑定固件阶段配死,运行时改动麻烦每条 LPI 可单独改亲和性

数字锚点:LPI 编号起点 8192 来自源码里的硬编码(SGI/PPI/SPI 占用前 8192 个编号);优先级寄存器 8 位,共 256 级。

🧭 翻译怎么发生:三个步骤

1. 消息到达

设备发的 MSI 本质上是一条指向 ITS 的 TLP 消息,目标地址就是 ITS 的 Translater 寄存器(GITS_TRANSLATER,偏移 0x10040)。这条消息里藏着两个字段:DeviceID 和 EventID。

2. 查表翻译

ITS 内部依次走三张表,内核初始化时负责把它们填好:

索引起点表项指向内核对应命令
Device TableDeviceID该设备的中断翻译表(ITT)基址MAPD
Interrupt Translation TableEventID一个 LPI 中断号MAPTI
CollectionLPI 中断号目标 CPU 的亲和性MAPC / MOVI

举个具体数值:DeviceID=0x21、EventID=3 的消息进来,Device Table 第 0x21 条指向 ITT,ITT 第 3 条读出 LPI 中断号 8196,Collection 表说 8196 归 CPU 5。

3. 路由到目标 CPU

重分布器(Redistributor,每个 CPU 一个)按 Collection 指向把这条 LPI 投递出去,目标核跑它的处理程序。翻译完成之后,MSI 的后续处理完全在硬件里完成,不占 CPU 周期。

翻译表是内核建起来的,靠的是 ITS 命令队列:

命令队列的固定顺序是 MAPD → MAPC → MAPTI → MOVI → SYNC:先绑设备、再绑 Collection、然后填 EventID 映射、需要时改亲和性,最后 SYNC 使缓存失效。队列满了内核会等它排空再写,这一段逻辑全部在 drivers/irqchip/irq-gic-v3-its.c 里。

🔍 内核关键路径:从探测到 MSI domain

入口是 drivers/irqchip/irq-gic-v3-its.c 里的its_init():它按设备树或 ACPI 遍历所有 ITS 节点,逐个走its_probe_one()——分配命令队列页、调its_alloc_tables()建三张表、写 CBASER 挂上队列、置位 GITS_CTLR_ENABLE 使能硬件;随后allocate_lpi_tables()全局分配 LPI 属性表,最后给每个 ITS 注册一个 MSI domain。

值得单独看的是注册这一步:父 domain 指回 GICv3 主 domain,子 domain 承载 MSI 向量分配逻辑。没有这一段,设备树里所有msi-parent指向 ITS 的设备都拿不到 MSI 向量。

static int its_init_domain(struct its_node *its) { struct irq_domain_info dom_info = { .fwnode = its->fwnode_handle, .ops = &its_domain_ops, .domain_flags = its->msi_domain_flags, .parent = its_parent, }; struct msi_domain_info *info; info = kzalloc_obj(*info); if (!info) return -ENOMEM; info->ops = &its_msi_domain_ops; info->data = its; dom_info.host_data = info; return msi_create_parent_irq_domain(&dom_info, &gic_v3_its_msi_parent_ops) ? 0 : -ENOMEM; }

its_msi_domain_ops挂在一组操作后面:设备pci_enable_msi_range()要 N 个向量时,内核从 LPI 号池切一段连续的 LPI 给它,逐条填好翻译表,设备驱动全程只用标准 MSI 接口,对 ITS 无感知。

🧩 设备树里怎么写 ITS 节点

GICv3 节点和 ITS 节点的完整写法可以对照 Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml 的官方示例。精简版如下:

gic: interrupt-controller@2cf00000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; #address-cells = <1>; #size-cells = <1>; ranges; interrupt-controller; reg = <0x2f000000 0x10000>, /* GICD 分发器 */ <0x2f100000 0x200000>; /* GICR 重分布器基址 */ /* ITS 作为子节点,每个实例一个 */ its0: msi-controller@2c200000 { compatible = "arm,gic-v3-its"; msi-controller; /* 标记它是 MSI 控制器 */ #msi-cells = <1>; /* 恒为 1:设备号 */ reg = <0x2c200000 0x20000>; /* ITS 寄存器空间 */ }; }; nvme: nvme@01000000 { compatible = "pci-nvme"; msi-parent = <&its0>; /* MSI 请求交给 ITS */ interrupts-msi = <1 0>; /* 1 个向量,EventID 从 0 起 */ };

逐段说明:compatible = "arm,gic-v3-its"是内核its_of_probe()匹配的钥匙;#msi-cells必须写 1,因为 MSI 父数据只有一个 DeviceID;外设不再用interrupts,改用msi-parentinterrupts-msi,向量数量由 PCI 枚举阶段协商。属性细节(比如mbi-rangesredistributor-stride的写法)以官方绑定文档为准,链接见上文。

⚙️ 跑起来之后还能调什么

  • 中断亲和性echo "3" > /proc/irq/<lpi号>/smp_affinity把中断挪到 CPU 0、1。需要它的场景:某个核被某设备的中断打满、邻居核却闲着时。
  • 优先级:GICv3 的优先级寄存器 8 位、256 级,数值越小越优先。LPI 的优先级在启动时统一设置,SPI 可在 DTS 中断单元格第三位逐条指定。需要它的场景:把关键设备(如存储控制器)的中断压过大量低优先级设备的噪声。
  • 多 ITS 实例:并列写多个 ITS 节点即可,内核会把设备分摊到不同实例。需要它的场景:设备数上万的平台,用多个实例分摊命令队列和翻译表压力;小设备数的单板 SoC 通常一个 ITS 足够。

一句话收尾

Linux GICv3 ITS 做的事情很克制:把 DeviceID + EventID 翻译成 LPI,再把这条 LPI 动态指向目标 CPU,其余交给硬件。源码入口 drivers/irqchip/irq-gic-v3-its.c,设备树写法看 Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml,寄存器与命令定义以 ARM 官方 GICv3/v4 架构规范(IHI 0069)为准。

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 11:39:36

爱奇艺前端二面面经:性能优化、大文件上传与微前端实战复盘

这份爱奇艺前端二面面经&#xff0c;我拖了两周才动笔写。不是懒&#xff0c;是有些题当时没答好&#xff0c;回来复盘越想越觉得自己“欠练”&#xff0c;那种被按在地上摩擦的感觉需要缓缓。现在情绪平复了&#xff0c;把整场面试从流程到题目到回答思路&#xff0c;原原本本…

作者头像 李华
网站建设 2026/8/29 11:38:15

9款AI写论文哪个好?测完发现,文献“保真”这一关就淘汰了8个

官网&#xff1a;www.shujiangce.com | 微信 公众号 &#xff1a;书匠策AI 各位同学好&#xff0c;我是那个专门帮你们测评论文工具的教育博主。 毕业季后台全是催更——“某某AI写论文到底靠不靠谱&#xff1f;”“文献是编的还是真的&#xff1f;”“生成的图表能直接用吗…

作者头像 李华
网站建设 2026/8/29 11:35:15

货拉拉大数据中心笔试题复盘:SQL与数仓建模的实战要点

“货拉拉2018秋招大数据中心笔试题”——单看这个标题&#xff0c;可能觉得是一份过期真题&#xff0c;没什么参考价值。但我在准备秋招时正好卡在那个时间节点&#xff0c;这份笔试给我的冲击相当大。它没有堆砌偏题怪题&#xff0c;而是把Hadoop、Spark、数据仓库建模和实际物…

作者头像 李华
网站建设 2026/8/29 11:34:26

Hermes Agent 5分钟搭好性能监控,不再盲猜

Hermes Agent 5分钟搭好性能监控&#xff0c;不再盲猜 【免费下载链接】hermes-agent The agent that grows with you 项目地址: https://gitcode.com/GitHub_Trending/he/hermes-agent 凌晨两点&#xff0c;用户反馈 Agent 响应变慢。你翻日志&#xff0c;只有几行报错…

作者头像 李华
网站建设 2026/8/29 11:30:50

写文献综述怎么选AI?我从通用大模型聊到毕业之家

又到开题季&#xff0c;很多同学最头疼的不是“写不出来”&#xff0c;而是&#xff1a; 文献读了几十篇&#xff0c;还是串不成研究脉络&#xff1b;AI 给的参考文献看起来像模像样&#xff0c;一查作者、年份、期刊全是编的&#xff1b;生成内容像“文献流水账”&#xff0c;…

作者头像 李华
网站建设 2026/8/29 11:30:43

集群高峰下先守住解析链路

集群高峰下先守住解析链路高并发场景下保障 Kubernetes 集群的稳定性&#xff0c;关键在于精准定位并巩固基础设施层与内核层面的关键瓶颈点。 排查高并发下的解析超时时&#xff0c;先区分业务 Pod、DNS 服务和节点网络三层指标。业务扩容并不会自动消除 DNS 查询放大、连接池…

作者头像 李华