PCIE链路拓展代码

上边只是简单介绍了链路过程,但原理是什么?代码流程是什么?
注:这里只是简单描述了链路的初始化代码流程,详细代码后续分析

初始化代码

入口过程回顾

  1. pci_acpi_scan_root // 主桥信息 struct pci_root_info struct pci_sysdata 初始化, 当前设备只有一个主桥,瓜分了SEG0 [bus 00-ff]
  2. -> acpi_pci_root_create // ECAM初始化,主桥资源初始化
  3. -> pci_create_root_bus(NULL, busnum, ops->pci_ops,sysdata, &info->resources); // 主桥PCI总线初始化
  4. -> struct pci_host_bridge *bridge = pci_alloc_host_bridge(0); // 创建pci_host_bridge结构
  5. -> pci_register_host_bridge(bridge); // 注册pci_host_bridge , 并初始化 struct pci_bus bus00
  6. -> pci_scan_child_bus(bus); // 扫描bus下所有子设备

第一轮扫描

BUS=00(因为我得主机只有一个主桥)

  1. max = bus->busn_res.start; // 这里max==0
  2. // 一条总线有32个接口,一个接口有8个子功能(先不考虑ARI),所以这里只能以8递增
  3. for (devfn = 0; devfn < 0x100; devfn += 8) // PCI总线基于某个BUS,非ARI设备可以拓展8个功能
  4. pci_scan_slot(bus, devfn);
  5. -> if (only_one_child(bus) && (devfn > 0)); // 这里肯定为0,因为 bus0parent NULL
  6. -> pci_scan_single_device(bus, devfn); // !!! 检测设备并初始化设备资源信息
  7. -> for (fn = next_fn(bus, dev, 0); ......); // 初始化 mult-func设备
  8. -> pci_scan_single_device(bus, devfn);
  9. // SR-IOV设备预留总线位置 dev->sriov->max_VF_buses sriov_initcompute_max_vf_buses(dev) 实现
  10. max += pci_iov_bus_range(bus);
  11. // 第一次扫描 bus0上边得所有桥设备, 第二次可以直接跳过
  12. if (pci_is_bridge(dev)) // 根据hdr_type字段来区分
  13. max = pci_scan_bridge(bus, dev, max, 0);
  14. // 检测桥设备总线 bus索引
  15. pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
  16. primary = buses & 0xFF;
  17. secondary = (buses >> 8) & 0xFF;
  18. subordinate = (buses >> 16) & 0xFF;
  19. // bus0下边设备得primary bus都为0 ,但primary == bus->number == 0 所以不进这个分支
  20. if (!primary && (primary != bus->number) && secondary && subordinate) {
  21. dev_warn(&dev->dev, "Primary bus is hard wired to 0\n");
  22. primary = bus->number;
  23. }
  24. // 这个是异常分支,不考虑,因此broken==0
  25. if (!pass &&
  26. (primary != bus->number || secondary <= bus->number ||
  27. secondary > subordinate)) {
  28. dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
  29. secondary, subordinate);
  30. broken = 1;
  31. }
  32. // 这里其实 软件只读得, 这个必须为0 P7.5.1.3.13 描述中 软件只读
  33. pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
  34. pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
  35. bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
  36. pci_enable_crs(dev); // 设置CRS功能
  37. // probe默认没pcibios_assign_all_busses 也不考虑card_bus
  38. if ((secondary || subordinate) && !pcibios_assign_all_busses() &&
  39. !is_cardbus && !broken) {
  40. child = pci_add_new_bus(bus, dev, secondary); // !!! 分配并创建pci_bus ************
  41. pci_scan_child_bus(child); // !!! 递归扫描子 bus得设备 *************
  42. }

桥设备扫描

  1. for (pass = 0; pass < 2; pass++)
  2. list_for_each_entry(dev, &bus->devices, bus_list) {
  3. if (pci_is_bridge(dev))
  4. max = pci_scan_bridge(bus, dev, max, pass);
  5. }
  6. ```![c231732a2445ed75495fd1c8d3b7d7d8.png](en-resource://database/779:1)