首页 理论教育PCI设备的BAR空间检查方法

PCI设备的BAR空间检查方法

【摘要】:最后这段程序使用acpi_pci_irq_enable函数为当前PCI总线树上的所有PCI设备分配irq号。pcibios_init→pcibios_resource_survey函数将检查当前处理器系统的所有PCI设备的BAR空间,该函数并不会操作PCI设备的BAR寄存器,而只是检查当前处理器系统中所有PCI设备的pci_dev→resource参数是否合法。源代码14-36 pci_find_parent_resource函数pci_find_parent_resource首先对PCI桥管理的地址空间进行检查。pcibios_init函数主要操作Linux系统中的数据结构,并没有对PCI设备的BAR寄存器进行读写操作。

当acpi_pci_link_init函数执行完毕后,Linux PCI开始执行pci_subsys_init函数。在第14.1.3节曾简要介绍了该函数的实现,该函数如源代码14-9所示。

当一个处理器系统使能了ACPI机制,pci_subsys_init函数的执行路径将会发生变化。该函数将首先执行pci_acpi_init函数,并跳过pci_legacy_init和pcibios_irq_init函数之后,执行pcibios_init函数。pci_acpi_init函数的实现较为简单,其源代码在./arch/x86/pci/acpi.c文件中,如源代码14-33所示。

源代码14-33 pci_acpi_init函数

978-7-111-29822-9-Part03-48.jpg

该函数首先调用acpi_irq_penalty_init函数更新acpi_irq_penalty表,该函数与Linux系统使用的IRQ Balance技术相关,对此感兴趣的读者可以从http://www.irqbalance.org网站获得更多的信息,本书并不关心这部分内容。

这段程序将pcibios_scanned参数置1,并将pcibios_enable_irq和pcibios_disable_irq参数初始化为acpi_pci_irq_enable和acpi_pci_irq_disable。这也是Linux系统使能ACPI机制后,Linux PCI并不执行pci_legacy_init[20]和p cibios_irq_init[21]函数的原因。最后这段程序使用acpi_pci_irq_enable函数为当前PCI总线树上的所有PCI设备分配irq号。

如果当前处理器系统使能了ACPI机制,pci_acpi_init函数执行后,pci_subsys_init函数将执行pcibios_init函数。pcibios_init→pcibios_resource_survey函数将检查当前处理器系统的所有PCI设备的BAR空间,该函数并不会操作PCI设备的BAR寄存器,而只是检查当前处理器系统中所有PCI设备的pci_dev→resource参数是否合法。

由第14.3.2节所示,pci_scan_slot函数己经将pci_dev→resource参数进行基本的初始化工作,但是对于不同的处理器系统,resource→start参数的值并不一定有效。

pcibios_resource_survey函数在./arch/x86/pci/i386.c文件中,如源代码14-34所示。

源代码14-34 pcibios_resource_survey函数

978-7-111-29822-9-Part03-49.jpg

在Linux x86中,所有PCI总线树的根节点使用一个双向链表连接在一起,pci_root_buses指向这个链表的起始地址。pcibios_allocate_bus_resources函数使用DFS算法检查并分配PCI总线树中的所有PCI桥使用的系统资源,函数的源代码在./arch/x86/pci/i386.c文件中,如源代码14-35所示。

源代码14-35 pcibios_allocate_bus_resources函数(www.chuimin.cn)

978-7-111-29822-9-Part03-50.jpg

978-7-111-29822-9-Part03-51.jpg

pcibios_allocate_bus_resources函数首先遍历链表pci_root_buses中的所有pci_bus结构,之后调用pci_claim_resource→pci_find_parent_resource函数对pci_bus结构进行检查。pci_find_parent_resource函数在./driver/pci/pci.c文件中,如源代码14-36所示,该函数成功返回时,将获得当前PCI桥的上游PCI桥使用的resource参数。

源代码14-36 pci_find_parent_resource函数

978-7-111-29822-9-Part03-52.jpg

pci_find_parent_resource首先对PCI桥管理的地址空间进行检查。如图3-2所示,每一个PCI桥都管理一段PCI总线地址空间,而且这段地址空间必须隶属于上游PCI桥管理的地址空间,其中PCI桥2管理的地址空间隶属于PCI桥1,而PCI桥1管理的地址空间隶属于HOST主桥,而且这些地址空间的类型需要一致。

之后这段代码检查上下游PCI桥的预读设置位,PCI总线规定下游设备“不可预读空间”不能使用PCI桥的“可预读空间”;而下游设备“可预读空间”可以使用PCI桥的“不可预读空间”和“可预读空间”,下游设备的“可预读空间”优先使用PCI桥的“可预读空间”。

当完成这些检查后pcibios_allocate_bus_resources→request_resource函数将从上游PCI桥管理的地址空间中为当前PCI桥分配地址空间,如果该函数返回失败,则将r→flags参数置0,标记资源没有被正确分配,这种情况可能是因为BIOS的bug,也可能因为其他原因。之后pcibios_allocate_bus_resources函数将递归调用pcibios_allocate_bus_resources函数遍历其下游的PCI总线树。

我们再次回到pcibios_resource_survey函数,发现该函数分别使用两个不同的入口参数0和1调用了pcibios_allocate_resources函数。当入口参数为0时,pcibios_allocate_resources函数为“在BIOS中已经启用了PCI设备”优先分配资源;当入口参数为1时,该函数为其他PCI设备分配资源。

该函数的实现较为简单,其主要过程依然是调用pci_find_parent_resource函数获得上游PCI桥管理的资源,并使用request_resource函数为当前PCI设备分配地址空间。值得注意的是,当入口参数为0时,pcibios_resource_survey函数将暂时禁止PCI设备的ROM空间,ROM空间的初始化将在下文介绍。

pcibios_init函数主要操作Linux系统中的数据结构,并没有对PCI设备的BAR寄存器进行读写操作。在x86处理器系统中,BIOS会枚举PCI总线树,并初始化PCI设备的BAR寄存器;但是在其他处理器系统中,Firmware可能并没有做出这些操作,为此Linux系统将继续遍历PCI总线树,并初始化这些PCI设备的BAR寄存器。