PCIE 设备扫描的过程.docx
- 文档编号:2397440
- 上传时间:2022-10-29
- 格式:DOCX
- 页数:19
- 大小:222.46KB
PCIE 设备扫描的过程.docx
《PCIE 设备扫描的过程.docx》由会员分享,可在线阅读,更多相关《PCIE 设备扫描的过程.docx(19页珍藏版)》请在冰豆网上搜索。
PCIE设备扫描的过程
PCIE设备扫描的过程
初步了解完PCI总线标准之后,我们接下来正式开始PCIe设备的漫游之旅。
从我们按下PC的电源按钮开始,BIOS就接管系统控制权开始工作,它会先进行一些内存和设备的初始化工作(当然,也包括我们的PCI设备),由于商业上的原因,Phoenix等厂商的BIOS代码需要授权协议,在此,我们以另外一个款开源BIOS(openbios)为例,来剖析BIOS中,我们的PCIe设备是如何被找到以及初始化的。
PCI设备的扫描是基于深度优先搜索算法(DFS:
DepthFirstSearch),也就是说,下级分支最多的PCI桥将最先完成其子设备的扫描。
下面我们以图片来具体说明,BIOS是如何一步步完成PCI设备扫描的。
第一步:
PCIHost主桥扫描Bus0上的设备(在一个处理器系统中,一般将与HOST主桥直接相连的PCI总线被命名为PCIBus0),系统首先会忽略Bus0上的D1,D2等不会挂接PCI桥的设备,主桥发现Bridge1后,将Bridge1下面的PCIBus定为Bus1,系统将初始化Bridge1的配置空间,并将该桥的PrimaryBusNumber和SecondaryBusNumber寄存器分别设置成0和1,以表明Bridge1的上游总线是0,下游总线是1,由于还无法确定Bridge1下挂载设备的具体情况,系统先暂时将SubordinateBusNumber设为0xFF。
如下图所示:
第二步:
系统开始扫描Bus1,将会发现Bridge2。
系统将Bridge2下面的PCIBus定为Bus2,并将该桥的PrimaryBusNumber和SecondaryBusNumber寄存器分别设置成1和2,和上一步一样暂时把Bridge2的SubordinateBusNumber设为0xFF。
如下图所示:
第三步:
系统继续扫描Bus2,将会发现Bridge4。
系统将Bridge4下面的PCIBus定为Bus3,并将该桥的PrimaryBusNumber和SecondaryBusNumber寄存器分别设置成2和3,此后
系统继续扫描后发现Bus3下面已经没有任何Bridge了,意味着该PCI总线下已经没有任何挂载下游总线了,因此Bridge4的SubordinateBusNumber的值已经可以确定为3了。
如下图所示:
第四步:
完成Bus3的扫描后,系统返回到Bus2继续扫描,发现Bus2下面已经没有其他Bridge了。
此时Bridge2的SubordinateBusNumber的值也已经可以确定为3了。
如下图所示:
第五步:
完成Bus2的扫描后,系统返回到Bus1继续扫描,会发现Bridge3,系统将Bridge3下面的PCIBus定为Bus4。
并将Bridge4的PrimaryBusNumber和SecondaryBusNumber寄存器分别设置成1和4,此后系统继续扫描后发现Bus4下面已经没有任何Bridge了,意味着该PCI总线下已经没有挂载任何下游总线了,因此Bridge3的SubordinateBusNumber的值已经可以确定为4了。
如下图所示:
第六步:
完成Bus4的扫描后,系统返回到Bus1继续扫描,发现Bus1下面已经没有其他Bridge了。
此时Bridge1的SubordinateBusNumber的值已经可以确定为4,系统返回Bus0继续扫描(Bus0下如果有其他它Bridge,将重复上述的步骤进行扫描)。
至此,本例中的整个PCI的设备扫描已经完成了。
最终的设备和总线的扫描结果如下图所示。
了解了上面PCI设备扫描的大概流程,我们接下来看看Bios代码中具体是如何实现这些扫描的。
一般来说,我们可以通过两个寄存器来访问PCI的配置空间(寄存器CONFIG_ADDRESS与CONFIG_DATA),在x86体系下,这两个寄存器分别对应0xCF8和0xCFC端口,对配置空间的访问都是通过对这两个寄存器的读写来实现先。
CONFIG_ADDRESS寄存器的具体位组成如下图所示:
BusNumber:
总线号(8bit),范围0--255。
DeviceNumber:
设备号(5bit),范围0--31。
FunctionNumber:
功能号(3bit),范围0--7。
RegisterNumber:
寄存器号(6bit),范围0--63(配置空间一共256个字节,分割成64个4字节的寄存器,从0--63编号)。
每个PCI设备可根据上图所示的四个信息:
BusNumber,DeviceNumber,FunctionNumber,RegisterNumber来进行具体设备的定位并对其配置空间访问。
当我们要访问PCI设备的配置空间时,先根据以上格式设置CONFIG_ADDRESS寄存器,然后再读取CONFIG_DATA寄存器即可得到相应的配置空间寄存器的值。
因此,BIOS中PCI配置空间的读写可以封装成下面的函数:
[cpp]viewplaincopy
1.staticinlineuint32_tpci_config_read32(pci_addrdev,uint8_treg)
2.{
3.outl(dev|reg,0xcf8);
4.returninl(0xcfc|reg);
5.}
6.
7.staticinlinevoidpci_config_write32(pci_addrdev,uint8_treg,uint32_tval)
8.{
9.outl(dev|reg,0xcf8);
10.outl(val,0xcfc);
11.}
总体来说。
该BIOS扫描过程中调用如下几个主要的函数:
ob_pci_init---->ob_scan_pci_bus---->pci_find_device---->ob_pci_configure
下面我们来具体看看代码,首先BIOS执行ob_pci_init(void)函数
[cpp]viewplaincopy
1.intob_pci_init(void)
2.{
3.intbus;
4.unsignedlongmem_base,io_base;
5.char*path;
6.
7.#ifdefCONFIG_DEBUG_PCI
8.printk("InitializingPCIdevices...\n");
9.#endif
10.
11./*bruteforcebusscan*/
12.
13./*FindallPCIbridges*/
14.
15.//获取系统指定的memeory与I/O空间的范围,分配给PCIe设备。
16.mem_base=arch->mem_base;
17./*I/Oportsunder0x400areusedbydevicesmappedatfixed
18.location.*/
19.io_base=arch->io_base+0x400;
20.path=strdup("");
21.
22./*遍历256条总线*/
23.for(bus=0;bus<0x100;bus++){
24.ob_scan_pci_bus(bus,&mem_base,&io_base,&path);
25.}
26.free(path);
27.return0;
28.}
总线扫描具体实现:
[cpp]viewplaincopy
1.staticvoidob_scan_pci_bus(intbus,unsignedlong*mem_base,
2.unsignedlong*io_base,char**path)
3.{
4.intdevnum,fn,is_multi,vid,did;
5.unsignedinthtype;
6.pci_addraddr;
7.pci_config_tconfig;
8.constpci_dev_t*pci_dev;
9.uint32_tccode;
10.uint8_tclass,subclass,iface,rev;
11.
12.activate_device("/");
13.for(devnum=0;devnum<32;devnum++){
14.is_multi=0;
15.for(fn=0;fn==0||(is_multi&&fn<8);fn++){
16.#ifdefCONFIG_XBOX
17.if(pci_xbox_blacklisted(bus,devnum,fn))
18.continue;
19.#endif
20.addr=PCI_ADDR(bus,devnum,fn);/*获取设备配置空间地址*/
21.vid=pci_config_read16(addr,PCI_VENDOR_ID);/*获取VendorID*/
22.did=pci_config_read16(addr,PCI_DEVICE_ID);/*获取DeviceID*/
23.
24.if(vid==0xffff||vid==0)
25.continue;
26.
27.ccode=pci_config_read16(addr,PCI_CLASS_DEVICE);
28.class=ccode>>8;
29.subclass=ccode;
30.iface=pci_config_read8(addr,PCI_CLASS_PROG);
31.rev=pci_config_read8(addr,PCI_REVISION_ID);
32.
33.pci_dev=pci_find_device(class,subclass,iface,/*具体设备查找以及初始化*/
34.vid,did);
35.
36.#ifdefCONFIG_DEBUG_PCI
37.printk("%x:
%x.%x-%x:
%x-",bus,devnum,fn,
38.vid,did);
39.#endif
40.htype=pci_config_read8(addr,PCI_HEADER_TYPE);
41.if(fn==0)
42.is_multi=htype&0x80;
43.
44.if(pci_dev==NULL||pci_dev->name==NULL)
45.snprintf(config.path,sizeof(config.path),
46."%s/pci%x,%x",
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- PCIE 设备扫描的过程 设备 扫描 过程