diff --git a/misc/config_tools/board_inspector/extractors/60-pci.py b/misc/config_tools/board_inspector/extractors/60-pci.py index 607c17d5b..6f97b4729 100644 --- a/misc/config_tools/board_inspector/extractors/60-pci.py +++ b/misc/config_tools/board_inspector/extractors/60-pci.py @@ -56,6 +56,13 @@ cap_parsers = { def parse_device(bus_node, device_path): device_name = os.path.basename(device_path) + cfg = parse_config_space(device_path) + + # There are cases where Linux creates device-like nodes without a file named "config", e.g. when there is a PCIe + # non-transparent bridge (NTB) on the physical platform. + if cfg is None: + return None + if device_name == "0000:00:00.0": device_node = bus_node else: @@ -66,7 +73,6 @@ def parse_device(bus_node, device_path): if device_node is None: device_node = add_child(bus_node, "device", None, address=adr) - cfg = parse_config_space(device_path) for cap in cfg.caps: # If the device is not in D0, power it on and reparse its configuration space. if cap.name == "Power Management" and cap.power_state != 0: @@ -180,7 +186,8 @@ def enum_devices(bus_node, root_path): for device_name in device_names: p = os.path.join(root_path, device_name) device_node = parse_device(bus_node, p) - enum_devices(device_node, p) + if device_node is not None: + enum_devices(device_node, p) def extract(args, board_etree): # Assume we only care about PCI devices under domain 0, as the hypervisor only uses BDF (without domain) for device diff --git a/misc/config_tools/board_inspector/pcieparser/__init__.py b/misc/config_tools/board_inspector/pcieparser/__init__.py index 11377cfed..0ec51d762 100644 --- a/misc/config_tools/board_inspector/pcieparser/__init__.py +++ b/misc/config_tools/board_inspector/pcieparser/__init__.py @@ -32,14 +32,18 @@ class PCIConfigSpace(namedtuple("PCIConfigSpace", ["header", "caps", "extcaps"]) return False def parse_config_space(path): - data = open(os.path.join(path, "config"), mode='rb').read() - hdr = header(data) - caps = capabilities(data, hdr.capability_pointer) - config_space = PCIConfigSpace(hdr, caps, []) - # While PCI Express specification requires that a PCIe endpoint must have an extended capability header at offset - # 100h of its configuration space, we do see real PCIe endpoints not meeting this requirement occasionally. Thus, - # check the length of the configuration space as well before trying to parse its extended capability list. - if config_space.has_cap("PCI Express") and len(data) >= 260: - extcaps = extended_capabilities(data) - config_space = PCIConfigSpace(hdr, caps, extcaps) - return config_space + try: + data = open(os.path.join(path, "config"), mode='rb').read() + hdr = header(data) + caps = capabilities(data, hdr.capability_pointer) + config_space = PCIConfigSpace(hdr, caps, []) + # While PCI Express specification requires that a PCIe endpoint must have an extended capability header at + # offset 100h of its configuration space, we do see real PCIe endpoints not meeting this requirement + # occasionally. Thus, check the length of the configuration space as well before trying to parse its extended + # capability list. + if config_space.has_cap("PCI Express") and len(data) >= 260: + extcaps = extended_capabilities(data) + config_space = PCIConfigSpace(hdr, caps, extcaps) + return config_space + except FileNotFoundError: + return None