config_tools: skip directories without a "config" file

Today we assume a device node under /sys/devices/pciXXXX:XX/ always contain
a `config` file which shows the configuration space of the PCI
functions. This seems not the case for, at least, Non-Transparent
Bridge (or NTB).

This patch checks the existence of the `config` file and skips PCI
functions which do not contain one.

Tracked-On: #6902
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Junjie Mao 2021-11-30 14:34:49 +08:00 committed by acrnsi-robot
parent a7e06cec2f
commit efb2860104
2 changed files with 24 additions and 13 deletions

View File

@ -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

View File

@ -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