【ARM系列】GICv3/v4-软件概述(三)

6.配置LPI

只有当亲和性路由使能的时候才支持LPI中断,这种中断类型和其他中断配置不同。
配置LPI包括如下两部分:

  • Redistributor
  • ITS(Interrupt Translation Service)

LPI中断是基于消息类型的中断,支持通过ITS实现。ITS负责接收来自外围设备的中断,并将LPI转发给适当的Redistributor。一个系统可能包括多个ITS,在这种情况下,每个ITS必须单独配置。
外设可以绕过ITS直接将LPI发送到Redistributor。但是ITS提供了许多功能,可以有效地处理大量中断源。

注:对LPI的支持是可选的,由GICD_TYPER.LPIs表示。如果至少存在一个ITS,则外围设备是否可以绕过ITS直接向Redistributor发送LPI是IMPLEMENTATION DEFINED。

6.1 ITS

6.1.1 ITS的操作

外设通过写ITS中的GITS_TRANSLATER寄存器产生一个LPI中断,写操作为ITS提供了如下信息:

  • EventID
    EventID是写入到GITS_TRANSLATER寄存器中的值,EventID用于标识外设发送的是哪个中断。EventID可以和INTID一致,或者经ITS翻译出INTID。
  • DeviceID
    DeviceID用于标识外设,DeviceID的生成方式是IMPLEMENTATION DEFINED,例如可以使用AXI User信号标识。

ITS负责将外设写入GITS_TRANSLATER的EventID转换为INTID,EventID如何转换为INTID取决于每个外设,这就是为什么需要DeviceID。

LPI INTID被分组在collection,其中的所有INTID都路由到同一个Redistributor。软件将LPI INTID分配给collection,使其能够有效地将中断从一个PE移动到另一个PE。

ITS使用三种类型的表完成LPI中断的翻译和路由:

  • Device Table
    负责将DeviceID映射到Interrupt Translation Table
  • Interrupt Translation Table
    包含特定DeviceID的EventID与INITID的映射关系,同时还包括INITID所属的Collection
  • Collection Table
    将Collection映射到Redistributor
    在这里插入图片描述
    当外设完成一笔写 GITS_TRANSLATER操作,ITS会完成如下操作:
    1.使用DeviceID从Device Table选择出合适的entry,该entry用于标识选择使用哪个Interrupt Translation Table ;
    2.使用EventID从Interrupt Translation Table选择出合适的entry,该entry提供了INITID和Collection ID;
    3.使用Collection ID选择Collection Table中的entry,该entry用于标识中断的路由信息;
    4.将中断转发至目标Redistributor

Note:ITS可以选择支持多个hardware collection,硬件collection是实现在ITS内部的,而非通过软件配置在内存中。GITS_TYPER.HCC用于标识是否支持硬件collection以及可以支持多少个硬件collection

6.1.2 命令队列

ITS table是通过内存中的命令队列(command queue)进行控制的,这个命令队列是一个环形的buffer同时由如下3个寄存器定义:

  • GITS_CBASER
    该寄存器定义了命令队列的基地址和大小。命令队列必须64KB对齐,大小必须是4KB的倍数,其中的每一个entry为32 bytes。同时该寄存器还指定了ITS在访问命令队列时使用的cacheable和shareable属性。
    在这里插入图片描述
  • GITS_CREADR
    该寄存器指向ITS要执行的下一条命令
    在这里插入图片描述
  • GITS_CWRITER
    这个寄存器指向队列中应该写入下一个新命令的entry
    在这里插入图片描述
    下图是一个命令队列的简易模型。The ARM® Generic Interrupt Controller Architecture Specification GIC architecture version 3.0 and 4.0 中提供了所有ITS支持的命令队列以及对应的编码方式
    在这里插入图片描述

6.1.3 ITS的初始化配置

在系统启动时配置ITS,软件需完成如下配置:

  • 为Device Table和Collection Table分配内存
    GITS_BASER[n]指定了ITS Device Table和Collection Table的基地址和大小。软件需要访问该寄存器识别出寄存器的编号和类型,然后分配所需的内存,并将GITS_BASERn寄存器设置为指向该分配的内存。
    在这里插入图片描述
  • 为命令队列分配内存
    软件需要为命令队列分配内存同时设置 GITS_CBASER 和 GITS_CWRITER指向所分配内存的首地址
  • 使能ITS
    当ITS Table和命令队列已经分配完成后,通过设置GITS_CTLR.Enable==1将ITS使能。一旦使能配置完成, GITS_BASERn 和GITS_CBASER寄存器变为只读。

