HOST处理器对PCI设备的数据访问主要包含两方面内容,一方面是处理器向PCI设备发起存储器和I/O读写请求;另一方面是处理器对PCI设备进行配置读写。
在PCI设备的配置空间中,共有6个BAR寄存器。每一个BAR寄存器都与PCI设备使用的一组PCI总线地址空间对应,BAR寄存器记录这组地址空间的基地址。本书将与BAR寄存器对应的PCI总线地址空间称为BAR空间,在BAR空间中可以存放I/O地址空间,也可以存放存储器地址空间。
PCI设备可以根据需要,有选择地使用这些BAR空间。值得注意的是,在BAR寄存器中存放的是PCI设备使用的“PCI总线域”的物理地址,而不是“存储器域”的物理地址。
HOST处理器访问PCI设备I/O地址空间的过程,与访问存储器地址空间略有不同。有些处理器,如x86处理器,具有独立的I/O地址空间。x86处理器可以将PCI设备使用的I/O地址映射到存储器域的I/O地址空间中,之后处理器可以使用IN,OUT等指令对存储器域的I/O地址进行访问,然后通过HOST主桥将存储器域的I/O地址转换为PCI总线域的I/O地址,最后使用PCI总线的I/O总线事务对PCI设备的I/O地址进行读写访问。在x86处理器中,存储器域的I/O地址与PCI总线域的I/O地址相同。
对于有些没有独立I/O地址空间的处理器,如PowerPC处理器,需要在HOST主桥初始化时,将PCI设备使用的I/O地址空间映射为处理器的存储器地址空间。PowerPC处理器对这段“存储器域”的存储器空间进行读写访问时,HOST主桥将存储器域的这段存储器地址转换为PCI总线域的I/O地址,然后通过PCI总线的I/O总线事务对PCI设备的I/O地址进行读写操作。
在PCI总线中,存储器读写事务与I/O读写事务的实现较为类似。首先HOST处理器在初始化时,需要将PCI设备使用的BAR空间映射到“存储器域”的存储器地址空间。之后处理器通过存储器读写指令访问“存储器域”的存储器地址空间,HOST主桥将“存储器域”的读写请求翻译为PCI总线的存储器读写总线事务之后,再发送给目标设备。
值得注意的是,存储器域和PCI总线域的概念,PCI设备能够直接使用的地址为PCI总线域的地址,在PCI总线事务中出现的地址也为PCI总线域的地址;而处理器能够直接使用的地址为存储器域的地址。理解存储器域与PCI总线域的区别对于理解PCI总线至关重要,本篇将在第2.1节专门讨论这两个概念。
以上对PCI总线的存储器与I/O总线事务的介绍并没有考虑PCI桥的存在,如果将PCI桥考虑进来,情况将略微复杂一些。当处理器对PCI设备11进行存储器写操作时,这些数据需要通过HOST主桥x和PCI桥x1,最终到达PCI设备11,其访问步骤如下。值得注意的是,以下步骤忽略PCI总线的仲裁过程。
- (1)首先处理器将要传递的数据放入通用寄存器中,之后向PCI设备11映射到的存储器域的地址进行写操作。值得注意的是,处理器并不能直接访问PCI设备11的PCI总线地址空间,因为这些地址空间是属于PCI总线域的,处理器所能直接访问的空间是存储器域的地址空间。处理器必须通过HOST主桥将存储器域的数据访问转换为PCI总线事务才能对PCI总线地址空间进行访问。
(2)HOST主桥x接收来自处理器的存储器写请求,之后处理器结束当前存储器写操作,释放系统总线。HOST主桥x将存储器域的存储器地址转换为PCI总线域的PCI总线地址。并向PCI总线x0发起PCI写请求总线事务。值得注意的是,虽然在许多处理器系统中,存储器地址和PCI总线地址完全相等,但其含义完全不同。
(3)PCI总线x0上的PCI设备01、PCI设备02和PCI桥1将同时监听这个PCI写总线事务。最后PCI桥x1接收这个写总线事务,并结束来自PCI总线x0的PCI总线事务。之后PCI桥x1向PCI总线x1发起新的PCI总线写总线事务。
(4) PCI总线x1上的PCI设备11和PCI设备12同时监听这个PCI写总线事务。最后PCI设备11通过地址译码方式接收这个写总线事务,并结束来自PCI总线x1上的PCI总线事务。
由以上过程可以发现,由于存储器写总线事务使用Posted传送方式,因此数据通过PCI桥后都将结束上一级总线的PCI总线事务,从而上一级PCI总线可以被其他PCI设备使用。如果使用Non-Posted传送方式,直到数据发送到PCI设备11之后,PCI总线x1和x0才能依次释放,从而在某种程度上将造成PCI总线的拥塞。
处理器对PCI设备11进行I/O写操作时只能采用Non-Posted方式进行,与Posted方式相比,使用Non-Posted方式,当数据到达目标设备后,目标设备需要向主设备发出“回应”,当主设备收到这个“回应”后才能结束整个总线事务。本节不再讲述处理器如何对PCI设备进行I/O写操作,请读者思考这个过程。 处理器对PCI设备11进行存储器读时,这个读请求需要首先通过HOST主桥x和PCI桥x1到达PCI设备,之后PCI设备将读取的数据再次通过PCI桥x1和HOST主桥x传递给HOST处理器,其步骤如下所示。我们首先假设PCI总线没有使用Delayed传送方式处理Non-Posted总线事务,而是使用纯粹的Non-Posted方式。
- (1) 首先处理器准备接收数据使用的通用寄存器,之后向PCI设备11映射到的存储器域的地址进行读操作,
(2)HOST主桥x接收来自处理器的存储器读请求。HOST主桥x进行存储器地址到PCI总线地址的转换,之后向PCI总线x0发起存储器读总线事务。
(3)PCI总线x0上的PCI设备01、PCI设备02和PCI桥x1将监听这个存储器读请求,之后PCI桥1接收这个存储器读请求。然后PCI桥x1向PCI总线x1发起新的PCI总线读请求。
(4) PCI总线x1上的PCI设备11和PCI设备12监听这个PCI读请求总线事务。最后PCI设备11接收这个存储器读请求总线事务,并将这个读请求总线事务转换为存储器读完成总线事务之后,将数据传送到PCI桥x1,并结束来自PCI总线x1上的PCI总线事务。
(5) PCI桥x1将接收到的数据通过PCI总线x0,继续上传到HOST主桥x,并结束PCI总线x0上的PCI总线事务。
(6) HOST主桥x将数据传递给处理器,最终结束处理器的存储器读操作。
显然这种方式与Posted传送方式相比,PCI总线的利用率较低。因为只要HOST处理器没有收到来自目标设备的“回应”,那么HOST处理器到目标设备的传送路径上使用的所有PCI总线都将被阻塞。因而PCI总线x0和x1并没有被充分利用。
由以上例子,我们可以发现只有“读完成”依次通过PCI总线x1和x0之后,存储器读总线事务才不继续占用PCI总线x1和x0的资源,显然这种数据传送方式并不合理。因此PCI总线使用Delayed传送方式解决这个总线拥塞问题。