ACPI相关(3)- PCI枚举

一、pci主桥acpi框架

1、匹配DSDT中(PCI0)调用.attach

kernel调用acpi_init执行,
acpi_init->acpi_scan_init->acpi_bus_scan->acpi_bus_check_add->acpi_scan_init_hotplug->acpi_scan_match_handler->acpi_scan_handler_matching
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
                       const char *idstr,
                       const struct acpi_device_id **matchid)
{
    ...
    for (devid = handler->ids; devid->id[0]; devid++)
        if (!strcmp((char *)devid->id, idstr)) {
            if (matchid)
                *matchid = devid;
            return true;
  ...
}
这个函数会比较biso是否传递PNP0A03 字符串,而这个字符串代表的是pcie的root。

如果bios传递了这个字符串(Name (_CID, EisaId ("PNP0A03")在DSDT中有描述)。则
int acpi_bus_scan(acpi_handle handle)
{
  ...
    if (device) {
        acpi_bus_attach(device);
        return 0;
    }
    ...
}
acpi_bus_scan 中调用acpi_bus_attach->acpi_scan_attach_handler,主要代码:
static int acpi_scan_attach_handler(struct acpi_device *device)
{
   ...
            ret = handler->attach(device, devid);
  ...
    return ret;
}
这个函数最终调用handler->attach,对于pcie root则acpi_pci_root_add
这个函数中就会扫描主桥。下面是主桥设备注册的数据结构。

static struct acpi_scan_handler pci_root_handler = {

        .ids = root_device_ids,

        .attach = acpi_pci_root_add,

        .detach = acpi_pci_root_remove,

        .hotplug = {

                .enabled = true,

                .scan_dependent = acpi_pci_root_scan_dependent,

        },

}

2、acpi_pci_root_init流程

(1)acpi_hest_init()

在acpi下对HEST表的支持,这个表可以包含硬件错误源。

(2)pci_acpi_crs_quirks

X86下实现为解析获取dmi信息,当匹配某些信息(板卡名称、厂商、固件版本号等)后,确定是否使用DSDT中_CRS下的资源以及是否忽略_SEG方法(returns a device’s PCI Segment Group number)。前提是使用UEFI作为固件并且支持acpi。

(3)注册struct acpi_scan_handler

acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root");

将struct acpi_scan_handler添加到&acpi_scan_handlers_list链表中。并使能为热插拔设备。当在DSDT中找到 Name (_CID, EisaId ("PNP0A03") 描述,系统调用.attach函数,即acpi_pci_root_add函数。(acpi框架已实现)

3、acpi_pci_root_add流程

(1)解析DSDT方法

检测_SEG控制方法,如不存在,则假定所有pci总线段位段组0. 检测_CRS方法,try_get_root_bridge_busnr 获取_CRS资源列表,这里主要获取下游bus号范围。

_CRS中包含总线范围资源

评估_CBA,获取pci主桥的配置基地址。

评估_BBN(base bus number),来获取总线号。如找到为[_BBN-0xFF] ,否则默认为 [0-0xFF]。

 

(2)negotiate_os_control

判断主桥设备是否支持aspm、run_wake、以及热插拔事件。

(3)扫描主桥下设备

pci_acpi_scan_root(与架构相关,须在mips下实现)。(必须在尝试绑定根设备之前执行此操作,因为在进行此调用之前不会创建PCI名称空间(因此根桥的pci_dev不存在)。

X86架构下pci_acpi_scan_root函数的分析:

首先检测系统对pci组段的支持情况。

acpi的_PXM 表示device所在的numa id,这里通过评估_PXM方法获取node号。

为结构struct pci_root_info申请空间,填充struct pci_sysdata sd结构成员

检测pci主桥总线的0000:00设备。由于pci总线还没有初始化,在这里显然找不到。

这里主要分析未创建。首先将root资源插入资源列表。调用probe_pci_root_info函数。在这个函数中,调用acpi_dev_get_resources函数。通过acpi_walk_resources评估_CRS控制方法。获取_CRS中描述的资源信息。

这里从使用crs获取信息和不使用两方面分析:

  1. 使用_CRS中获取的资源

在add_resources中、调用validate_resources确认获取到的IO/MEM资源是正确的。遍历_CRS中的资源,将IO和MEM资源分别插入iomem_resource和ioport_resource中,如出现冲突,则释放要插入的资源。最后将_CRS中的资源插入资源列表。

  1. 不使用_CRS中获取的资源

释放从_CRS获取到的资源。调用x86_pci_root_bus_resources函数。在这个函数中,遍历pci_root_infos,查找bus为0的总线信息。找不到则使用默认资源设置。否则资源列表,将IO和MEM资源分别插入iomem_resource和ioport_resource中。

接下来判断是否支持MMCFG。不支持则执行pci扫描的整个流程。创建根节点。扫描主桥下的所有pci设备。

二、pci在acpi下枚举和普通枚举对比

1、ACPI热插拔扫描
|->acpi_bus_scan(ACPI_ROOT_OBJECT)
      |->acpi_bus_scan@drivers/acpi/scan.c

acpi_bus_check_add检测root
                  |->acpi_walk_namespace@drivers/acpi/acpica/nsxfeval.c
                          |->acpi_ns_walk_namespace@drivers/acpi/acpica/nswalk.c
                  |->acpi_bus_device_attach(即post_order_visit)
                          |->acpi_scan_attach_handler
                                |->acpi_scan_match_handler
                                      |->handler->attach(即acpi_pci_root_add) 
                                           |->pci_acpi_scan_root@arch/x86/pci/probe.c
                                                   |->probe_pci_root_info
                                                   |->pci_scan_child_bus@drivers/pci/probe.c
                                                      |->pci_scan_slot
  

2. 传统扫描
subsys_initcall(pcibios_init)@arch/mips/pci/pci.c
  |->pcibios_init
     |->pcibios_scanbus@arch/mips/pci/pci.c
        |->pci_scan_root_bus
             |->pci_scan_root_bus@drivers/pci/probe.c
                 |->pci_create_root_bus
                     |->pci_scan_child_bus
                         |->pci_scan_slot

 

  • MIPS下支持代码
  1. ACPI模式pci枚举

(1)获取域、node号

目前平台忽略pci段组的概念,在3a+7a环境下,默认pci段组为0.在acpi中,段组的概念通过seg对象来获取。

acpi模式下,可通过_PXM来获取node的概念。

        pxm = acpi_get_pxm(handle);

 

        return acpi_map_pxm_to_node(pxm);

(2)适配acpi新增字段

mips架构下对acpi没有支持,所以在pci控制器结构中添加了acpi_device的概念。

struct pci_controller {

      ...

#ifdef CONFIG_ACPI

        struct acpi_device *companion;

#endif

};

使用companion成员来记录acpi_device结构成员。传递给pci_create_root_bus接口来创建0号总线及pci主桥。

(3)资源获取流程

调用接口acpi_dev_get_resources获取主桥设备的_CRS对象下描述的io/mem资源。将获取到的资源插入到资源列表中,以便后续传递给pci_create_root_bus来创建0号总线及pci主桥。

获取到的资源需要进行资源检查:1、是否获取到io/mem资源(DSDT中是否有描述)2、获取到的io/mem资源是否合理。

如果没有在DSDT中获取到资源描述或检测到获取到的资源不符合逻辑,则使用默认资源。

2、主桥初始化添加代码

1、pci_domain_nr函数返回bus->sysdata(controller)的index数据。

2、pcibios_root_bridge_prepare为主桥设备设置固件节点(struct fwnode_handle *fwnode)。

3、pcibios_add_bus(b)

->acpi_pci_slot_enumerate --- 遍历名称空间,检查每个名称空间中存在的节点句柄是否有相关联的插槽,如果有,则创建PCI插槽(在/sys/bus/pci/slots/ 目录中显示)。(物理插槽与pci总线对应关系)

->acpiphp_enumerate_slots --- 为给定的总线枚举pci插槽

三、扫描过程问题

(1)parent NULL...return ------------

[    0.265625] pci 0000:00:16.0: [0014:7a0b] type 00 class 0x088000

[    0.265625] pci 0000:00:16.0: reg 0x10: [mem 0x4b1a7000-0x4b1a7fff 64bit]

[    0.265625] pci 0000:00:16.0: reg 0x18: [mem 0x4a000000-0x4affffff 64bit]

[    0.265625] pci 0000:00:17.0: [0014:7a0c] type 00 class 0x060100

问题原因:pci主桥下设备在DSDT中没有描述_ADR对象时,则在扫描过程会出现Unable to get handle打印。属正常现象。

(2)调用acpi_find_child_device失败

问题问题原因,由于在pci扫描过程没有为device->device_rh->fwnode赋值,导致在使用ACPI_COMPANION宏获取acpi dev时获取总为NULL。后续在创建主桥过程,在struct pci_controller中添加acpi_device字段,并将deivce赋值。解决此问题,在pci扫描过程会检测DSDT中_ADD的描述,如发现,则会调用这个函数来查找设备。

(3)PCI枚举问题

1)卡死问题

。。。。
[ 0.148437] CPU#1 finished, CP0_ST=d400cce1
[ 0.152343] Enable clock for CPU#2
[ 0.152343] Booting CPU#2...
[ 0.152343] Primary instruction cache 64kB, VIPT, 4-way, linesize 64 bytes.
[ 0.152343] Primary data cache 64kB, 4-way, VIPT, no aliases, linesize 64 bytes

2)bar空间为NULL

以上问题都是在移植过程,由于x86和mips架构代码及数据结构不同导致。

调用pci标准接口pci_create_root_bus来创建0号总线及主桥设备时,传递的参数void *sysdata,mips下需将pci_controller结构传递,且在调用pci_bus_assign_resources函数时会使用pci_controller的成员io_resource以及mem_resource成员,所以必须对其赋值。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值