6.1.4 集合表和设备表的大小和布局

Device Table和Collection Table的位置和大小保存在GITS_BASERn寄存器中。在使能ITS之前,软件必须为这些表分配充足的内存并完成GITS_BASERn寄存器的配置。
软件可以分配一个flat table(single level) 或 two_level table,该设置由GITS_BASERn.Indirect决定。

Note:支持两级页表是可选的,如果ITS只支持一级页表,那么GITS_BASERn.Indirect为 RAZ/WI

  • 一级页表

使用一级页表,需分配连续的内存空间给ITS Table做映射。在使能ITS之前,软件需要对整块空间进行清零操作,随后ITS通过在处理来自命令队列的命令填充该表。

表的大小随着DeviceID或Collection ID的位宽而缩放,视情况而定,所需尺寸可计算如下:

Size = 2 I D _ w i d t h 2^{ID\_width} 2ID_width * entry_size
此处的entry_size表示Table中每一个entry中所包含的byte的个数,记录在GITS_BASERn.Entry_Size
在配置GITS_BASERn时,指定的size指的是page的数量,页表大小通过GITS_BASERn.Page_Size指定,可以配置为4KB,16KB或64KB。因为根据上述表达式计算的结果必须是页表大小的整数倍,不足一页的按照一页分配。

  • 二级页表
    使用二级页表时,软件分配一个一级页表,多个二级页表,如下所示:
    在这里插入图片描述

第一级表由软件填充,每个条目指向第二级表或标记为invalid。二级表在分配给ITS之前必须填写0,并且由ITS在处理来自命令队列的命令时进行填充。当ITS启用时(GITS_CTLR.enabled==1),软件可能会分配额外的二级表,并更新相应的一级表条目以指向这些额外的表。启用ITS时,软件不得删除分配或更改现有分配。
每个二级表的大小为一页,与flat page一样,页面大小由GITS_BASERn.Page_size指定。
因此,它包含(page_size/entry_size)个entry。

每个一级表示(page_size/entry_size)个ID,可以指向二级表或标记为无效,使用命令进行配置时,如果使用了无效ID的ITS命令,会被丢弃。
一级页表的大小按照如下公式计算:
Size = ( 2 I D _ w i d t h 2^{ID\_width} 2ID_width / ( page_size / entry_size ) ) * 8

6.1.5 添加一个command到命令队列

通过如下方式将一个新命令添加到命令队列中:
1.将新命令写入命令队列
GITS_CWRITER指向command queue中下一个待写入的entry(不包含有效命令的enrty或空entry)。软件将command写入该entry,并且必须确保全局可见。

2.更新 GITS_CWRITER
软件将GITS_CWRITER更新到下一个entry(不包含新命令的),更新GITS_CWRITER会通知ITS已添加完成新命令。
如果command queue中有足够大的空间,软件可以同时添加多条command进来,并同时更新GITS_CWRITER

3.等待ITS读走该命令
软件可以通过轮询GITS_CREADR来检查ITS是否已读取该命令,当GITS_CWRITER.Offset==GITS_CREADR.Offset时,表示ITS已读取所有命令。或者,还可以通过添加INT命令生成一个中断信号,告知一组命令信号被ITS已读走。

ITS按顺序读取命令队列中的命令。但是,这些命令对Redistributers的影响是乱序的。SYNC命令可以确保前面发出的命令的可见的

Note:当GITS_CWRITER指向GITS_CREADR的前一个位置时,说明命令队列满了。在尝试添加新命令之前,软件必须检查队列中是否还有足够空间

6.1.6 映射一个中断到Redistributor

  • 将DeviceID映射到转换表

每个可以发出中断到ITS的外设都有属于自己的DeviceID,每个DeviceID都需要有自己对应的ITT(Interrupt Translation Table),ITT中保存着EventID和INITID的映射关系。软件需要为ITT分配内存空间,同时使用MAPD命令完成DeviceID和ITT的映射。

