1# Copyright (C) 2021-2022 Intel Corporation. 2# 3# SPDX-License-Identifier: BSD-3-Clause 4# 5 6import ctypes 7import copy 8import inspectorlib.cdata as cdata 9from .header import MemoryBar32, MemoryBar64, IOBar, \ 10 PCIE_BAR_SPACE_MASK, PCIE_BAR_MEMORY_SPACE, PCIE_BAR_IO_SPACE, \ 11 PCIE_BAR_TYPE_MASK, PCIE_BAR_TYPE_32_BIT, PCIE_BAR_TYPE_64_BIT 12 13class ExtendedCapability: 14 # Capability names from PCI Express Base Specification, mostly Table 9-23 15 _cap_names_ = { 16 0x01: "Advanced Error Reporting", 17 0x02: "Virtual Channel", 18 0x03: "Device Serial Number", 19 0x04: "Power Budgeting", 20 0x05: "Root Complex Link Declaration", 21 0x06: "Root Complex Internal Link Control", 22 0x07: "Root Complex Event Collector Endpoint Association", 23 0x08: "Multi-Function Virtual Channel", 24 0x09: "Virtual Channel", 25 0x0a: "RCRB Header", 26 0x0b: "Vendor-Specific Extended", 27 0x0c: "Configuration Access Correlation", 28 0x0d: "ACS", 29 0x0e: "ARI", 30 0x0f: "ATS", 31 0x10: "SR-IOV", 32 0x11: "MR-IOV", 33 0x12: "Multicast", 34 0x13: "PRI", 35 0x15: "Resizable BAR", 36 0x16: "DPA", 37 0x17: "TPH Requester", 38 0x18: "LTR", 39 0x19: "Secondary PCI Express", 40 0x1a: "PMUX", 41 0x1b: "PASID", 42 0x1c: "LNR", 43 0x1d: "DPC", 44 0x1e: "L1 PM Substates", 45 0x1f: "PTM", 46 0x20: "M-PCIe", 47 0x21: "FRS Queueing", 48 0x22: "Readiness Time Reporting", 49 0x23: "Designated Vendor-Specific", 50 0x24: "VF Resizable BAR", 51 0x25: "Data Link Feature", 52 0x26: "Physical Layer 16.0 GT/s", 53 0x27: "Lane Margining at the Receiver", 54 0x28: "Hierarchy ID", 55 0x29: "NPEM", 56 0x2a: "Physical Layer 32.0 GT/s", 57 0x2b: "Alternate Protocol", 58 0x2c: "SFI", 59 } 60 61 @property 62 def name(self): 63 if self.id in self._cap_names_.keys(): 64 return self._cap_names_[self.id] 65 else: 66 return f"Reserved Extended ({hex(self.id)})" 67 68 @property 69 def next_cap_ptr(self): 70 # Classes inherit ExtendedCapability must implement the attribute next_cap_ptr_raw 71 return self.next_cap_ptr_raw & 0xffc 72 73class ExtendedCapabilityListRegister(cdata.Struct, ExtendedCapability): 74 _pack_ = 1 75 _fields_ = [ 76 ('id', ctypes.c_uint32, 16), 77 ('version', ctypes.c_uint32, 4), 78 ('next_cap_ptr_raw', ctypes.c_uint32, 12), 79 ] 80 81# SR-IOV (0x10) 82 83class SRIOVBase(cdata.Struct, ExtendedCapability): 84 _pack_ = 1 85 _fields_ = copy.copy(ExtendedCapabilityListRegister._fields_) + [ 86 # SR-IOV Capabilities Register 87 ('vf_migration_capable', ctypes.c_uint32, 1), 88 ('ari_capable_hierarchy_preserved', ctypes.c_uint32, 1), 89 ('vf_10_bit_tag_requester_supported', ctypes.c_uint32, 1), 90 ('reserved1', ctypes.c_uint32, 18), 91 ('vf_migration_interrupt_message_number', ctypes.c_uint32, 11), 92 93 # SR-IOV Control Register 94 ('vf_enable', ctypes.c_uint32, 1), 95 ('vf_migration_enable', ctypes.c_uint32, 1), 96 ('vf_migration_interrupt_enable', ctypes.c_uint32, 1), 97 ('vf_mse', ctypes.c_uint32, 1), 98 ('ari_capable_hierarchy', ctypes.c_uint32, 1), 99 ('vf_10_bit_tag_requester_enable', ctypes.c_uint32, 1), 100 ('reserved2', ctypes.c_uint32, 10), 101 102 # SR-IOV Status Register 103 ('vf_migration_status', ctypes.c_uint32, 1), 104 ('reserved3', ctypes.c_uint32, 15), 105 106 ('initial_vfs', ctypes.c_uint16), 107 ('total_vfs', ctypes.c_uint16), 108 ('num_vfs', ctypes.c_uint16), 109 ('function_dependency_link', ctypes.c_uint8), 110 ('reserved4', ctypes.c_uint8), 111 ('first_vf_offset', ctypes.c_uint16), 112 ('vf_stride', ctypes.c_uint16), 113 ('reserved5', ctypes.c_uint16), 114 ('vf_device_id', ctypes.c_uint16), 115 116 ('supported_page_sizes', ctypes.c_uint32), 117 ('system_page_size', ctypes.c_uint32), 118 ] 119 120def SRIOV_factory(addr): 121 vf_bars_list = list() 122 bar_base = addr + ctypes.sizeof(SRIOVBase) 123 bar_addr = bar_base 124 bar_end = bar_base + 0x18 125 while bar_addr < bar_end: 126 bar = ctypes.c_uint32.from_address(bar_addr).value 127 idx = int((bar_addr - bar_base) / 4) 128 if (bar & PCIE_BAR_SPACE_MASK) == PCIE_BAR_MEMORY_SPACE: 129 if (bar & PCIE_BAR_TYPE_MASK) == PCIE_BAR_TYPE_64_BIT: 130 vf_bars_list.append((f"vf_bar{idx}", MemoryBar64)) 131 bar_addr += 0x8 132 else: 133 vf_bars_list.append((f"vf_bar{idx}", MemoryBar32)) 134 bar_addr += 0x4 135 else: 136 vf_bars_list.append((f"vf_bar{idx}", IOBar)) 137 bar_addr += 0x4 138 139 class SRIOV(cdata.Struct, ExtendedCapability): 140 class VFBars(cdata.Struct): 141 _pack_ = 1 142 _fields_ = vf_bars_list 143 144 def __iter__(self): 145 for f in self._fields_: 146 yield getattr(self, f[0]) 147 148 _pack_ = 1 149 _fields_ = copy.copy(SRIOVBase._fields_) + [ 150 ('vf_bars', VFBars), 151 ('vf_migration_state_array_offset', ctypes.c_uint32), 152 ] 153 154 return SRIOV 155 156def parse_sriov(buf, cap_ptr): 157 return SRIOV_factory(ctypes.addressof(buf) + cap_ptr).from_buffer_copy(buf, cap_ptr) 158 159# Module API 160 161capability_parsers = { 162 0x10: parse_sriov, 163} 164 165def extended_capabilities(data): 166 buf = ctypes.create_string_buffer(data, len(data)) 167 cap_ptr = 0x100 168 169 acc = list() 170 while cap_ptr != 0: 171 caplist = ExtendedCapabilityListRegister.from_buffer_copy(buf, cap_ptr) 172 if caplist.id in capability_parsers.keys(): 173 acc.append(capability_parsers[caplist.id](buf, cap_ptr)) 174 elif caplist.id != 0: 175 acc.append(caplist) 176 cap_ptr = caplist.next_cap_ptr 177 178 return acc 179