PCIE链路拓展代码
上边只是简单介绍了链路过程,但原理是什么?代码流程是什么?
注:这里只是简单描述了链路的初始化代码流程,详细代码后续分析
初始化代码
入口过程回顾
pci_acpi_scan_root // 主桥信息 struct pci_root_info 和 struct pci_sysdata 初始化, 当前设备只有一个主桥,瓜分了SEG0的 [bus 00-ff]
-> acpi_pci_root_create // ECAM初始化,主桥资源初始化
-> pci_create_root_bus(NULL, busnum, ops->pci_ops,sysdata, &info->resources); // 主桥PCI总线初始化
-> struct pci_host_bridge *bridge = pci_alloc_host_bridge(0); // 创建pci_host_bridge结构
-> pci_register_host_bridge(bridge); // 注册pci_host_bridge , 并初始化 struct pci_bus bus00
-> pci_scan_child_bus(bus); // 扫描bus下所有子设备
第一轮扫描
BUS=00(因为我得主机只有一个主桥)
max = bus->busn_res.start; // 这里max==0
// 一条总线有32个接口,一个接口有8个子功能(先不考虑ARI),所以这里只能以8递增
for (devfn = 0; devfn < 0x100; devfn += 8) // PCI总线基于某个BUS,非ARI设备可以拓展8个功能
pci_scan_slot(bus, devfn);
-> if (only_one_child(bus) && (devfn > 0)); // 这里肯定为0,因为 bus0得parent 为NULL
-> pci_scan_single_device(bus, devfn); // !!! 检测设备并初始化设备资源信息
-> for (fn = next_fn(bus, dev, 0); ......); // 初始化 mult-func设备
-> pci_scan_single_device(bus, devfn);
// 给SR-IOV设备预留总线位置 dev->sriov->max_VF_buses 在 sriov_init中compute_max_vf_buses(dev) 实现
max += pci_iov_bus_range(bus);
// 第一次扫描 bus0上边得所有桥设备, 第二次可以直接跳过
if (pci_is_bridge(dev)) // 根据hdr_type字段来区分
max = pci_scan_bridge(bus, dev, max, 0);
// 检测桥设备总线 bus索引
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
primary = buses & 0xFF;
secondary = (buses >> 8) & 0xFF;
subordinate = (buses >> 16) & 0xFF;
// bus0下边设备得primary bus都为0 ,但primary == bus->number == 0 所以不进这个分支
if (!primary && (primary != bus->number) && secondary && subordinate) {
dev_warn(&dev->dev, "Primary bus is hard wired to 0\n");
primary = bus->number;
}
// 这个是异常分支,不考虑,因此broken==0
if (!pass &&
(primary != bus->number || secondary <= bus->number ||
secondary > subordinate)) {
dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
secondary, subordinate);
broken = 1;
}
// 这里其实 软件只读得, 这个必须为0, P7.5.1.3.13 描述中 软件只读
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
pci_enable_crs(dev); // 设置CRS功能
// probe默认没pcibios_assign_all_busses, 也不考虑card_bus,
if ((secondary || subordinate) && !pcibios_assign_all_busses() &&
!is_cardbus && !broken) {
child = pci_add_new_bus(bus, dev, secondary); // !!! 分配并创建pci_bus ************
pci_scan_child_bus(child); // !!! 递归扫描子 bus得设备 *************
}
桥设备扫描
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (pci_is_bridge(dev))
max = pci_scan_bridge(bus, dev, max, pass);
}
```![c231732a2445ed75495fd1c8d3b7d7d8.png](en-resource://database/779:1)