因为很多device都是PCI device,所以本章重点看一下PCI(Peripheral Component Interconnect),首先明确一点,PCI是总线类型,总线有两种接口类型组成,electrical interface和programming interface,软件层面都属于programming interface。
12.1. The PCI Interface
PCI由一系列的spec组成,我们只关注kernel里面,PCI device driver如何找到PCI device并且访问它。
PCI总线是为了替代ISA总线,主要为了实现三个目标:
1,提高计算机和外设之间数据传输的速率
2, 让外设与平台无关
3, 方便的添加和移除PCI设备
第一个目标,PCI总线提供了更好的频率,比如25MHz或者33MHz,66Mhz,甚至133MHz。PCI可以可以实现32bit或者64bit总线位宽,并且同时设计为与平台无关,比如IA-32,Alpha,PowerPC,SPARC64,以及IA-64系统。对于developer而言,PCI支持动态检测PCI设备,PCI设备在系统bootup阶段就会被配置,driver后续能直接访问device的配置信息,从而方便的完成设备初始化。
12.1.1. PCI Addressing
PC上存在很多的PCI设备,如何快速的找到某一个特定的PCI device?这就涉及到PCI设备的寻址。
每一个PCI device在系统中都有一个唯一的ID,这个ID由bus number,device number,function number组成,这三个值的组合在系统中是唯一的,所以说只要知道了BDF(Bus,Device,Function)值,就能找到对应的PCI device。
PC的标准,最开始只支持256个bus number,但是对于大型系统而言,256个bus显然太少了。所以Linux增加了一个domain的概念,一个domain最多包含256个bus,一个bus最多包含32个device,一个device最多包含8个function,BDF加起来就是16bit,所以一个16bit的地址就能标记一个function。不过device driver不需要直接使用BDF,而应该通过pci_dev来访问PCI device。
如果一个系统中有不止一个bus,就需要通过bus bridge把这些bus聚合到一起。而绝大部分的PCI都有不止一个PCI bus,所以一般都有PCI bus bridge,由PCI bridge把这些PCI bus链接到系统总线。PCI的整个系统按照树形结构来管理,每一个bus链接到上层的bus,直到bus 0,也就是root bus为止:
通常情况下,不需要使用BDF来访问PCI 设备,因为都被隐藏在了struct pci_dev这个结构体里面,但是有些情况下,需要直接使用BDF,比如在用户态,通过lspci查看pci device的id等情况,这个时候就需要打印所有PCI设备的BDF。比如某个PCI device的BDF是0000:00:00.1,其中前面的0000是domain,后面的00是8bit bus number,最大为255,再后面的00是5bit device number,最大为31,最后的1是3bit的function,最大为7.
$ lspci | cut -d: -f1-3
0000:00:00.0 Host bridge
0000:00:00.1 RAM memory
0000:00:00.2 RAM memory
0000:00:02.0 USB Controller
0000:00:04.0 Multimedia audio controller
0000:00:06.0 Bridge
0000:00:07.0 ISA bridge
0000:00:09.0 USB Controller
0000:00:09.1 USB Controller
0000:00:09.2 USB Controller
0000:00:0c.0 CardBus bridge
0000:00:0f.0 IDE interface
0000:00:10.0 Ethernet controller
0000:00:12.0 Network controller
0000:00:13.0 FireWire (IEEE 1394)
0000:00:14.0 VGA compatible controller
$ cat /proc/bus/pci/devices | cut -f1
0000
0001
0002
0010
0020
0030
0038
0048
0049
004a
0060
0078
0080
0090
0098
00a0
$ tree /sys/bus/pci/devices/
/sys/bus/pci/devices/
|-- 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0
|-- 0000:00:00.1 -> ../../../devices/pci0000:00/0000:00:00.1
|-- 0000:00:00.2 -> ../../../devices/pci0000:00/0000:00:00.2
|-- 0000:00:02.0 -> ../../../devices/pci0000:00/0000:00:02.0
|-- 0000:00:04.0 -> ../../../devices/pci0000:00/0000:00:04.0
|-- 0000:00:06.0 -> ../../../devices/pci0000:00/0000:00:06.0
|-- 0000:00:07.0 -> ../../../devices/pci0000:00/0000:00:07.0
|-- 0000:00:09.0 -> ../../../devices/pci0000:00/0000:00:09.0
|-- 0000:00:09.1 -> ../../../devices/pci0000:00/0000:00:09.1
|-- 0000:00:09.2 -> ../../../devices/pci0000:00/0000:00:09.2
|-- 0000:00:0c.0 -> ../../../devices/pci0000:00/0000:00:0c.0
|-- 0000:00:0f.0 -> ../../../devices/pci0000:00/0000:00:0f.0
|-- 0000:00:10.0 -> ../../../devices/pci0000:00/0000:00:10.0
|-- 0000:00:12.0 -> ../../../devices/pci0000:00/0000:00:12.0
|-- 0000:00:13.0 -> ../../../devices/pci0000:00/0000:00:13.0
`-- 0000:00:14.0 -> ../../../devices/pci0000:00/0000:00:14.0
PCI hardware会提供三种地址空间的查询:memory locations, I/O ports,