pcie的pci_create_root_bus 分析

在pci_create_root_bus 中 首先会申请一个pci的root bus
    struct pci_bus *b;
    b = pci_alloc_bus(NULL);
    if (!b)
        return NULL;

    b->sysdata = sysdata;
    b->ops = ops;
    b->number = b->busn_res.start = bus;
#ifdef CONFIG_PCI_DOMAINS_GENERIC
    b->domain_nr = pci_bus_find_domain_nr(b, parent);
#endif

然后会再申请一个host bridge
    bridge = pci_alloc_host_bridge(b);
    if (!bridge)
        goto err_out;
从pci_alloc_host_bridge 中可以看到pcie的root bus是挂在host bridge下面的
static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
{
    struct pci_host_bridge *bridge;

    bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
    if (!bridge)
        return NULL;

    INIT_LIST_HEAD(&bridge->windows);
    bridge->bus = b;
    return bridge;
}
在pci_alloc_host_bridge 中先申请一个pci_host_bridge 结构体,然后将bridge->bus 指向b,这个b就是前面申请的pci root bus,因此验证了前面的说明一个rc是有host bridge -> root bus -> root port 组成的.

    bridge->dev.parent = parent;
    bridge->dev.release = pci_release_host_bridge_dev;
因为这里的pci_create_root_bus 可能是switch 设备的bus,因为要对bridge->dev.parent 赋值parent,如果是root bus的话,parent 就等于NULL。
acpi_pci_root_create->pci_create_root_bus 调用时,明显看到parent是NULL。
再调用
    dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
来设定device的name,这样就可以在/sys/devices 下面看到以pci开始的device了,
root@ubuntu:/sys/devices# ls
LNXSYSTM:00  pci0002:80  pci0006:c0  pci000c:20  pnp0      tracepoint
armv8_pmuv3  pci0004:88  pci0007:90  pci000d:30  software  virtual
breakpoint   pci0005:00  pci000a:10  platform    system

这里的domain就是pci 的segment了,具体也是在pci_create_root_bus 中通过
#ifdef CONFIG_PCI_DOMAINS_GENERIC
    b->domain_nr = pci_bus_find_domain_nr(b, parent);
#endif
来赋值的.
int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
{
    return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
                   acpi_pci_bus_find_domain_nr(bus);
}
由于我们使用的acpi因此走acpi_pci_bus_find_domain_nr
int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
{
    struct pci_config_window *cfg = bus->sysdata;
    struct acpi_device *adev = to_acpi_device(cfg->parent);
    struct acpi_pci_root *root = acpi_driver_data(adev);

    return root->segment;
}
这就比较清楚的看到在pci中所谓的domain就是pci的segment。
    error = pcibios_root_bridge_prepare(bridge);
    if (error) {
        kfree(bridge);
        goto err_out;
    }

pcibios_root_bridge_prepare 这个函数在arm64 下只有在非apci mode下才意义,如果是acpi mode相当与空函数
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
    if (!acpi_disabled) {
        struct pci_config_window *cfg = bridge->bus->sysdata;
        struct acpi_device *adev = to_acpi_device(cfg->parent);
        ACPI_COMPANION_SET(&bridge->dev, adev);
    }

    return 0;
}
注册bridge 对应的device,并给bus下面的bridage赋值.
    error = device_register(&bridge->dev);
    if (error) {
        put_device(&bridge->dev);
        goto err_out;
    }
    b->bridge = get_device(&bridge->dev);
给bus下的device 赋值和bus相同的domain
    pci_set_bus_msi_domain(b);
给root bus赋值
    b->dev.class = &pcibus_class;
    b->dev.parent = b->bridge;
    dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
    error = device_register(&b->dev);
这样就可以在/sys/bus/pci/devices 下面看到pci bus下面挂了多少个devices.
root@ubuntu:/sys/bus/pci/devices# ls
0002:80:00.0  0005:00:00.0  0007:90:00.0  000a:10:00.0  000d:30:00.0
0004:88:00.0  0006:c0:00.0  0007:91:00.0  000c:20:00.0

