PCI Header配置空间详解
Posted smartvxworks
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PCI Header配置空间详解相关的知识,希望对你有一定的参考价值。
目录
(2)Revision ID 和 Class Code 寄存器
(5)Subsystem ID 和 Subsystem Vendor ID 寄存器
(6)Expansion ROM base address 寄存器
(10)Base Address Register 0~5寄存器
(1) Subordinate Bus Number、Secondary Bus Number 和 Primary Bus Number 寄存器
(3) Secondary Latency Timer 寄存器
(5)Memory Limit 和 Memory Base 寄存器
(6)Prefetchable Memory Limit 和 Prefetchable Memory Base 寄存器
(7)I/O Base Upper 16 Bits and I/O Limit Upper 16寄存器
一、存储域和总线域
在PCI 体系结构中,含有两类桥片,一个是 HOST 主桥,另一个是 PCI 桥。在每一个 PCI设备中(包括 PCI 桥)都含有一个配置空间。这个配置空间由 HOST 主桥管理,而 PCI 桥可以转发来自 HOST 主桥的配置访问。在 PCI 总线中,PCI Agent 设备使用的配置空间与 PCI 桥使用的配置空间有些差别,但这些配置空间都是由处理器通过 HOST 主桥管理。
1.1 PCI总线域
PCI 总线域(PCI Segment)由 PCI 设备所能直接访问的地址空间组成。在一个处理器系统中,可能存在多个 HOST 主桥,因此也存在多个 PCI 总线域。
在多数处理器系统中,分属于两个 PCI 总线域的 PCI 设备并不能直接进行数据交换,而需要通过 FSB 进行数据交换。值得注意的是,如果某些处理器的 HOST 主桥支持 Peer-to-Peer数据传送,那么这个 HOST 主桥可以支持不同 PCI 总线域间的数据传送。
1.2处理器域
CPU 域地址空间指 CPU 所能直接访问的地址空间集合。DRAM 域地址空间指 DRAM 控制器所能访问的地址空间集合。目前处理器系统的 DRAM 一般由 DDR-SDRAM 组成,有的书籍也将这部分内存称为主存储器。存储器域统称 CPU 域与 DRAM 域。存储器域包括 CPU 内部的通用寄存器,存储器映像寻址的寄存器,主存储器空间和外部设备空间。
处理器由一个或者多个 CPU、外部 Cache、中断控制器和 DRAM 控制器组成;而处理器系统由一个或者多个处理器和外部设备组成。
处理器域是指一个处理器系统能够访问的地址空间集合。处理器系统能够访问的地址空间由存储器域和外部设备域组成。
在一个处理器系统中,CPU 所能访问的 PCI 总线地址一定在存储器域中具有地址映射;而 PCI 设备能访问的存储器域的地址也一定在 PCI 总线域中具有地址映射。当 CPU 访问 PCI域地址空间时,首先访问存储器域的地址空间,然后经过 HOST 主桥转换为 PCI 总线域的地址,再通过 PCI 总线事务进行数据访问。而当 PCI 设备访问主存储器时,首先通过 PCI 总线事务访问 PCI 总线域的地址空间,然后经过 HOST 主桥转换为存储器域的地址后,再对这些空间进行数据访问。
二、HOST主桥
2.1 PCI 设备配置空间的访问机制
PCI 总线规定访问配置空间的总线事务,即配置读写总线事务,使用 ID 号进行寻址。
PCI 设备的 ID 号由总线号(Bus Number)、设备号(Device Number)和功能号(Function Number)组成。其中总线号在 HOST 主桥遍历 PCI 总线树时确定。PCI 总线可以使用 PCI 桥扩展 PCI 总线,并形成一颗 PCI 总线树。在一颗 PCI 总线树上,有几个 PCI 桥(包括 HOST 主桥),就有几条 PCI 总线。在一颗 PCI 总线树中,总线号由系统软件决定,通常与 HOST 主桥直接相连的 PCI 总线编号为0,系统软件使用 DFS(Depth-First Search)算法扫描 PCI 总线树上的所有 PCI 总线,并依次进行编号。
2.2 X86处理器的主桥
Intel 使用南北桥概念统一 PC 架构。但是从体系结构的角度上看,南北桥架构并不重要,北桥中存放的主要部件不过是存储器控制器、显卡控制器和 HOST 主桥而已,而南桥存放的是一些慢速设备,如 ISA 总线和中断控制器等。
x86处理器定义了两个 I/O 端口寄存器,分别为 CONFIG_ADDRESS 和 CONFIG_DATA 寄存器,其地址为0xCF8和0xCFC。x86处理器使用这两个 I/O 端口访问 PCI 设备的配置空间。PCI 总线规范也以这个两个寄存器为例,说明处理器如何访问 PCI 设备的配置空间。其中CONFIG_ADDRESS 寄存器存放 PCI 设备的 ID 号,而 CONFIG_DATA 寄存器存放进行配置读写的数据。
三、PCI桥和PCI设备的配置空间
PCI 设备都有独立的配置空间,HOST 主桥通过配置读写总线事务访问这段空间。PCI 总线规定了俩种类型的 PCI 配置空间,分别是 PCI Agent 设备使用的配置空间,PCI 桥使用的配置空间。
3.1 PCI桥
PCI 桥的引入使 PCI 总线极具扩展性,也极大地增加了 PCI 总线的复杂度。PCI 总线的电气特性决定了在一条 PCI 总线上挂接的负载有限,当 PCI 总线需要连接多个 PCI 设备时,需要使用 PCI 桥进行总线扩展,扩展出的 PCI 总线可以连接其他 PCI 设备,包括 PCI 桥。在一颗 PCI 总线树上,最多可以挂接256个 PCI 设备,包括 PCI 桥。
透明桥:系统软件不需要专门的驱动程序设置的PCI桥
PCI 桥跨接在两个 PCI 总线之间,其中距离 HOST 主桥较近的 PCI 总线被称为该桥片上游总线(Primary Bus),距离 HOST 主桥较远的 PCI 总线被称为该桥片的下游总线(Secondary Bus)。
3.2 PCI设备的配置空间
在一个具体的处理器应用中,PCI 设备通常将 PCI 配置信息存放在 E2PROM 中。PCI 设备进行上电初始化时,将 E2PROM 中的信息读到 PCI 设备的配置空间中作为初始值。这个过程由硬件逻辑完成,绝大多数 PCI 设备使用这种方式初始化其配置空间。
(1)Device ID 和 VendorID 寄存器
两个寄存器的值由 PCISIG 分配,只读。其中 Vendor ID 代表 PCI 设备的生产厂商,而 Device ID 代表这个厂商所生产的具体设备。
(2)Revision ID 和 Class Code 寄存器
这两个寄存器只读。其中 Revision ID 寄存器记载 PCI 设备的版本号。该寄存器可以被认为是 Device ID 寄存器的扩展。
(3)Header Type 寄存器
该寄存器只读,由8位组成。
第7位为1表示当前 PCI 设备是多功能设备,为0表示为单功能设备。
第6~0位表示当前配置空间的类型,为0表示该设备使用 PCI Agent 设备的配置空间,普通 PCI 设备都使用这种配置头;为1表示使用 PCI 桥的配置空间,PCI 桥使用这种配置头;为2表示使用 Cardbus 桥片的配置空间,Card Bus 桥片在这里暂时不介绍。
系统软件需要使用该寄存器区分不同类型的 PCI 配置空间,该寄存器的初始化必须与PCI 设备的实际情况对应,而且必须为一个合法值。
(4)Cache Line Size 寄存器
该寄存器记录CPU使用的 Cache 行长度。在 PCI 总线中和 Cache 相关的总线事务,如存储器写并无效和 Cache 多行读等总线事务需要使用这个寄存器。值得注意的是,该寄存器由系统软件设置,但是在 PCI 设备的运行过程中,只有其硬件逻辑才会使用该寄存器,比如 PCI 设备的硬件逻辑需要得知处理器系统 Cache 行的大小,才能进行存储器写并无效总线事务,单行读和多行读总线事务。
如果 PCI 设备不支持与 Cache 相关的总线事务,系统软件可以不设置该寄存器,此时该寄存器为初始值0x00。对于 PCIe 设备,该寄存器的值无意义,因为 PCIe 设备在进行数据传送时,在其报文中含有一次数据传送的大小,PCIe 总线控制器可以使用这个“大小”,判断数据区域与 Cache 行的对应关系。
(4)BIST寄存器
PCI兼容寄存器,可选。既可以铜鼓请求者功能也可以通过完成者功能实现。如果某功能实现了内部自检(Built-In Self-Test, BIST)机制,必须实现下图的寄存器。下表描述了每个比特的作用。如果该功能不支持BIST,在读取时者个寄存器必须返回0。比特6设置为1,则会调用该功能的BIST机制。BIST完成后,该功能将复位bit6。如果该功能未能在2s的事件内复位bit6,配置软件必须放弃执行该功能。在BIST结束后,测试结果会立即反映在该寄存器的低端4比特中。如果结果值为0,则表示已成功完成BIST;若为非零值,则表示这是一个功能专用错误代码。
(5)Subsystem ID 和 Subsystem Vendor ID 寄存器
这两个寄存器和 Device ID 和 Vendor ID 类似,也是记录 PCI 设备的生产厂商和设备名称。但是这两个寄存器和 Device ID 与 Vendor ID 寄存器略有不同。下文以一个实例说明Subsystem ID 和 Subsystem Vendor ID 的用途。
Xilinx 公司在 FGPA 中集成了一个 PCIe 总线接口的 IP 核,即 LogiCORE。用户可以使用LogiCORE 设计各种各样基于 PCIe 总线的设备,但是这些设备的 Device ID 都是0x10EE,而Vendor ID 为0x0007[3]。这里即可使用Subsystem ID 和 Subsystem Vendor ID 寄存器来区分这些设备。
(6)Expansion ROM base address 寄存器
有些 PCI 设备在处理器还没有运行操作系统之前,就需要完成基本的初始化设置,比如显卡、键盘和硬盘等设备。为了实现这个“预先执行”功能,PCI 设备需要提供一段 ROM 程序,而处理器在初始化过程中将运行这段 ROM 程序,初始化这些 PCI 设备。Expansion ROM base address 记载这段 ROM 程序的基地址。
(6) Class寄存器
这个寄存器属于PCI兼容寄存器,要求强制实现。如下图,它是个24bits的只读存储器,分为3个区域:基类、子类和编程接口。用于确定该功能的基本功能和功能更为明确的子类,以及在某些情况下的寄存器专用编程接口。
高字节用于定义该功能的基类;
中间字节用于定义基类中的子类;
低字节用于定义编程接口。
下表列出了当前新定义的基类代码,对虚度基类/子类而言,编程解扣子解被硬连线成返回0(无意义)。但对某些类而言是有意义的。
当操作系统试图与类驱动程序一起工作的功能时,类代码寄存器很有用。操作系统能找出一个具有基类代码和子类代码的功能,驱动程序就能与该功能一起工作。类驱动程序比制造商提供的仅与某个特定功能一起工作的驱动程序更具灵活性。
编程接口字节:为准确识别寄存器组的布局提供了最终的尺度。
(7)Capabilities Pointer 寄存器
在 PCI 设备中,该寄存器是可选的,但是在 PCI-X 和 PCIe 设备中必须支持这个寄存器,Capabilities Pointer 寄存器存放 Capabilities 寄存器组的基地址,PCI 设备使用Capabilities 寄存器组存放一些与 PCI 设备相关的扩展配置信息。后面会详细说明。
(8)Interrupt Line 寄存器
这个寄存器是系统软件对 PCI 设备进行配置时写入的,该寄存器记录当前 PCI 设备使用的中断向量号,设备驱动程序可以通过这个寄存器,判断当前 PCI 设备使用处理器系统中的哪个中断向量号,并将驱动程序的中断服务例程注册到操作系统中。
(9)Interrupt Pin 寄存器
这个寄存器保存 PCI 设备使用的中断引脚,PCI 总线提供了四个中断引脚 INTA#、INTB#、INTC#和 INTD#。Interrupt Pin 寄存器为1时表示使用 INTA#引脚向中断控制器提交中断请求,为2表示使用 INTB#,为3表示使用 INTC#,为4表示使用 INTD#。
如果 PCI 设备只有一个子设备时,该设备只能使用 INTA#;如果有多个子设备时,可以使用 INTB~D#信号。如果 PCI 设备不使用这些中断引脚,向处理器提交中断请求时,该寄存器的值必须为0。
(10)Base Address Register 0~5寄存器
该组寄存器简称为 BAR 寄存器,BAR 寄存器保存 PCI 设备使用的地址空间的基地址,该基地址保存的是该设备在 PCI 总线域中的地址。其中每一个设备最多可以有6个基址空间,但多数设备不会使用这么多组地址空间。
在 PCI 设备复位之后,该寄存器将存放 PCI 设备需要使用的基址空间大小,这段空间是I/O 空间还是存储器空间,如果是存储器空间该空间是否可预取。
获得 PCI 设备使用的 BAR 空间的长度,其方法是向 BAR 寄存器写入0xFFFF-FFFF,之后再读取该寄存器。
处理器访问 PCI 设备的 BAR 空间时,需要使用 BAR 寄存器提供的基地址。值得注意的是,处理器使用存储器域的地址,而 BAR 寄存器存放 PCI 总线域的地址。因此处理器系统并不能直接使用“BAR 寄存器+偏移”的方式访问 PCI 设备的寄存器空间,而需要将 PCI 总线域的地址转换为存储器域的地址。
如果 x86处理器系统使能了 IOMMU 后,这两个地址也并不一定相等,因此处理器系统直接使用这个 PCI 总线域的物理地址,并不能确保访问 PCI 设备的 BAR 空间的正确性。除此之外在 Linux 系统中,ioremap 函数的输入参数为存储器域的物理地址,而不能使用 PCI 总线域的物理地址。
而在 pci_dev->resource[bar].start 参数中保存的地址已经经过 PCI 总线域到存储器域的地址转换,因此在编写 Linux 系统的设备驱动程序时,需要使用pci_dev->resource[bar].start 参数中的物理地址,然后再经过 ioremap 函数将物理地址转换为“存储器域”的虚拟地址。
(11)Command 寄存器
该寄存器为 PCI 设备的命令寄存器,该寄存器在初始化时,其值为0,此时这个 PCI 设备除了能够接收配置请求总线事务之外,不能接收任何存储器或者 I/O 请求。系统软件需要合理设置该寄存器之后,才能访问该设备的存储器或者 I/O 空间。在 Linux 系统中,设备驱动程序调用 pci_enable_device 函数,使能该寄存器的 I/O 和 Memory Space 位之后,才能访问该设备的存储器或者 I/O 地址空间。
(12)Status 寄存器
该寄存器的绝大多数位都是只读位,保存 PCI 设备的状态。
(13)Latency Timer 寄存器
在 PCI 总线中,多个设备共享同一条总线带宽。该寄存器用来控制 PCI 设备占用 PCI总线的时间,当 PCI 设备获得总线使用权,并使能 Frame#信号后,Latency Timer 寄存器将递减,当该寄存器归零后,该设备将使用超时机制停止[6]对当前总线的使用。
如果当前总线事务为 Memeory Write and Invalidate 时,需要保证对一个完整 Cache行的操作结束后才能停止当前总线事务。对于多数 PCI 设备而言,该寄存器的值为32或者64,以保证一次突发传送的基本单位为一个 Cache 行。
PCIe 设备不需要使用该寄存器,该寄存器的值必须为0。因为 PCIe 总线的仲裁方法与PCI 总线不同,使用的连接方法也与 PCI 总线不同。
3.3 PCI 桥的配置空间
PCI 桥使用的配置空间的寄存器如下图所示。PCI 桥作为一个 PCI 设备,使用的许多
配置寄存器与 PCI Agent 的寄存器是类似的,如 Device ID、Vendor ID、Status、Command、Interrupt Pin、Interrupt Line 寄存器等,本节不再重复介绍这些寄存器。下文将重点介绍在 PCI 桥中与 PCI Agent 的配置空间不相同的寄存器。
PCI桥中的BAR寄存器只有俩组且在不再私有寄存器的情况下不去使用。在 PCI 桥的配置空间中使用两个 BAR 寄存器的目的是这两个32位的寄存器可以组成一个64位地址空间。
(1) Subordinate Bus Number、Secondary Bus Number 和 Primary Bus Number 寄存器
PCI 桥可以管理其下的 PCI 总线子树。其中 Subordinate Bus Number 寄存器存放当前PCI 子树中,编号最大的 PCI 总线号。而 Secondary Bus Number 寄存器存放当前 PCI 桥Secondary Bus 使用的总线号,一个 PCI 桥能够管理的 PCI 总线号在 Secondary Bus Number~Subordinate Bus Number 之间。这两个寄存器的值由系统软件遍历 PCI 总线树时设置。Primary Bus Number 寄存器存放该 PCI 桥上游的 PCI 总线号,该寄存器可读写。Primary Bus Number、Subordinate Bus Number 和 Secondary Bus Number 寄存器在初始化时必须为0,系统软件将根据这几个寄存器是否为0,判断 PCI 桥是否被配置过。
不同的操作系统使用不同的 Bootloader 引导,有的 Bootloader 可能会对 PCI 总线树进行遍历,此时操作系统可以不再重新遍历 PCI 总线树。在 x86处理器系统中,Bios 会遍历处理器系统中的所有 PCI 总线树,操作系统可以直接使用 BIOS 的结果,也可以重新遍历 PCI总线树。而 PowerPC 处理器系统中的 Bootloader,如 U-Boot 并没有完全遍历 PCI 总线树,此时操作系统必须重新遍历 PCI 总线树。
(2) Secondary Status 寄存器
该寄存器的含义与 PCI Agent 配置空间的 Status 寄存器的含义相近,PCI 桥的 Secondary Status 寄存器记录 Secondary Bus 的状态,而不是 PCI 桥作为 PCI 设备时使用的状态。
(3) Secondary Latency Timer 寄存器
该寄存器的含义与 PCI Agent 配置空间的 Latency Timer 寄存器的含义相近,PCI 桥的Secondary Latency Timer 寄存器管理 Secondary Bus 的超时机制,即 PCI 桥发向下游的总线事务;在 PCI 桥配置空间中还存在一个 Latency Timer 寄存器,该寄存器管理 PCI 桥发向上游的总线事务。
(4)I/O Limit 和 I/O Base 寄存器
在 PCI 桥下设备的IO资源基地址和大小。
(5)Memory Limit 和 Memory Base 寄存器
在 PCI 桥下设备的mem资源基地址和大小。
(6)Prefetchable Memory Limit 和 Prefetchable Memory Base 寄存器
在 PCI 桥管理的 PCI 子树中有许多 PCI 设备,如果这些 PCI 设备支持预读,则需要从PCI 桥的可预读空间中获取地址空间。PCI 桥的这两个寄存器存放这些 PCI 设备使用的,可预取存储器空间的基地址和大小。
如果 PCI 桥不支持预读,则其下支持预读的 PCI 设备需要从 Memory Base 寄存器为基地址的存储器空间中获取地址空间。如果 PCI 桥支持预读,其下的 PCI 设备需要根据情况,决定使用可预读空间,还是不可预读空间。PCI 总线建议 PCI 设备支持预读,但是支持预读的PCI 设备并不多见。
(7)I/O Base Upper 16 Bits and I/O Limit Upper 16寄存器
如果 PCI 桥仅支持16位的 I/O 端口,这组寄存器只读,且其值为0。如果 PCI 桥支持32位 I/O 端口,这组寄存器可以提供 I/O 端口的高16位地址。
(8)Bridge Control Register。
该寄存器用来管理 PCI 桥的 Secondary Bus,其主要位的描述如下。Secondary Bus Reset 位,第6位,可读写。当该位为1时,将使用下游总线提供的 RST#-信号复位与 PCI 桥的下游总线连接的 PCI 设备。通常情况下与 PCI 桥下游总线连接的PCI 设备,其复位信号需要与 PCI 桥提供的 RST#信号连接,而不能与 HOST 主桥提供的RST#信号连接。Primary Discard Timer 位,第8位,可读写。PCI 桥支持 Delayed 传送方式,当 PCI桥的 Primary 总线上的主设备使用 Delayed 方式进行数据传递时,PCI 桥使用 Retry 周期结束 Primary 总线的 Non-Posted 数据请求,并将这个 Non-Posted 数据请求转换为Delayed 数据请求,之后主设备需要择时重试相同的 Non-Posted 数据请求。当该位为1时,表示在 Primary Bus 上的主设备需要在2 ^10 个时钟周期之内重试这个数据请求,为0 ^15时,表示主设备需要在2 个时钟周期之内重试这个数据请求,否则 PCI 桥将丢弃 Delayed数据请求。
Secondary Discard Timer 位,第9位,可读写。当该位为1时,表示在 Secondary Bus 上的主设备需要在2 10 个时钟周期之内重试这个数据请求,为0时,表示主设备需要在2^15个时钟周期之内重试这个数据请求,如果主设备在规定的时间内没有进行重试时,PCI桥将丢弃 Delayed 数据请求。具体可参考PCI-to-PCI Bridge Architecture Specification Revision 1.2。
四、PCI 总线的配置请求
PCI 总线定义了两类配置请求,一个是 Type 00h 配置请求,另一个是 Type 01h 配置请求。PCI 总线使用这些配置请求访问 PCI 总线树上的设备配置空间,包括 PCI 桥和 PCI Agent设备的配置空间。
其中 HOST 主桥或者 PCI 桥使用 Type 00h 配置请求,访问与 HOST 主桥或者 PCI 桥直接相连的 PCI Agent 设备或者 PCI 桥;而 HOST 主桥或者 PCI 桥使用 Type 01h 配置请求,需要至少穿越一个 PCI 桥,访问没有与其直接相连的 PCI Agent 设备或者 PCI 桥。Type 01h 配置请求在通过 PCI 桥时,到达目标设备时,将被转换为 Type 00h 配置请求,并读取 PCI Agent 设备的配置寄存器。
值得注意的是,PCIe 总线还可以使用 ECAM(Enhanced Configuration Access Mechanism)机制访问 PCIe 设备的扩展配置空间,使用这种方式可以访问 PCIe 设备256B~4KB 之间的扩展配置空间。
参考:(2条消息) PCIE系统标准体系结构解读(九):PCIe配置_fpgaer0630的博客-CSDN博客
参考:(4条消息) PCIE系统标准体系结构解读(九):PCIe配置_fpgaer0630的博客-CSDN博客
参考:(36条消息) PCIe学习笔记之pcie结构和配置空间_Hober_yao的博客-CSDN博客_downstream portc
以上是关于PCI Header配置空间详解的主要内容,如果未能解决你的问题,请参考以下文章
Linux下PCI设备驱动程序开发 --- PCI驱动程序实现