杂文|PCI设备读取配置空间

【杂文|PCI设备读取配置空间】一个较为典型的PCI总线体系结构图。


我们来看看PCI设备是如何被识别和工作的。
首先,如何读取配置空间
PCI设备的配置信息包含了关于这个设备的基本情况的介绍,包括设备的名称,功能,使用方式等,因此首先必需要读取PCI设备的配置空间,才能够再讨论PCI设备的识别以及操作了。
PCI 规范系列文档总共定义了三种方法让CPU 通过Host/PCI 桥在PCI 总线上启动配置空间访问事务,这三种方法是:(1)配置机制#1,即Host/PCI 桥将CPU 对Host/PCI 桥设备的配置地址端口0xcf8 和配置数据端口0xcfc 的访问转换为桥后PCI 总线上的配置空间访问事务。这也是PCI Specification 2.2 所定义的唯一方法。(2)配置机制#2。这是早期PCI 规范所定义的方法,在PCI Specification 2.2 中已经被去除。(3)通过PCI BIOS 提供的服务来访问配置空间。我主要介绍一下最最常用的第一种方法。
对于PC-AT compatible System,可以通过两个I/O端口来操作,CONFIG_ADDRESS(CF8h),CONFIG_DATA(CFCh)(都是32位的),通过给CONFIG_ADDRESS写如下命令字



Bus Number选择是那个PCI总线,Device Number选择这个总线上的那个设备,Function Number选择这个设备上的那个子设备(称作功能),host-bridge会通过以上信息选择正确的pci设备(置高正确的IDSEL引脚),然后给这个pci设备发送configuration read/write(可以参考PCI总线规范,PCI总线上一共有三种不同读写类型的命令,IO,MEMORY,CONFIG,具体的做法是通过在给PCI设备传送地址的时候C/BE[3:0]引脚上的值来决定到底是什么命令的,随后是data circle) 命令读取配置空间相应的Register Number处的Dword值到CONFIG_DATA端口上。
Configuration read/write命令同一般的io或mem的read/write不一样,他在PCI地址线上放的不是实际的地址,而是将CONFIG_ADDRESS上的数据改变了一下放到PCI总线的AD引脚上,如图(当然对于所找的PCI设备不在host-bridge后直联的pci总线上的情况,还要复杂点)。


PCI设备规定必须要支持configuration read/write操作,所以其会回复相应的配置空间Register Number位置处的值给host bridge,从而传递到COFIG_DATA端口。
对于PCI设备的配置空间,这个是有规定的,最小为150字节,格式如下:


另外,补充一下,对于端口CF8h和CFCh的访问必须是双字DWORD的访问,其他的访问会被host bridge直接传递,因此这两个端口还可以给其他设备用。


再来看看PCI设备是如何被识别的
当机器刚启动以后,内核在起初始化阶段会依次采用上面提到的三种访问配置空间的方法来查询主板上PCI总线上的PCI设备的配置空间。内核首要查找的是PCI总线编号为0的那个PCI根总线上的Host/PCI桥或者是VGA现实控制器的PCI设备,或者是厂商ID为INTEL和Compaq的PCI设备,只要上述的设备之一被检查到,那么内核就结束了PCI总线的探测工作,确定了通过哪种方式来访问配置空间。随后,系统会进行PCI总线枚举过程,也就是说它会依次查询各个PCI总线上的所有设备(从根总线开始查找其下面的每一个设备,其它的总线对于上级总线来说也类似于一个PCI设备,一次可以递归深入查找),枚举的过程其实就是往CONFIG_ADDRESS端口发送各种不同Bus Number以及Device Number的命令字。经过这个枚举过程,系统就得到了当前主板上的所有PCI设备的配置信息了。
PCI设备通过这些配置信息(看上面的那个表)告诉系统自己的ID(用来区分不同的设备以及帮助驱动程序绑定特定的设备),同时还可以把PCI设备上的一些寄存器、内存和IO资源通过BAR(Base Address Register)告诉系统,从而系统可以根据这些信息给设备上的寄存器和内存和IO端口资源分配总线地址,在必要的时候再将这些资源映射到系统内存和端口上(这一步是通过驱动程序实现的,将PCI设备的物理资源(即总线地址)建立虚拟映射),这样访问PCI设备,就变成了访问系统内存和IO端口操作了(通过命令iowrite32/ioread32操作)。对于设备上大内存的访问,也有通过DMA实现的,它可以将PCI总线这边的(也就是主机下的)内存里的数据,搬移到pci总线上的设备的内存中,当然前提是这个设备支持这种DMA(做法是把主机内存的虚拟地址转换成总线地址,然后再填写设备的目标和源地址,以及传输的数据大小,启动DMA就可以了)。
设备被识别以后,驱动程序也建立好了相应的内存和端口映射了,那么就是要按照不同的PCI设备的手册来读写设备的寄存器、内存以及IO端口,完成设备相应的功能。PCI驱动程序一般只是封装了几组底层的访问特定寄存器、内存和IO端口的操作,提供给用户一组实在的功能,如读取PCI设备的视频信息等。
http://snowrry.spaces.live.com/blog/cns!33E68980CE576FDD!1286.entry

    推荐阅读