补充:
PCI/PCIe基础——配置空间:
/jiangwei0512/article/details/51603525
8.1深入理解PCI总线
8.1.1PCI设备工作原理
8.1.2 PCI总线域
8.1.3PCI资源管理
为了管理PCI设备的I/O端口和I/O内存,内核定义了一个resource结构:
代表I/O端口的resource :
struct resource ioport_resource = {.name= "PCI IO",.start= 0,.end= IO_SPACE_LIMIT,.flags= IORESOURCE_IO,};
ioport_resource起始地址为 0 ,结束地址 0xffff ,这个变量定义了全部的I/O端口地址空间,每个PCI设备新加入系统,都要检查它的配置空间的I/O端口的结束地址是否大于0xffff ,和现存的设备是否冲突,是否可以插入I/O端口地址空间。
I/O内存的resource结构:
struct resource iomem_resource = {.name= "PCI mem",.start= 0,.end= -1,.flags= IORESOURCE_MEM,};EXPORT_SYMBOL(iomem_resource);
I/O内存需要映射到主机内存地址空间,所以结束地址为-1。当PCI设备加入系统的时候,检查它的配置空间的I/O内存和其他设备是否冲突,是否可以插入I/O内存地址空间。
8.1.4PCI配置空间读取和设置
第3章,PCI设备的读取通过I/O指令读一个特殊的I/O端口空间来完成。内核提供了一个pci_raw_ops结构来控制配置空间的读写。这个结构的读写和函数通常被设置为pci_confl_read函数和pci_confl_write函数,通过它们执行对PCI配置空间的读写。
/include/linux/pci.h
struct pci_raw_ops {int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,int reg, int len, u32 *val);int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn,int reg, int len, u32 val);};
read和write函数指针的调用进行读写操作;
分析pci_confl_read函数对PCI配置空间的读取过程如下所示:
static int pci_conf1_read(unsigned int seg, unsigned int bus,unsigned int devfn, int reg, int len, u32 *value){unsigned long flags;if ((bus > 255) || (devfn > 255) || (reg > 4095)) {*value = -1;return -EINVAL;}raw_spin_lock_irqsave(&pci_config_lock, flags);outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);switch (len) {case 1:*value = inb(0xCFC + (reg & 3));break;case 2:*value = inw(0xCFC + (reg & 2));break;case 4:*value = inl(0xCFC);break;}raw_spin_unlock_irqrestore(&pci_config_lock, flags);return 0;}
pci_conf1_read函数首先往I/O端口0xCF8写入一个PCI地址,然后从I/O端口 0xCFC读取该地址的配置信息。
如果觉得《PCI总线---深入理解PCI总线》对你有帮助,请点赞、收藏,并留下你的观点哦!