补充:
PCI/PCIe基础——配置空间:
http://blog.csdn.net/jiangwei0512/article/details/51603525
8.1 深入理解PCI总线
8.1.1 PCI设备工作原理
8.1.2 PCI总线域
8.1.3 PCI资源管理
为了管理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.4 PCI配置空间读取和设置
第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读取该地址的配置信息。