acrn-hypervisor/misc/config_tools/board_inspector/pcieparser/extcaps.py

179 lines
5.7 KiB
Python

# Copyright (C) 2021 Intel Corporation.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import ctypes
import copy
import inspectorlib.cdata as cdata
from .header import MemoryBar32, MemoryBar64, IOBar, \
PCIE_BAR_SPACE_MASK, PCIE_BAR_MEMORY_SPACE, PCIE_BAR_IO_SPACE, \
PCIE_BAR_TYPE_MASK, PCIE_BAR_TYPE_32_BIT, PCIE_BAR_TYPE_64_BIT
class ExtendedCapability:
# Capability names from PCI Express Base Specification, mostly Table 9-23
_cap_names_ = {
0x01: "Advanced Error Reporting",
0x02: "Virtual Channel",
0x03: "Device Serial Number",
0x04: "Power Budgeting",
0x05: "Root Complex Link Declaration",
0x06: "Root Complex Internal Link Control",
0x07: "Root Complex Event Collector Endpoint Association",
0x08: "Multi-Function Virtual Channel",
0x09: "Virtual Channel",
0x0a: "RCRB Header",
0x0b: "Vendor-Specific Extended",
0x0c: "Configuration Access Correlation",
0x0d: "ACS",
0x0e: "ARI",
0x0f: "ATS",
0x10: "SR-IOV",
0x11: "MR-IOV",
0x12: "Multicast",
0x13: "PRI",
0x15: "Resizable BAR",
0x16: "DPA",
0x17: "TPH Requester",
0x18: "LTR",
0x19: "Secondary PCI Express",
0x1a: "PMUX",
0x1b: "PASID",
0x1c: "LNR",
0x1d: "DPC",
0x1e: "L1 PM Substates",
0x1f: "TPM",
0x20: "M-PCIe",
0x21: "FRS Queueing",
0x22: "Readiness Time Reporting",
0x23: "Designated Vendor-Specific",
0x24: "VF Resizable BAR",
0x25: "Data Link Feature",
0x26: "Physical Layer 16.0 GT/s",
0x27: "Lane Margining at the Receiver",
0x28: "Hierarchy ID",
0x29: "NPEM",
0x2a: "Physical Layer 32.0 GT/s",
0x2b: "Alternate Protocol",
0x2c: "SFI",
}
@property
def name(self):
if self.id in self._cap_names_.keys():
return self._cap_names_[self.id]
else:
return f"Reserved Extended ({hex(self.id)})"
@property
def next_cap_ptr(self):
# Classes inherit ExtendedCapability must implement the attribute next_cap_ptr_raw
return self.next_cap_ptr_raw & 0xffc
class ExtendedCapabilityListRegister(cdata.Struct, ExtendedCapability):
_pack_ = 1
_fields_ = [
('id', ctypes.c_uint32, 16),
('version', ctypes.c_uint32, 4),
('next_cap_ptr_raw', ctypes.c_uint32, 12),
]
# SR-IOV (0x10)
class SRIOVBase(cdata.Struct, ExtendedCapability):
_pack_ = 1
_fields_ = copy.copy(ExtendedCapabilityListRegister._fields_) + [
# SR-IOV Capabilities Register
('vf_migration_capable', ctypes.c_uint32, 1),
('ari_capable_hierarchy_preserved', ctypes.c_uint32, 1),
('vf_10_bit_tag_requester_supported', ctypes.c_uint32, 1),
('reserved1', ctypes.c_uint32, 18),
('vf_migration_interrupt_message_number', ctypes.c_uint32, 11),
# SR-IOV Control Register
('vf_enable', ctypes.c_uint32, 1),
('vf_migration_enable', ctypes.c_uint32, 1),
('vf_migration_interrupt_enable', ctypes.c_uint32, 1),
('vf_mse', ctypes.c_uint32, 1),
('ari_capable_hierarchy', ctypes.c_uint32, 1),
('vf_10_bit_tag_requester_enable', ctypes.c_uint32, 1),
('reserved2', ctypes.c_uint32, 10),
# SR-IOV Status Register
('vf_migration_status', ctypes.c_uint32, 1),
('reserved3', ctypes.c_uint32, 15),
('initial_vfs', ctypes.c_uint16),
('total_vfs', ctypes.c_uint16),
('num_vfs', ctypes.c_uint16),
('function_dependency_link', ctypes.c_uint8),
('reserved4', ctypes.c_uint8),
('first_vf_offset', ctypes.c_uint16),
('vf_stride', ctypes.c_uint16),
('reserved5', ctypes.c_uint16),
('vf_device_id', ctypes.c_uint16),
('supported_page_sizes', ctypes.c_uint32),
('system_page_size', ctypes.c_uint32),
]
def SRIOV_factory(addr):
vf_bars_list = list()
bar_base = addr + ctypes.sizeof(SRIOVBase)
bar_addr = bar_base
bar_end = bar_base + 0x18
while bar_addr < bar_end:
bar = ctypes.c_uint32.from_address(bar_addr).value
idx = int((bar_addr - bar_base) / 4)
if (bar & PCIE_BAR_SPACE_MASK) == PCIE_BAR_MEMORY_SPACE:
if (bar & PCIE_BAR_TYPE_MASK) == PCIE_BAR_TYPE_64_BIT:
vf_bars_list.append((f"vf_bar{idx}", MemoryBar64))
bar_addr += 0x8
else:
vf_bars_list.append((f"vf_bar{idx}", MemoryBar32))
bar_addr += 0x4
else:
vf_bars_list.append((f"vf_bar{idx}", IOBar))
bar_addr += 0x4
class SRIOV(cdata.Struct, ExtendedCapability):
class VFBars(cdata.Struct):
_pack_ = 1
_fields_ = vf_bars_list
def __iter__(self):
for f in self._fields_:
yield getattr(self, f[0])
_pack_ = 1
_fields_ = copy.copy(SRIOVBase._fields_) + [
('vf_bars', VFBars),
('vf_migration_state_array_offset', ctypes.c_uint32),
]
return SRIOV
def parse_sriov(buf, cap_ptr):
return SRIOV_factory(ctypes.addressof(buf) + cap_ptr).from_buffer_copy(buf, cap_ptr)
# Module API
capability_parsers = {
0x10: parse_sriov,
}
def extended_capabilities(data):
buf = ctypes.create_string_buffer(data, len(data))
cap_ptr = 0x100
acc = list()
while cap_ptr != 0:
caplist = ExtendedCapabilityListRegister.from_buffer_copy(buf, cap_ptr)
if caplist.id in capability_parsers.keys():
acc.append(capability_parsers[caplist.id](buf, cap_ptr))
elif caplist.id != 0:
acc.append(caplist)
cap_ptr = caplist.next_cap_ptr
return acc