PCI-PCIE初始化流程主要分成如下几个部分:
第一部分:解析设备树,获取控制器地址资源,CPU-MEM域地址资源,PCIE域地址资源以及两者的关系,中断资源等信息
#address-cells=<0x2>//父域地址长度
#size_cell=<0x2>//父域大小长度
pcie@fbef08000 {
......
#address-cells=<0x3>//子域地址长度
#size_cell=<0x2>//子域大小长度
ranges = <0x2000000 0x0 0x80000000 0xf 0x80000000 0x0 0x20000000>
//ranges表示CPU域和PCI-PCIE域的映射关系,规则为 PCIE子域 CPU父域 父域/子域长度
//所以0x2000000 0x0 0x80000000代表子域,0xf 0x80000000代表父域,0x0 0x20000000代表长度
//其中,0x2000000表示该PCI域段是MEM空间属性,不是I/O空间属性,起始地址0x0 0x80000000
//0xf 0x80000000表示从CPU的角度来看,该域段起始的地址
interrupt-parent = <&mpic>
......
interrupt-map = <
/**/
0x20a00 0x0 0x0 0x3 &mpic 0xb 0x1
......
>
}
第二部分:建立总线,将设备树获取的信息保存在总线配套的数据结构里面
第三部分:遍历设备,根据PCIE协议探测设备,并获取到设备硬件需要的MEM大小以及硬件中断号
例如X设备,通过操作BASE_ADDRESS寄存器,获取MEM大小例如[mem 0x00000000 - 0x00ffffff],也就是需要0x1000000大小的空间
第四部分:遍历设备,根据PCIE设备需要的MEM大小,从PCIE资源池里面分配出来,写到BASE_ADDRESS寄存器里面
例如上面说的X设备,如果是第一个遍历的设备 BAR 0:set to [mem 0xf 80000000 - 0xf 80ffffff] PCI addr [0x80000000 - 0x80ffffff]
通过lspci -x读取该设备的PCIE配置空间,可以看到如下信息:
10: 00 00 00 80
10表示0x10地址,也就是第一个BASE_ADDRESS的地址, 00 00 00 80小头序,表示0x80000000,是该设备的PCIE设备PCIE域的MEM起始空间
参考文档:
device tree中对PCIe的描述
https://blog.csdn.net/ambercctv/article/details/53762753
linux 下PCIE控制器设备树 学习
https://blog.csdn.net/wstpt/article/details/75040656
理解linux pci 扫描流程
https://blog.csdn.net/moon146/article/details/18988849