http://blog.chinaaet.com/justlxy/p/5100053251
比如x1 的卡可以插到x8的插槽中使用, x8 的卡可以插到x16的插槽中使用,升级方便。
注:这并不意味着所有的读写操作都需要通过北桥中转,因为PCI总线上的主设备和从设备属性是可以变化的。比如Ethernet和SCSI需要传输数据,可以通过一种叫做Peer-to-Peer的方式来完成,此时Ethernet或者SCSI则作为主机,其它的设备则为从机。具体会在后面的博文中详细介绍。
本文来简单地介绍一下PCI Spec规定的三种数据传输模型:Programmed I/O(PIO),Peer-to-Peer和DMA。
三种数据传输模型的示意图如下图所示:
PCI体系结构中,一共支持三种地址空间:Memory Address Space、I/O Address Space和Configuration Address Space。其中x86处理器可以直接访问的只有Memory Address Space和I/O Address Space。而访问Configuration Address Space则需要通过索引IO寄存器来完成。
如上图所示,最左边的即为Memory Address Space,其中包括了多个PCI Memory、AGP Video(显卡)Memory以及Extended Memory、Boot ROM等。中间的为I/O Address Space,需要注意的是,虽然PCI支持32位的地址,但是由于x86的CPU只支持16位的I/O空间,这就限制了PCI的I/O Address Space最大只有64KB。最右边的则为Configuration Address Space,由于每一个PCI设备最多支持8种功能(Function),每一条PCI总线最多支持32个设备,而每一个PCI总线系统最多又支持256个子总线(通过PCI桥)。因此,总的Configuration Address Space的大小为:256 Bytes/function x 8 functions/device x 32 devices/bus x 256 buses/system = 16MB。
如图中所示,Configuration Address Space所使用的IO寄存器范围为0xCF8~ 0xCFF。其中0xCF80xCFB为端口地址,0xCFC0xCFF为配置数据。
上一篇文章中也是说到了,I/O Address Space的空间很有限(64KB),所以一般在I/O Space中都有两个寄存器,第一个指向要操作的内部地址,第二个存放读或者写的数据。因此,对于PCI的配置周期来说,包含了两个步骤:
Step1:CPU先对IO Address中的0xCF8~0xCFB写入要操作的配置寄存器的地址。如下图所示,其中包括了总线号(Bus Number)、设备号(Device Number)、功能号(Function Number)和寄存器指针。
Step2:CPU向IO Address中的0xCFC~0xCFF中写入读或者写的数据。
前面介绍过,每一个PCI功能(Function)都包含256个字节的配置空间(Configuration Space),其中前64个字节被称为Header,剩余的192个字节用于一些可选的功能。PCI Spec规定了两种类型的Header:Type1 和Type0。其中,Type1 Header表示该PCI设备功能为桥(Bridge),而Type0 Header则表示该PCI设备功能不是桥。两种Header的结构图分别如下所示:
每个function 有几个bar
在这个例子中,Endpoint的读请求通过了两个Switch,然后到达其目标,即Root。Root对读请求的包进行解码后,并从中识别出操作的地址,然后锁存数据,并将数据发送至Endpoint,即包含数据的Completion包,ClpD。需要注意的是,PCIe允许每个包的最大数据量(Max Data Payload)为4KB,但实际上设计者往往会采用较小的Max Payload Size(比如128,256,512,1024和2048)。因此,常常一个读请求会对应多个ClpD,即将大于Max Payload Size的数据分成多个包发送。如果遇到错误,则Root会通过Completion包告知相应的Endpoint。
前面的关于PCI总线的文章介绍过PCI总线的配置空间,PCIe总线为了兼容这些PCI设备,几乎完整的保留了PCI总线的配置空间。并将配置空间扩展到4KB,用于支持一些PCIe总线中新的功能,如PCI Express Capability、Power Management和MSI/MSI-X等。
下图是从PCI总线中继承过来的配置空间:
需要特别注意的是,PCIe的Spec中明确规定只有Root有权限发起配置请求(Originate Configuration Requests),也就是说PCIe系统里面的其他设备是不允许去配置其他设备的配置空间的,即peer-to-peer的配置请求是不允许的。并且配置请求的路由(Routing)方式只能是采用BDF(Bus,Device,Function)。
处理器一般不能够直接发起配置读写请求,因为其只能产生Memory Request和IO Request。这就意味着Root必须要将处理器的相关请求转换为配置读写请求。针对传统的PCI设备(Legacy PCI),采用的是IO间接寻址访问(IO-indirect Accesses);针对PCIe设备,采用的是Memory-Mapped Accesses。
之前的文章中强调过,PCIe中只有Root才可以发起配置空间读写请求,并且我们知道Root的每个端口中都包含有一个P2P桥。当Root发起配置空间读写请求时,相应的桥首先检查请求的BDF中的Bus号是否与自己的下一级总线号(Secondary Bus Number)相等,如果相等,则先将Type1转换为Type0,然后发给下一级(即Endpoint)。
注:PCIe Spec中明确指出,IO地址空间只是为了兼容早期的PCI设备(Legacy Device),在新设计中都应当使用MMIO,因为IO地址空间可能会被新版本的PCI Spec所抛弃。
当使用MMIO,因为IO地址空间可能会被新版本的PCI Spec所抛弃。
IO地址空间的大小是4GB(32bits),而MMIO则取决于处理器(和操作系统),并且由处理器进行统一分配管理。
如下图所示,PCIe总线中有两种MMIO:P-MMIO和NP-MMIO。
上一篇文章介绍了Type0型配置空间Header中的BAR的作用和用法,但是PCIe中的桥设备(Switch和Root中的P2P)又是如何判断某一请求(Request)是否属于自己或者自己的分支下的设备的呢?这实际上是通过Type1型配置空间Header中的Base和Limit寄存器来实现的,这篇文章来进行简单地介绍一下。
Base和Limit寄存器在Type1 Header中的位置如下图所示: