作者:江波龙谭荣
刚进江波龙时小谭就开始接触sata协议,经常性会遇到一堆OS蓝屏、ssd不上盘等奇葩地兼容性问题,那时经常会因为Capability不足而迟迟解不了bug,直到后来下定决心潜心研究Spec后,才开始慢慢熟悉了host与device交互的那些套路,当然这也正式开启了他后来的single-dog旅途。
言归正传,关于Pcie 的Configuration Space老男孩之前已经写过一篇文章了,小谭看后也是获益匪浅,但是最近遇到一个兼容性问题——同一台电脑,系统盘换了操作系统(win10 15063)后,Pcie 数据盘不上盘了,操作系统换回之前的win10 14393、win10 10240均可以上盘。进一步分析发现在Bios里,host还可以识别到device,但是在Bios加载操作系统后,Windows设备管理器里是找不到设备驱动的。通过使用Summit T34(Pcie 3.0 Analyzer)抓取该过程的trace,再对比可以上盘的Plextor,终于发现了问题点所在——在host读取Configuration Space时,寄存器RID – Revision ID 存在差别,通过把该寄存器改成和Plextor一样之后,这个问题一下就解决了,device可以在win10 15063成功被识别了。
问题解了之后,小谭心里还是犯嘀咕,因为道不出原由,就像是盲调解决了似的。通过继续潜心看Spec与找资料发现——Windows操作系统要识别一个Pcie 设备,首先会去匹配Configuration Space里Device的Vendor ID、Device ID、Revision ID、Subsystem Vendor ID、Subsystem Device ID、Base Class Code、Sub Class Code等字段,得出设备的类型,从而引导操作系统安装相应的INF驱动程序。先简单罗列下各个字段对应的意义:
Vendor ID:厂商标识。是由PCI SIG授权分配的一个ID,如marvell某款主控的ID——1B4Bh,这代表着该设备是经过PCI SIG技术专利认证的,只有经过了它的认证Windows才认为是一款合法的Pcie ssd设备。
Device ID:设备标识。这个是Pcie 规范给客户自定义的一个ID,用于区分对同款主控(如marvell、SMI)进行2次开发的不同厂商。
Revision ID:芯片版本;
Subsystem Vendor ID:子系统厂商标识;
Subsystem Device ID:子系统设备标识;
Base Class Code:设备类型的编码,比如01h表示mass storage controler;
Sub Class Code:设备子类型编码,比如08h表示ssd controler。
所以知道这些后大致可以分析,不能被Windows识别的这款SSD是因为匹配Revision ID不通过,导致windows认为它是一款非法的设备,从而拒绝认证该设备,并终止了相应驱动程序的安装。由于上述这些字段在ssd controler里都是可以自定义被更改的,所以这些影响驱动安装的ID,是可以人为的绕过Windows的认证,从而顺利的安装设备驱动程序。
讲完了Pcie Configuration Space里遇到的一个Pcie 设备识别问题后,接下来顺便讲讲Pcie 的那些Capability。为啥要特地讲这个东西呢?因为小谭发现很多同事就算是看了老男孩的那篇文章好久后,依然还是不知道如何在代码里看懂ssd controler是如何建立自己的capability链表的,更别说添加了,在此请允许小谭锦上添花一番。
Capability是device通过在4k Byte的Configuration Space里告诉host它支持哪些特性的,而Capability又大致分为基本的Capability与之后扩展的Capability,在使用4K的配置空间时两者大同小异,都是采用链表形式来自定义Capability的位置的,唯一的区别是后者种类多,且不同厂商所支持的Capability有很大区别。如下图为Configuration Space的基本架构——0-3Fh(PCI Head域),40h-FFh(基本Capability区域),100-FFF(扩展Capability区域)。
先以基本的Capability为例,讲述ssd controller在代码中是如何配置Configuration Space的Capability的。用一个非常简单的流程图模型表示如下:
其中Capability point是在0-3Fh(PCI Head域),偏移为34h,用于存放第一个Capability的偏移量,偏移量的范围是40h-FFh(基本Capability区域),这段区间可任意让你分配各种基本Capability。Spec说明如下:
下图是host端读出的一款ssd的基本Capability:
可以看出这款ssd具备5种Capability,以MSI Capability为例,它在Configuration Space里的偏移是50h,host通过识别ID号是11h,才解析出来是MSI Capability,当然host是如何知道40h-FFh(Capability区域)范围只有5个Capability呢?那是因为null Capability 的next point为0,它意味着整个Capability 链表结束了,这时host就知道没有其他Capability了。
提到扩展的Capability,真的是怪吓人的,因为在Pcie 3.1 a规范里,从第7章7.9节就开始讲PCI Express Extended Capabilities,一直讲到7.35小节Readiness Time Reporting Extended Capability,不得不佩服Pcie协议博大精深,看得人眼花缭乱,小谭当初差点被搞晕了。但是静下心来小谭发现它的链表建立和基本Capability差不多,只是第一个扩展Capability默认就从100h的偏移位置开始放置,而不是像基本的Capability那样从34h通过指针指过来。它的链表简化流程图模型表示如下:
最后再附上两张不同ssd的扩展Capability供大家欣赏,有木有觉得差异有那么点大呀!