Bootstrap

【PCIe 总线及设备入门学习专栏 4 -- PCIe GIC LPI 与 MSI 中断机制】


ARM GIC 学习专栏 --> 点击这里 <—

1. GICv2

ARM的 cpu,特别是 cortex-A 系列的 CPU,都是多 core 的 cpu,因此对于多 core 的 cpu 的中断管理,就不能像单 core 那样简单去管理,由此 arm定义了GICv2 架构,来支持多核 cpu 的中断管理。GICv2,支持最大 8个 core。其框图如下图所示:
在这里插入图片描述

Fiture 1-1 ARM GICv2


GICv2 中断类型

在这里插入图片描述

Fiture 1-2 ARM GICv2 内部实现


GICV2有3种中断:

  • 软件触发中断(SGI,SoftwareGenerated Interrupt)
    这是由软件通过写入专用仲裁单元的寄存器即软件触发中断寄存器(ICDSGIR)显式生成的。它最常用于CPU核间通信。SGI既可以发
    给所有的核,也可以发送给系统中选定的一组核心。中断号0-15保留用于SGI的中断号。用于通信的确切中断号由软件决定。
  • 私有外设中断(PPI,Private Peripheral Interrupt)
    这是由单个CPU核私有的外设生成的。PPI的中断号为16-31。它们标识CPU核私有的中断源,并且独立于另一个内核上的相同中源,
    比如,每个核的计时器。
  • 共享外设中断(SPI,Shared Peripheral Interrupt)
    这是由外设生成的,中断控制器可以将其路由到多个核。中断号为32-1020。SPI用于从整个系统可访问的各种外围设备发出中断信号

在GICv2里, 设备向中断控制器发出中断,必须使用物理上的线路:
在这里插入图片描述

Fiture 1-3 Dedicated interrupt signal


在复杂系统中有成本上千的中断时, 就需要成本上千的中断信号线这太复杂了
于是在GICv3中引入 MSI(“message-based interrupts”), 设备往某个地址写入数值,即可触发中断

2. GICv3

2.1 MSI

在GICv3里,添加了 MSI(“message-based interrupts”), 设备往某个地地址写入数值, 即可触发中断:
使用消息来发送中断, 好处是可以省略硬件线路。在大型系统中有成百上千个中断,使用MSI可以省下很多线路。
在这里插入图片描述

Fiture 1-4 GIC MSI


2.2 GICv3 内部结构

GICV3里新增加了一类中断: IPI(Locality-specific Peripheral Interrupts)

GICv3 框图如下:

在这里插入图片描述

Fiture 1-4 GIC logical partitioning with an ITS


1. 设备写 GITS_TRANSLATER 触发中断
2. 设备写 GICR_SETLPIR 触发中断

对于原来的 SPI, 它也是可以使用MSI的方式传递的,这个功能是可选的。如果GICV3支持MSI方式的SPI,要产生/清除中断时, 操乍如下
GIC寄存器:

  • 产生中断:写寄存器 GICD_SETSPI_NSR或 GICD_SETSPI_SR
  • 清除中断:写寄存器 GICD_CLRSPI_NSR 或 GICD_CLRSPI_SR

对于LPI中断,有两种触发方式:

  • 写寄存器 GITS_TRANSLATER
    • 设备把数据写入GITS_TRANSLATER寄存器,写入的值被称为EventlD
  • 写寄存器 GICR_SETLPIR

2.3 中断号

0~1023跟GICv2保存一致。
在这里插入图片描述

3. LPI 的触发方式

LPI有两种触发中断的方式:

  • 把INTID直接写入GICR_SETLPIR寄存器
  • 使用 ITS把 EventID 转换为 LPI INTID, 会用到 “GITS_TRANSLATER” 寄存器

这两种方法只能支持一种。

3.1 使用 GICR_SETPIR

这个寄存器格式如下:
在这里插入图片描述
把LPI的中断号写入这个寄存器即可触发中断。

使用 ITS

ITS 的意思是:Interrupt Translation Service,中断转换服务。
在这里插入图片描述
能产生 MSI 中断的设备, 都有一个 DeviceID (设备ID), 它产生的每一个MSI中断都有一个EventID(事件ID)。"DevicelD+EventlD"组合被传入ITS,IDS会把它们转换为INTID。

过程如下:

  • 外设发生中断消息(Interrupt Message)到ITS
    • 外设只要写 GITS_TRANSLATER 就可以发送消息, 这个寄存器格式如下:
      在这里插入图片描述
    • 消息里包含有: DevicelD(哪一个设备)、EventlD(这个设备的哪一个中断)
  • ITS 使用 DevicelD 在 Device Table 中找到 一项
    • 只有一个Device Table
    • 每一个能发生MSI中断的设备在里面都有一项,它指向这个设备的Interrupt Translation Table(中断转换表,简称ITT)
    • 每一个能发生MSI中断的设备,都有一个ITT
  • ITS使用EventID在ITT中找到一项,从中返回INTID和Collection |D
  • ITS使用Collection ID在Collection Table中找到一项,从中返回"Target Redistributor",即:中断发给哪个CPU
  • ITS把INTID发给Redistributor
    在这里插入图片描述
    假设有N个设备可以发出 LPI 中断,或者可以发出基于消息的中断,这N个设备都会有ID,Device1, Device2,Device3… 。每个设备都会有一个中断转换表 interrupt Translation Table,这些表都是放在内存里面的,那么怎么找到这个表呢?在 Device Table 中都会有一项,存放的是 interrupt Translation Table 的首地址。设备把消息发给 ITS 之后,消息里面含有设备ID 和 EventID,
    在这里插入图片描述
    设备 ID 表示 这个中断是有这个设备发出的,EventID 表示我这个设备发出的时哪个中断,比如某个设备可以发出多个中断。N个设备里面第一个设备它可以发出M个事件,每个事件都会有个ID, 首先会根据 Interrupt Message 中的 Device ID 在 Device Table 里面找打一项,从这项里面就可以找到这个设备的中断转换表格 interrupt Translation Table 在哪里,这个表格就是用来为这个设备服务的,每个设备都会有个表格,这个表格里面会含有 M 项,每一项里面会含有 INTID 和 Collection ID , 这个 INTID 要发给哪个 Redistributor 是由 Collection ID 决定的, 根据 Collection ID 在 Collection Table 中找到某一项,这一项里面会含有发给哪一个 Redistributor , 也就是发给哪个CPU,
;