小摩羯今天开始正式对GIC伸出了魔爪。GIC入门的部分感兴趣的铁子可以去看我的另一篇文章穿越之我在西安搞PCIE——GIC入门-优快云博客。本篇文章主要讲我读完《Arm Generic Interrupt Controller ArchitectureSpecification GIC architecture version 3 and version4》协议的第五章“Locality-specific Peripheral Interrupts and the ITS”之后,对LPI和ITS相关的一些理解(不包括virtual interrupt),不太准确的地方希望各位佬们帮我指出来,大家一起进步,感激不尽。
1.LPIs
LPIs(Locality-specific Peripheral Interrupts)是基于边缘触发的基于消息的中断,如果实现了ITS,可以ITS将中断路由到与特定的GICR连接的PE。 GICv3为LPI提供了两种类型的支持:
1)使用ITS将设备的EventID转换为LPI INTID。
2)通过GICR_SETLPIR寄存器直接将LPI INTID发送给Redistributor
实现必须只能支持两种方法中的一种。
如果没有实现ITS而要使用LPI中断,必须实现下列寄存器:GICR_INVLPIR、GICR_INVALLR、GICR_SYNCR。
在不包含ITS的系统中使用GICR_SETLPIR和GICR_CLRLPIR寄存器控制物理LPI,其中
GICR_SETLPIR该寄存器通过设置指定LPI的pending状态来生成LPI,GICR_CLRLPIR寄存器清除指定的LPI的pending状态。
如果实现了LPI,至少需要支持8192个LPI中断,每个中断的配置、pending信息都需要在内存中建立一些表来保存这些信息。图1描述了包含ITS的LPI中断传输。 图2描述了不包含ITS的LPI中断传输。
图1 包含ITS的LPI传输
图2 不包含ITS的LPI传输
当GICD_CTLR.DS==0时(DS, disable secure):
1)当非安全状态的亲和性路由使能时仅支持LPI。
2)LPI通常为非安全Group1中断。
当GICD_CTLR.DS==1时:
1)当亲和性路由使能时仅支持LPI。
2)LPI通常为Group1中断。
只有一个全局的物理LPI空间,因此LPI可以在所有的GICR之间移动,软件使用GICR_PROPBASER寄存器的ID位(bit[4:0])对全局物理LPI空间大小进行编程。
注:物理LPI空间的大小受限于实现支持的最大大小,该大小由GICD_TYPER寄存器的ID位(bit[23:19])定义。
LPI的配置和状态分别由内存中分配的LPI配置表和LPI状态表来维护。
1)需要在LPI配置表中配置LPI优先级和使能位,LPI配置表的地址通过GICR_PROPBASER寄存器配置。每个LPI中断占8个bit,包括1bit的使能位,6bit的优先级和1bit的保留位,这个LPI中断配置表需要软件维护,且所有GICR都要使用同一个LPI配置表,也就是每个GICR_PROPBASER所配置的LPI配置表的地址都是同一个。
2)为GICR_PENDBASER寄存器配置LPI Pending表,该表记录了当前GICR上被挂起的LPI中断,挂起的LPI可以上报到处理器进行处理,每个GICR表需要配置独立的LPI Pending表,这个表中,每一个bit位标识一个LPI的pending状态,从表的基地址开始的第0bit表示8192号中断,当某个bit被置为1,表示对应LPI中断已经处于pending状态,等待处理。当GICR_CTLR.EnableLPI==1时,如果GICR_PROPBASER被更新,结果是未知的。
GICR_PROPBASER寄存器的ID位设置ID space的大小,从而确定LPI配置表的entry数目和LPI pending表的数目。通过配置GICR_CTLR的bit[0]使能LPI中断。如果未使能,LPI中断信号无法发送到CPU接口,无法pending。
1.1 LPI configuration table
LPI 配置表是全局的(所有的 GICR都使用同一份 LPI 配置表),GIC 是否支持 GICR 指向不同的 LPI 配置表是实现定义的。
GICR_PROPBASER指定了一个4KB对齐的物理地址。这是LPI配置表的基地址。对于任何LPI N,entry的位置由(基地址+(N-8192))定义。
若要更改中断的配置,软件会写入LPI配置表,然后发出INV或INVALL命令。在不包含ITS的实现中,软件会写入GICR_INVALLR或GICR_INVLPIR。
LPI配置表为每个LPI 分配了一个8bit的entry,包括1bit的使能位,6bit的优先级和1bit的保留位,如图三所示:
图三 LPI Configuration table entry
1.2 LPI pending table
软件通过写入GICR_PENDBASER 指定 LPI pending 状态表基地址。每一个 GICR 都维护自己的 LPI pending 状态表,用单独的位表示某一个 LPI 的状态信息:
0:not pending
1:pending
LPI pending表使用 1KB 对齐的物理内存,如果pending信息表全 0,那么表示没有挂起的LPI
对于某一指定的 LPI:
Pending 表对应的 Pending 字节位置为 baseaddr + (N /8)
Pending 表对应的 Pending 位为 (N MOD 8)
注:每个GICR的pending表的Outcache,Shareability或者Innercache属性配置的都应该相同,如果不相同,那么LPI使能之后的所发生的事情是不可预测的。
注:如果GICR_PENDBASER的PTZ位(Pending Table Zero)==1时,pending表只包含0,硬件可能无法捕获到软件产生的LPI pending状态。
注: 如果实现了一个或者多个ITS,Arm建议在某一GICR关闭LPI使能之前映射到另一个GICR上。
2.ITS
ITS(Interrupt Translation Service) 将不同设备(通过Device ID)传入的Event ID翻译为INTID,目标处理器的GICR根据INTID做出对应的处理。
ITS的翻译流程如下所示:
1)根据DeviceID 在Device table中选择一个设备表项(DTE,Device table entry ),该表项描述要使用的中断翻译表(ITT,Interrupt translation table)。
2)EventID会在所描述的ITT中选择一个中断转换表项(ITE,Interrupt translation entry),该表项用于确定输出的LPI中断向量号(INTID)和中断集合ID号(ICID,Interrupt collection number)。
3) ICID从CT(Collection table )表中选择一个表项,用于确定处理目标PE中断的GICR。
注:Device Table: 根据Device ID对不同的设备都分配的一个表项,用于保存该设备使用的中断翻译表(ITT)。
中断翻译表:保存 EventID 与 LPI ID 的对应关系。
CT表:保存ICID与目标 GICR 的对应关系
2.1 ITS table
软件为 ITS 私有表提供内存,GIC提供了一组寄存器 - GITS_xxxR,用于实现以下功能:
1) ITS 需要的私有表的数量
2)每个表的entry大小
3)每个表的类型
GITS_BASER<n>指定了ITS表的基本地址和大小,并且必须在ITS使能之前进行配置。
ITS有一级表和二级表,是通过GITS_BASER<n>的Indirect位决定的。如果该bit位 == 0,使用一级表,当前表包含连续的 block 结构,block 格式是实现定义的。如果该bit位 == 1,使用二级表,在当前情况下,一级表中的每个entry都是64位,并且具有以下格式:
Bit[63] - Valid 位,置1表示有效,指向二级表基地址。
Bit[62 : 53] - 预留位
Bit[51 : N] - 二级表的基地址,N 表示 page size 大小所需要的位数,page size由GITS_BASER<n>.Page_size决定
Bit[N-1 : 0] - 预留位
图4描述了如何在翻译过程中使用这些表。
图4 The Interrupt Translation Service
2.2 Interrupt collections
ITS 认为所有生成的物理 LPI 是一个 Collections 的成员,Collection Table 的基地址通过GITS_BASER<n>寄存器指定,GITS_BASER<n>.Type == 0b100表示该表是collection表。collection表同样分为一级表和二级表。
2.3 Device table
设备表提供了设备表项(DTEs)。每个DTE都描述了DeviceID和ITT基地址之间的映射,它指向ITS可用于存储EventID的翻译的内存。ITS使用ITT来存储针对指定设备ID的每个EventID的翻译。DeviceID是分配给每个可以创建EventID范围的设备的唯一标识符。例如,Arm期望来自PCIe RC的16位requester ID作为DeviceID呈现给ITS。
DeviceID为该表提供了索引值。
2.4 The Interrupt translation table
每个设备都有自己的中断翻译表(ITT),翻译表可以对应多个事件的 LPI 中断翻译。ITT中的每个entry都被称为中断翻译条目(ITEs)。
ITT 表的大小由设备表的表项中的 ITT Range 位决定,它的大小为2^(DTE.ITT Range+ 1)* GITS_TYPER.ITT_entry_size。ITT 拥有与设备表相同的Shareability和 cache 属性。
对于物理中断,每个ITE都描述了:
1)输入EventID和发送到目标PE的输出物理INTID(pINTID)之间的映射。
2)输入EventID和ICID的对应关系,它确定LPI的目标PE。
EventID 是 ITT 的索引。
2.5 collection table
Collection table保存中断集合号 - ICID 与目标 GICR的地址的映射关系。每一个 ITS 都有一个 CT。ICID 提供 CT 使用的索引值。
2.6 Control and configuration of the ITS
GITS_IIDR and GITS_PIDR2 | 版本信息 |
GITS_TYPER | ITS 支持的特性 |
GITS_CTLR | ITS 配置 |
GITS_TRANSLATER | 接收 EventID |
GITS_BASER | 提供 ITS 私有表的地址、大小、访问属性 |
GITS_CBASER / GITS_CREADR / GITS_CWRITER | 存储ITS 命令队列的地址信息 |
2.7 ITS command interface
图5描述了ITS如何提供ITS命令队列所使用的基地址和大小。ITS命令队列entry的大小为32个字节。这意味着在每个4KB的页面中都支持128个entry。ITS 命令队列基地址是 64KB 对齐的,队列大小 4KB 对齐。
当第一个命令完成后,ITS将开始处理下一个命令。读指针GITS_CREADR 的移动由 ITS 硬件控制,如果GITS_CREADR到达GITS_CBASER中指定的内存的顶部,则跳回GITS_CBASER中指定的基地址。GITS_CWRITER由软件控制。
当GITS_CWRITER和GITS_CREADR指定相同的基本地址偏移值时,ITS命令队列为空。当GITS_CWRITER指向缓冲区中GITS_CREADR后面32字节的地址时,ITS命令队列已满。
当GITS_CREADR.stalled== 1时,不再处理后续命令。
GITS_CBASER:指定ITS命令队列的基本地址和大小。
GITS_CREADR: 指定 ITS 将要处理的下一个命令的偏移量。
GITS_CWRITERGITS:指定软件将下一个命令写入下一个entry的偏移量。
2.8 Ordering of translations with the output to ITS commands
每个命令队列条目似乎都是原子执行的,以便转换请求可以在命令之前看到ITS的状态,或者在命令之后看到ITS的状态。在SYNC或VSYNC命令完成后启动的转换请求使用与命令执行后状态一致的ITS状态进行转换。如果没有SYNC或VSYNC命令,则该架构不会定义ITS命令和翻译请求的顺序。
2.9 Restrictions for INTID mapping rules
1)将多个 DeviceID - EventID 组合映射为同一个 LPI 中断会产生不可预测的结果。
2)任一 LPI 中断只能由一个 Redistributor 处理。
2.10 ITS commands
ITS commands被 ITS 硬件用来维护 ITS 私有表,创建 ITS 中断翻译过程中使用的映射关系。需要在 ITS 中断使能之前,完成各私有表的映射关系初始化。具体的commands参见《Arm Generic Interrupt Controller ArchitectureSpecification GIC architecture version 3 and version4》第5.3小节。
参考资料:《Arm Generic Interrupt Controller ArchitectureSpecification GIC architecture version 3 and version4》