pci 配置空间
每个PCI设备有许多地址配置的寄存器,初始化时要通过这些寄存器来配置该设备的总线地址,一旦完成配置以后,CPU就可以访问该设备的各项资源了。PCI标准规定每个设备的配置寄存器组最多可以有256个连续的字节空间,开头64个字节叫头部,分为0型(PCI设备)和1型(PCI桥)头部,头部开头16个字节是设备的类型、型号和厂商等。这些头部寄存器除了地址配置的作用,还能使CPU能够探测到相应设备的存在,这样就不需要用户告诉系统都有哪些设备了,而是改由CPU通过一个号称枚举的过程自动扫描探测所有挂接在PCI总线上的设备。
由于PCI/PCIe设备分为Bridge和Agent两种,所以配置空间也有两种类型:
其中Agent的配置空间类型称为Type 00h:
简单介绍其中的几个寄存器的意义:
Vendor ID,Device ID:标记了一个设备的生产厂商和具体的设备,比如Intel的设备Vendor ID通常是0x8086,Device ID就需要厂家自定义了,总之能够识别到具体是哪个设备就可以了。
Status:设备状态字,具体每个BIT的意义见下图:
Command:设备状态字:
Base Address Registers:决定PCI/PCIe设备空间映射到系统空间具体位置的寄存器,映射方式有两种,分别是IO和Memory映射:
处理器系统资源分为IO资源和MMIO资源两种,因此PCI/PCIe空间地址对应也有两种。
下面是Bridge的配置空间,它的类型被称为Type 01h:
Type 01h中也有Vendor ID,Device ID,Status,Command等寄存器。
另外需要注意的是这里的BAR计算得到的系统空间是该桥下挂的所有设备的系统空间的总和。
另外Subordinate Bus Number、Secondary Bus Number和Primary Bus Number,这些寄存器共同确定了该桥上行和下行的所有Bus号。
二.PCI驱动
1. PCI寻找空间
PCI设备包括杀个寻址空间:配置空间,I/O端口空间,内存空间。
1.1 PCI配置空间:
内核为驱动提供的函数:
pci_read_config_byte/word/dword(struct pci_dev *pdev, int offset, int *value)
pci_write_config_byte/word/dword(struct pci_dev *pdev, int offset, int *value)
配置空间的偏移定义在include/linux/pci_regs.h
1.2 PCI的I/O和内存空间:
从配置区相应寄存器得到I/O区域的基址:
pci_resource_start(struct pci_dev *dev, int bar) Bar值的范围为0-5。
从配置区相应寄存器得到I/O区域的内存区域长度:
pci_resource_length(struct pci_dev *dev, int bar) Bar值的范围为0-5。
从配置区相应寄存器得到I/O区域的内存的相关标志:
pci_resource_flags(struct pci_dev *dev, int bar) Bar值的范围为0-5。
申请I/O端口:
request_mem_region(io_base, length, name)
读写:
inb() inw() inl() outb() outw() outl