MAPD <DeviceID>, <ITT_Address>, <Size>
  • 将INTID映射到collection,将collection映射到Redistributor
    在完成外设的DeviceID和ITT之间的映射后,外设可以发出的每个EventID需要和INITID完成映射,同时这些INITID也需要映射到collection。同时每个collection需映射到对应的目标Redistributor。INITID可以通过MAPTIMAPI命令映射到collection。

当EVentID和INITID相同时,可以使用MAPI命令配置:

MAPI <DeviceID>, <EventID>, <Collection ID>

当EVentID和INITID不相同时,可以使用MAPTI命令配置:

MAPTI <DeviceID>, <EventID>, <INTID>, <Collection ID>

使用MAPC命令完成collection和目标Redistributor的映射:

MAPC <Collection ID>, <Target Redistributor>

目标Redistributor的标识依赖于GITS_TYPER.PTA:

  • GITS_TYPER.PTA==0
    Redistributor根据ID识别,该ID可以从GICR_TYPER.Processor_Number获得。
  • GITS_TYPER.PTA==1
    Redistributor根据物理地址识别

举例
一个timer的DeviceID为5,使用2bit的EventID。我们希望将EventID 0映射到INITID 8725。同时为timer的ITT分配的内存地址为0x84500000。
使用collection编号为3,同时将中断路由到基地址为0x78400000的 Redistributor。

MAPD  5,  0x84500000,    2       //将DeviceID 5 映射到ITT
MAPTI 5,  0,   8725,   3         //将EventID 0映射到INITID 8725 和collection 3
MAPC  3,  0x78400000             //将collection 3 映射到0x78400000对应的Redistributor
SYNC  0x78400000

6.1.7 中断在Redistributor间的迁移

通常有以下两种方式将中断从一个Redistributor映射到另一个Redistributor

  • 重新映射collection
    软件可以通过重新映射整个collection,将所有中断从一个Redistributor迁移到另一个Redistributor。这通常发生在与Redistributor相连的PE关闭电源,且所有的中断必须迁移到另一个Redistributor上时。可以通过如下步骤进行重新映射:
MAPC <Collection ID>, <RDADDR2>     //将collection重新映射到一个新的Redistributor
SYNC <RDADDR2> 
MOVALL <RDADDR1>, <RDADDR2>         //将处于挂起状态的中断迁移到新Redistributor
SYNC <RDADDR1> 

如果有多个collection作用于RDADDR1,那么就需要使用多个MAPC命令,每一个命令对应一个collection。

  • 将中断映射到另一个collection
    使用如下方式可以将单个中断重新映射到其他的collection:
MOVI <DeviceID>, <EventID>, <ID of new Collection>
SYNC <RDADDR1>

在该命令序列中,RDADDR1是中断被重新映射之前,原来指定的那个集合对应的Redistributor

6.1.8 移除中断映射

为了重新映射或移除中断映射,软件应该:
1.禁止当前已映射的物理中断号的使能,这些配置在LPI configuration table中,具体可参考6.2.2节
2.使用DISCARD命令移除中断映射关系,同时会清除pending状态的中断
3.发起SYNC命令,直到该命令完成

在命令执行完成之后,中断便不会再向之前映射到的Redistributor发送中断

6.1.9 重映射或移除设备映射

要修改或移除设备的映射,软件必须:
1.对于当前映射外设的每个EventID,需要执行6.1.8中的步骤
2.使用MAPD命令重新映射设备。或者使用valid为0的MAPD命令删除映射
3.发出SYNC命令并等待,直到该命令完成

6.2 Redistributor

Redistributor对LPI的配置信息放在内存的表里,称为中断配置表(LPI Configuration Table),并且所有的Redistributor都会共享同一组LPI中断配置表,Redistributor中LPI中断配置表地址寄存器为是GICR_PROPBASER。相似的,LPI的触发状态信息表(LPI Pending Table)寄存器是GICR_PENDBASER,每Redistributor一份,像是下图这样:
在这里插入图片描述

6.2.1 Redistributor的初始化配置

