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==0if (!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);}```
