linux pci 协议一
先打下广告,上面是一本好书了O(∩_∩)O~
前言
因为遇到一个pci总线的问题,所以去学习了解linux 的pci驱动,中间总结了一些pci总线原理和linux驱动的知识,在此总结出来备查。
PCI总线原理简介
组成结构
PCI总线是一种局部总线,与系统总线有所区别,主要是为了连接外设。它在一个处理器系统中的位置如下图
与PCI总线相关的模块包括,HOST主桥、PCI总线、PCI桥和PCI设备,所有的PCI设备组成一棵树,后面会看到linux内核在内存中也维护了一棵类似的树。当然这个图只是一种特例,有的系统中存储器控制器的位置是集成在cpu中的,有些简单的系统可能没有PCI桥,只有PCI设备和和主桥。
1. HOST主桥
HOST主桥是一个很特别的桥片,其主要功能是隔离处理器系统的存储器域与处理器系统的PCI总线域,管理PCI总线域,并完成处理器与PCI设备间的数据交换。处理器与PCI设备间的数据交换主要由“处理器访问PCI设备的地址空间”和“PCI设备使用DMA机制访问主存储器”这两部分组成。HOST主桥是联系处理器与PCI设备的桥梁。在一个处理器系统中,每一个HOST主桥都管理了一颗PCI总线树,在同一棵PCI总线树上的所有PCI设备属于同一个PCI总线域。
2. PCI总线
PCI总线由HOST主桥或者PCI桥管理,用来连接各类设备,与HOST主桥直接连接的PCI总线通常被命名为PCI总线0
3. PCI设备
在PCI总线中有三类设备,PCI主设备、PCI从设备和桥设备。其中PCI从设备只能被动地接收来自HOST主桥,或者其他PCI设备的读写请求;而PCI主设备可以通过总线仲裁获得PCI总线的使用权,主动地向其他PCI设备或者主存储器发起存储器读写请求。而桥设备的主要作用是管理下游的PCI总线,并转发上下游总线之间的总线事务。
PCI桥可以连接两条PCI总线,上游PCI总线和下游PCI总线,这两个PCI总线属于同一个PCI总线域,使用PCI桥扩展的所有PCI总线都同属于一个PCI总线域。
读写总线事务
PCI总线使用单端并行数据线,采用地址译码方式进行数据传递,而采用ID译码方式进行配置信息的传递。其中地址译码方式使用地址信号,而ID译码方式使用PCI设备的ID号,包括BusNumber、DeviceNumber、FunctionNumber和RegisterNumber。
我们主要关心与软件关系比较密切的存储器读写总线事务,和配置读写总线事务。
配置读写
前面讲到PCI总线域地址空间与存储区域地址空间不同,需要Host主桥进行地址转换,配置读写总线事务当然涉及到了这个转换过程。我们对配置读写总线事务的硬件处理不关心,而不同host主桥的实现方式不同,配置过程也就不同。内核提供了现成的配置方法,我们着重关注可以配置什么。
PCI总线规定了三种类型的PCI配置空间,分别是PCI Agent设备使用的配置空间,PCI桥使用的配置空间和Cardbus桥片使用的配置空间。值得注意的是,在PCI设备配置空间中出现的地址都是PCI总线地址,属于PCI总线域地址空间。
各个配置寄存器详细说明见参考资料[1]
数据读写(假定配置空间已经被系统软件初始化)
PCI总线支持以下几类存储器读写总线事务。
(1) HOST处理器对PCI设备的BAR空间进行数据读写,BAR空间可以使用存储器或者I/O译码方式。HOST处理器使用PCI总线的存储器读写总线事务和I/O读写总线事务访问PCI设备的BAR(base address也就是数据基地址)空间。
(2) PCI设备之间的数据传递。在PCI总线上的两个设备可以直接通信,如一个PCI
设备可以访问另外一个设备的BAR空间。不过这种数据传递在PC处理器系统中,
较少使用。
(3) PCI设备对主存储器进行读写,即DMA读写操作。DMA读写操作在所有处理器系统中都较为常用,也是PCI总线数据传送的重点所在。在多数情况下,DMA读写操作结束后将伴随着中断的产生。PCI设备可以使用INTA#、INTB#、INTC#和INTD#信号提交中断请求,也可以使用MSI机制提交中断请求。(pci设备通过dma向主存中传数据时,收到中断请求时内存中数据未必立即可用,需要先读)
读写的具体过程这里不再具体描述。感兴趣的读者参考资料[1]。