Redistributor的初始化步骤如下:
1.分配 LPI Configuration table内存空间并使用每个LPI的配置信息填充该表;
2.配置每个Redistributor的GICR_PROPBASER指向 LPI Configuration table地址;
3.为每个Redistributor分配 LPI Pending table内存空间并初始化分配的内存空间(清零空间),清零表示所有的LPI中断在最开始都是无效的;
4.将所有Redistributor的GICR_PENDBASER指向对应的LPI Pending table;
5.配置每个Redistributor的 GICR_CTLR.EnableLPIs ==1,使能LPI,当LPI使能后, GICR_PENDBASER 和
GICR_PROPBASER会变成只读的

  • LPI Configuration Table
    LPI Configuration table为每个LPI INITID分配了一个字节的空间,包含了优先级和使能信息,如下如所示:
    在这里插入图片描述

SPI,PPI和SGI都是使用8 bit 表示中断的优先级,但是LPI中断只使用6 bit ,其中低 2 bit为0。同时也没有中断的安全信息,因为LPI中断一直是 Non-secure Group 1。

LPI Configuration table的大小会分配多大的空间依赖于LPI中断的数量。系统所支持的最大的INTIDs (SPIs, PPIs, SGIs and LPIs) 位宽记录在GICD_TYPER.IDbits。LPI Configuration table要处理大于8191的中断,因此要支持所有可能的LPI中断:

Size = 2 G I C D _ T Y P E R . I D b i t s + 1 − 8192 2^{GICD\_TYPER.IDbits+1} - 8192 2GICD_TYPER.IDbits+18192

实际使用中,很多场景不会用到全部LPI中断。可以通过配置GICR_PROPBASER.IDbits控制LPI中断的多少。这里的值必须小于等于GICD_TYPER.IDbits的值,软件必须分配足够的内存空间,这种情况下,LPI Configuration table的大小为:

Size = 2 G I C R _ P R O P B A S E R . I D b i t s + 1 − 8192 2^{GICR\_PROPBASER.IDbits+1} - 8192 2GICR_PROPBASER.IDbits+18192

中断控制器必须能够读取LPI配置表分配的内存空间,否则它无法完成对内存的写操作。

  • LPI Pending Table
    LPI中断的状态信息存放在内存中,LPI只有两种状态:inactive 和 pending:

在这里插入图片描述

LPI 中断在被应答后,就会从pending -> inactive.
因为只有两个状态,所以在LPI Pemnding中每个LPI只有一个比特。因此,为了在实现中支持所有可能的INTID,表的大小应该为:
Size = ( 2 G I C D _ T Y P E R . I D b i t s + 1 ) / 8 (2^{GICD\_TYPER.IDbits+1}) / 8 (2GICD_TYPER.IDbits+1)/8

与Configuration table不同的是,LPI Pending table的大小没有从8192开始。该表的第一个1KB(INTID 0到8192)的内容是由
IMPLEMENTATION DEFINED。

如本节所述,可以使用比硬件支持的范围更小的INTID。GICR_PROPBASER.IDBits控制INTID范围的大小。因此,它同时影响LPI配置表的大小和LPI挂起表的大小。为了支持配置的INTID范围,所需的LPI Pending table大小为:

Size = ( 2 G I C R _ P R O P B A S E R . I D b i t s + 1 ) / 8 (2^{GICR\_PROPBASER.IDbits+1}) / 8 (2GICR_PROPBASER.IDbits+1)/8

中断控制器必须能够读取和写入LPI Pending table的内存空间。通常,Redistributor会在内部缓存优先级最高的pending中断,并在有太多pending中断要缓存时或者当进入低功率状态时,将状态信息写入LPI Pending table。

6.2.2 重配LPI

LPI配置信息存储在内存中的表中,而不是寄存器中。允许Redistributor缓存LPI配置信息,这意味着要重新配置LPI,软件必须:
1.更新 LPI Configuration table entry
2.保证更新操作全局可见
3.无效掉Redistributors中缓存的LPI配置信息

可以通过发出ITS INV或INVALL来无效Redistributors中缓存的LPI配置信息。INV命令可以使特定中断的条目无效,因此此命令通常用于重新配置少量LPI,INVALL命令使指定集合中所有中断的条目无效。有关ITS命令的更多信息,请参阅第6.1.5节。如果没有实现ITS,软件必须在任何Redistributor中写入GICR_INVLPIR或GICR_INVALLR将缓存失效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值