--------内容来源于VT-d spec第4章及ATS spec
Device-TLB的出现是为了减轻DMA访问地址映射单元(intel命名VT-d,amd命名iommu,后面习惯于称呼iommu)的压力。
我们简单想一下IOMMU和MMU的区别,IOMMU负责设备访问映射,MMU负责CPU访问映射。MMU为CPU上运行的每个软件实体(进程)维护一份页表,起到进程间地址隔离的作用;IOMMU为每个设备提供一份页表,起到设备间地址隔离的作用。
但有一点不同,每个CPU同时只会执行一个进程,是分时调用的,所以MMU在切换页表的时候会刷新TLB,同一时间只需要处理一份页表。而设备是同时工作的,IOMMU肯定是要同时处理所有设备的地址访问请求,如果设备数量可观(尤其是SRIOV /Scalable IOV场景)必然对IOMMU里的页表cache造成很大的压力,DMA访问会在IOMMU的地址翻译环节形成瓶颈。
这就促进了Device-TLB的发展。Device-TLB相当于将设备的地址翻译工作分散到每个设备,在PCIE协议里的体现形式是ATS(Address Translation Service)特性。
另外,Device-TLB还可以实现I/O缺页处理,填补了DMA访问时IOMMU无法进行缺页处理的缺憾。
一、Device-TLB的实现
Device和IOMMU之间通过专门的操作实现Device-TLB。
Translation Request/Completion用于设备向RC获取页表映射关系。
Translated Request是设备发起的DMA访问,但使用的是已经映射后的地址,不需要IOMMU进行地址转换。
Invalidation Request/completion用于RC通知设备清除页表映射关系。
这些操作体现在TLP报文里,都会有单独定义的格式。PCIE的TLP报文为ATS协议提供了"AT"字段(Address Type),用于标识ATS操作。默认AT=00b,表示没有经过Device-TLB的DMA访问;AT=01b,标识Translation Request;AT=10b,表示经过了Device-TBL的Translated DMA访问。
1、Translation Request
用于设备向RC申请地址映射关系。
AT=01b;
Address=起始地址;
Length=RC根据这个长度决定返回多少个Completion消息。每条Translation需要回复8个字节,这个长度是按4字节为单位,所以必须是2^n,最小是2。
No Write(NW)flag = 置位,表示这次Translation对应的translated DMA访问的权限是只读。
2、Translation Completion
如果没有办法返回有效的映射关系,主机会回复
1)UR,标识主机没有对该设备开放Translation Request权限。
2)CA,主机在处理Translation Request时遇到问题。
如果正确处理Translation Request,主机会返回带数据的Translation completion报文。报文的有效信息:
Size(S): 0表示这条映射关系对应4KB大小的页面,1表示这条映射关系对应的页面大小根据Translated Address field的配置指定,低Nbit为0,类似于BAR空间的大小获取方式。
Non-Snooped access flag(N):设置后,后面的translated request必须清除No snoop Attribute。
Untranslated access only flag (U): 用于权限设置,设置后,该区间只支持non-translated访问。
Read permission (R): 权限设置,只有置1,才允许translated read。
Write permission (W): 权限设置,只有置1,才允许translated write。
Translated Address:R/W标识置位,U标识没有置位,translated address field填写translation的结果。终端可以通过transtated request访问该地址。
3、Translated Request
AT=10b的Memory请求。
如果设备在Device-TLB cache中找到了具备相应权限的映射关系,就可以发出Translated Request。
4、Invalidation Request and Completion
Invalidation-requests-without-PASID的关键字段:
Device ID:ID寻址型TLP报文,BDF号。
Size(S): 0表示invalidate地址范围是4KB;1表示根据Untranslated Address字段低多少位为0来决定地址范围大小。
二、IOMMU如何处理Device-TLBs
1、ATS协议异常处理
某些会引发UR,某些会引发Malformed TLP。后者还是比较严重的,应该会导致内核coredump。具体不再描述。
ACS capability里有一个Translate Blocking特性,用来block AT字段非0的TLP报文。如果root port该特性被使能,AT字段非0的报文会引发ACS violation。(查看服务器的root port确实使能了这个标识,是不是需要修改bios关闭该特性??!!)
2、Translation requests处理
主机对于各种无法处理的请求会回复UR或CA,具体的异常情况会有一个表格,不单独介绍。
1、对于正常的请求,主机的处理机制如下:
1)如果请求的地址范围在0xFEEx_xxxx,主机的completion报文关键字段R=0,W=1,U=1,S=0。这种处理方式也是为了让msix post write也兼容在ATS的场景。
2)如果IOMMU匹配到了映射地址,且至少有读或写的一项权限,就会回复success状态的translation完成报文,带着相应的R、W标识。
Execute (EXE) bit和Privilege Mode (PRIV) bit对于非PASID场景,始终置0。
Non-snooped access (N) bit:translation完成报文的N bit用来指示使用这次翻译地址的DMA访问的No-Snoop(NS)标识。不支持Snoop Ctrl的IOMMU会将Nbit置0。
Untranslated access only (U) bit:置1说明只支持Untranslated访问。比如中断地址范围0xFEEx_xxxx。
Size (S) bit:不再重复描述。
Translated Address(ADDR):指明了Second-Stage映射的概念,类似于页表的二级映射,第一次翻译请求返回的是一级表的表项,第二次翻译请求才会返回真正的地址。还有passthrough映射请求,此时会返回该地址属于的地址区间的基地址,地址区间是IOMMU支持的最大页面大小。
问题:如何区分Second-Stage、passthrough?
2、Accessed, Extended Accessed, and Dirty Flags
这几个标识是在主机的页表entry中的标识。而且仅在second-stage映射场景中的一级页表项中使用。
first-stage映射请求的时候,IOMMU成功翻译该地址之后,会自动置位A bit。
3、Multi-Translation的处理
长度字段超过2WORD的translation请求属于Multi-Translation。IOMMU有两种处理方式:
1)硬件只执行single translation;
2)返回multiple translations
实际使用暂不考虑该场景。
三、Invalidate Device-TLB
当主机侧释放某些映射关系的情况,如何同步给设备,防止设备继续使用这些映射关系发起异常访问。Translation Invalidation报文就是由主机发起,通知设备清除Device-TLB表项的。
对于主机侧的IOMMU,硬件提供了invalidation queue interface触发translation invalidation,最终还是受软件控制,需要软件感知和发起。
IOMMU对于Invalidate request的处理逻辑:
1)会从硬件池分配一个iTag,唯一标识一次translation invalidation。如果iTag分配完了,就需要等待可用的iTag。对于每个iTag,硬件都配备一个InvComCnt计数器,跟踪收到的Invalidation completions的个数。
2)对于每个iTag,硬件还会启动一个invalidation completion计时器,超时时间建议最小设置为PCIE的read completion超时时间。
硬件对于Invalidate completion的处理逻辑:
1)Invalidation完成报文里的iTag-Vector字段与本次invalidation操作的iTag值一致。
2)InvComCnt计数器会递增,如果跟Invalidation response里的"completion count"字段相符(并不是相同,Completion count=0表示完成),认为已经完成了本次invalidation操作,iTag会被释放。
3)如果在完成操作之前,计时器超时了,硬件也会释放iTag,同时置位错误状态寄存器里的ITE 字段。如果错误事件使能寄存器的相应位置置位,会触发错误事件,然后硬件将不再从队列中取新的invalidation请求及发出请求,直到软件写寄存器清除该错误事件后恢复。
四、SOC一体化设备的Device-TLB实现
I/O fabric和System fabric是什么意思……
软件可能会发起不同地址类型的DMA访问,这些地址都会经过DevTLB转换成HPA。
1、所有的SOC上的所有设备都需要满足下面的要求:
1)HPA Isolation Boundary一定不能暴露翻译后的HPA地址给Device Core。(HPA Isolation Boundary可以从图中看到对应的概念,圈出的区域)
2)连接RC和SOC设备的接口,必须包含在HPA Isolation Boundary内。
3)Device Core决不能直接发起DMA操作,必须通过HPA Isolation Boundary发起。
4)HPA isolation单元必须做到主控DevTLB,并完全遵守ATS协议。
5)HPA isolation单元必须完全管理ATS相关的寄存器:ATS Extended Capability、ATS Extended Capability Header、ATS Capability Register、ATS Control Register。
6)Device Core可以发起一个不经过DevTLB的传输,这种情况HPA isolation单元会发起Untranslated request。
7)Device Core不可以修改DevTLB以及Data Cache的任何内容。
2、对于使用System Fabric的设备,需要额外遵循:
1)在发送Invalidation Completion Response给RC之前,必须保证所有使用旧映射关系的DMA操作已经在线路上发送完成。
2)如果IOMMU开启了DMA映射,HPA isolation单元通过System Fabric的访问都必须使用Translated HPA地址。
3)为了通知HPA isolation单元主机开启了DMA映射,RC可以执行产品自定义的操作。(谁定义?产品自己定义,RC怎么能适配那么多产品呢?)
五、软件使能和关闭ATS
软件需要写两个独立的bit来使能设备的ATS,这不会是一个原子操作。所以设备会有一段时间处于不稳定状态,建议设备在这个期间暂停DMA访问。
1、使能ATS的推荐步骤
1)软件停止所有的DMA访问;
2)软件写入DevTLB的context entry;
3)向ATS Control寄存器的Program Enable位写1。
2、关闭ATS的推荐步骤
1)软件需要停止所有的DMA访问;
2)向ATS Control寄存器的Program Enable位写0。
3)软件发起全局的Device-TLB Invalidate操作,然后发起Invalidate等待操作,用来令所有DevTLB的传输失效。也会排空所有已经发出的传输,令他们传输完成。
4)写入DevTBL的context entry,来阻塞所有的ATS请求。