Redistributor
Redistributor通过内存中的表来对所有的物理LPI进行控制,优先级调节,pending信息控制。
LPI的配置信息存放在内存的表中。LPI配置表由GICR_PROPBASER指向。LPI配置表是全局的,即所有的Redistributor必须看到相同的配置。典型的是一个系统有单独的由所有Redistributor共享的LPI配置表。
类似的,LPI的状态信息存放在内存的表中。LPI pending表由GICR_PENDBASER指向。每个Redistributor都有自己的LPI pending表,这些表不会在Redistributor共享。
1. Redistributor的初始化配置
系统中初始化Redistributor的步骤如下:
(1)为LPI配置表分配内存,采用合适的配置对每个LPI进行初始化表;
(2)设置每个Redistributor的GICR_PROPBASER指向LPI配置表;
(3)为每个Redistributor的LPI pending表分配内存,并初始化每个表的内容。在系统启动时,这通常意味着将内存(所有LPI INTID都处理inactive状态)清零。
(4)设置每个Redistributor的GICR_PENDBASER指向与每个Redistributor相关的LPI pending表;
(5)设置每个Redistributor的GICR_CTRL.EnableLPIs来使能LPI。当GICR_CTRL.EnableLPIs设置为1时,GICR_PENDBASER和GICR_PROPBASER寄存器变成只读。
LPI配置表
LPI配置表为每个LPI INTID分配一个byte。每个条目的格式:
虽然SPI/PPI/SGI的优先级值有8bit,但表中只有6bit来记录LPI的优先级。LPI优先级的低2位一直为0b00。
没有域来记录安全配置。LPI通常为非安全group1中断。
LPI配置表的大小和要分配的内存大小依赖于LPI的数量。GIC支持的最大INTID的数目由GICD_TYPER.IDbits决定。LPI配置表处理LPI,LPI使用的INTID超过8191。因此支持的可能的配置表大小可通过如下公式计算:
Size in bytes - 2~GICD_TYPER.IDbits+1 - 8192
但是,也可能支持更小的INTID。GICR_PROPBASER包含IDbits域,这指明了LPI配置表支持的最大INTID。这个值必须等于或小于GICD_TYPER的值。软件必须为这些条目分配足够的内存。在这种情况LPI配置表要求的大小变为:
Size in bytes = 2~GICR_PROPBASER.IDbits+1 - 8192
中断控制器必须可以读LPI配置表的内存。但它不能写这些内存。
LPI pending表
LPI 状态信息保存在内存中。LPI有两个状态,inactive和active。
当中断被答应时中断转换从pending到inactive。
由于只有两个状态,只需要在LPI pending表中1bit。因此,为支持可能实现的所有INITID,表必须:
Size in bytes = (2~GICR_TYPER.IDbits + 1)/8
不像LPI配置表,LPI pending表的大小不适合LPI开始于INTID 8192。表的前1KB(与INTID 0到8191)存放实现定义的状态。
如本节描述的,使用小于硬件支持的INTID范围也是允许的。GICR_PROPBASER.IDbits控制着INTID的范围。因此,它影响着LPI配置表和LPI pending表的大小。为支持可配置的INTID范围,LPI pending表大小为:
Size in bytes = (2~GICR_PROPBASER.IDbits +1) / 8
中断控制器必须能够读取和写入LPI pending表分配的内存。通常,一个Redistributor可以缓存内部的最高优先级pending中断,当有太多pending中断需要缓存或当进入低功耗状态时,需要写出状态信息到LPI pending表中。
2. 配置LPI
LPI配置信息存放在内存中的表中,而不是寄存器中。Redistributor不允许缓存LPI配置信息。这意味着为配置LPI,软件必须:
(1)更新LPI配置表中的条目;
(2)确保更新全局可见;
(3)无效化Redistributor中任何缓存的配置信息;
可以通过发送ITS INV或INVALL命令来执行Redistributor中缓存的无效化。INV命令可以无效化某个中断的条目,所有当配置一个小数目的LPI时通常使用这个命令。INVALL命令用来无效化特定collection的所有中断的条目。
如果没有ITS,软件必须写GICR_INVLPIR或GICR_INVALLR 来代替。