在开机log中可以通过下面的log找到系统中有多少个host bridge
    if (parent)
        dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
    else
        printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));

[   13.411622] PCI host bridge to bus 0002:80
[   13.411622] PCI host bridge to bus 0002:80
可以看到系统中有两个host bridge ???。
    /* Add initial resources to the bus */
    resource_list_for_each_entry_safe(window, n, resources) {
        list_move_tail(&window->node, &bridge->windows);
        res = window->res;
        offset = window->offset;
        if (res->flags & IORESOURCE_BUS)
            pci_bus_insert_busn_res(b, bus, res->end);
        else
            pci_bus_add_resource(b, res, 0);
        if (offset) {
            if (resource_type(res) == IORESOURCE_IO)
                fmt = " (bus address [%#06llx-%#06llx])";
            else
                fmt = " (bus address [%#010llx-%#010llx])";
            snprintf(bus_addr, sizeof(bus_addr), fmt,
                 (unsigned long long) (res->start - offset),
                 (unsigned long long) (res->end - offset));
        } else
            bus_addr[0] = '\0';
        dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
    }
通过这段code 给bus添加资源,可以通过在开机log 中查找dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
[   13.419865] pci_bus 0002:80: root bus resource [mem 0xa8800000-0xaffeffff window]
[   13.419865] pci_bus 0002:80: root bus resource [mem 0xa8800000-0xaffeffff window]
[   13.434941] pci_bus 0002:80: root bus resource [io  0x0000-0xffff window]
[   13.434941] pci_bus 0002:80: root bus resource [io  0x0000-0xffff window]
[   13.448617] pci_bus 0002:80: root bus resource [bus 80-87]
[   13.448617] pci_bus 0002:80: root bus resource [bus 80-87]
来得到root bus的资源,从log看bus的资源分为3类,及mem/io/bus

最后将bus的node添加到pci_root_buses 中
 list_add_tail(&b->node, &pci_root_buses);
而pci_root_buses是一个list,其定义为extern struct list_head pci_root_buses;    /* list of all known PCI buses */


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vivado是Xilinx公司推出的综合开发环境,用于实现FPGA芯片的设计。其中,Vivado PCIe cfg_fc_ph指的是PCIe Endpoint的配置。PCIe(Peripheral Component Interconnect Express,外设组件互连扩展)是一种高速的、低延迟的计算机总线,特别适用于连接外部设备和处理器之间的高速数据传输。而PCIe Endpoint是PCIe总线上接口的一种,其附加在计算机外围的设备上,可作为计算机系统的内部或外部设备使用。 PCIe Endpoint在Vivado中的配置是通过cfg_fc_ph寄存器进行的。该寄存器用于控制PCIe传输,其中,cfg表示该寄存器用于配置Endpoint设备,fc表示该寄存器用于流控方式的选择,ph表示该寄存器是PHY在物理层面生成和检测的传输的标志。具体来说,cfg_fc_ph寄存器主要包括以下配置信息: 1. PCIe Endpoint设备的ID信息,包括Vendor ID(Vid)、Device ID(Did)等; 2. 物理层面的传输控制信息,包括不同的流控方式(如成功传输Acknowledge、端到端流控等); 3. 数据传输和传输层面的配置信息,包括传输协议、数据立即传输等。 通过设置cfg_fc_ph寄存器中的这些信息,可以实现对PCIe传输的控制和配置,确保数据传输的准确性和高效性。而在Vivado中,可以通过IP核来创建和配置PCIe Endpoint设备,以实现与计算机系统的高速数据传输。同时,Vivado也提供了强大的仿真和调试功能,以支持对PCIe传输的可靠性验证和故障排查,以确保PCIe设备的稳定性和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值