目录
6. Linux读取Capabilities List代码解析
1. 配置空间概念和作用
详细的定义可以参考PCI Spec的第六章《Configuration Space》中的描述,这里仅摘抄关键点
- 所有的PCI设备必须实现配置空间,配置空间的本质是一堆寄存器。
- 配置空间可以用来发现设备
- pci local bus spec规定的配置空间最大256字节,前64字节是spec中定义好的,称预定义空间,其中前16字节对所有类型的pci设备都相同(是指格式,而不其中具体的值),之后的空间格式因类型而不同,对前16字节空间,我称它为通用配置空间。

上面是摘自PCI3.0规范的配置空间,一共64字节,即预定义空间,其中前16字节对应通用配置空间。
预定义空间解析
vendor id:厂商ID,用来标识pci设备出自哪个厂商,这里是0x1af4,来自Red Hat。
device id:厂商下的产品ID,传统virtio-blk设备,这里是0x1001
revision id:厂商决定是否使用,设备版本ID,这里未使用
header type:pci设备类型,0x00(普通设备),0x01(pci bridge),0x02(CardBus bridge)。virtio是普通设备,这里是0x00

status: 描述pci设备状态的寄存器

其中有一位是Capabilities List,它是pci规范定义的附加空间标志位,Capabilities List的意义是允许在pci设备配置空间之后加上额外的寄存器,这些寄存器由Capability List组织起来,用来实现特定的功能,附加空间在64字节配置空间之后,最大不能超过256字节。以virtio-blk为例,它标记了这个位,因此在virtio-blk设备配置空间之后,还有一段空间用来实现virtio-blk的一些特有功能。1表示capabilities pointer字段(0x34)存放了附加寄存器组的起始地址。这里的地址表示附加空间在pci设备空间内的偏移。具体Capability List怎么理解本文后面分析。
2. 通过配置空间发现设备
发下设备需要确定两个事情:PCI设备地址,以及确定地址之后具体怎么通过该地址访问。
PCI设备地址 : 参考PCI规范3.2.2.3.2章节
设备地址可以通过Bus号,Device号,功能号和寄存器号唯一确定:


Linux内核中确定该地址可以通过宏:
/*
* Functions for accessing PCI base (first 256 bytes) and extended
* (4096 bytes per PCI function) configuration space with type 1
* accesses.
*/
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
| (devfn << 8) | (reg & 0xFC))
访问配置空间
- 配置空间寄存器偏移
PCI_CONF1_ADDRES宏确定了配置空间的基地址(Base Address),还要结合配置空间偏移具体访问具体的功能,比如访问配置空间的Command对应的offset:04h,Capabilities pointer偏移:0x34h。
- 端口访问
配置空间地址无法直接访问,需要通过特定的端口来访问:
CONFIG_ADDRESS(CF8h) : 将需要访问的配置空间地址设置到该端口
CONFIG_DATA(CFCh):从该端口读取配置空间的值。

3. Linux读取PCI配置空间接口
//参数dev : pci 设备
//where : 配置空间寄存器对应的偏移offset
int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(const struct pci_dev *dev, int where, u16 val

文章详细介绍了PCI设备的配置空间概念,包括其作用、结构和预定义空间的解析。接着,讲述了如何通过配置空间发现和访问PCI设备,重点解析了Linux内核中的接口`pci_read_config_*`。此外,文章讨论了Virtio设备的自定义空间和CapabilitiesList,以及Linux内核如何读取这些信息。最后,展示了`virtio_pci_modern_probe`函数的代码,解释了如何遍历和解析CapabilitiesList。
最低0.47元/天 解锁文章
2939

被折叠的 条评论
为什么被折叠?



