]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
BaseTools:Add import in FvImageSection
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / PciInfo.c
1 /** @file
2
3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6 **/
7
8 #include "DmaProtection.h"
9
10 /**
11 Return the index of PCI data.
12
13 @param[in] VtdIndex The index used to identify a VTd engine.
14 @param[in] Segment The Segment used to identify a VTd engine.
15 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
16
17 @return The index of the PCI data.
18 @retval (UINTN)-1 The PCI data is not found.
19 **/
20 UINTN
21 GetPciDataIndex (
22 IN UINTN VtdIndex,
23 IN UINT16 Segment,
24 IN VTD_SOURCE_ID SourceId
25 )
26 {
27 UINTN Index;
28 VTD_SOURCE_ID *PciSourceId;
29
30 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
31 return (UINTN)-1;
32 }
33
34 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
35 PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
36 if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) &&
37 (PciSourceId->Bits.Device == SourceId.Bits.Device) &&
38 (PciSourceId->Bits.Function == SourceId.Bits.Function) ) {
39 return Index;
40 }
41 }
42
43 return (UINTN)-1;
44 }
45
46 /**
47 Register PCI device to VTd engine.
48
49 @param[in] VtdIndex The index of VTd engine.
50 @param[in] Segment The segment of the source.
51 @param[in] SourceId The SourceId of the source.
52 @param[in] DeviceType The DMAR device scope type.
53 @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.
54 FALSE: SUCCESS will be returned if the PCI device is registered.
55
56 @retval EFI_SUCCESS The PCI device is registered.
57 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.
58 @retval EFI_ALREADY_STARTED The device is already registered.
59 **/
60 EFI_STATUS
61 RegisterPciDevice (
62 IN UINTN VtdIndex,
63 IN UINT16 Segment,
64 IN VTD_SOURCE_ID SourceId,
65 IN UINT8 DeviceType,
66 IN BOOLEAN CheckExist
67 )
68 {
69 PCI_DEVICE_INFORMATION *PciDeviceInfo;
70 VTD_SOURCE_ID *PciSourceId;
71 UINTN PciDataIndex;
72 UINTN Index;
73 PCI_DEVICE_DATA *NewPciDeviceData;
74 EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId;
75
76 PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;
77
78 if (PciDeviceInfo->IncludeAllFlag) {
79 //
80 // Do not register device in other VTD Unit
81 //
82 for (Index = 0; Index < VtdIndex; Index++) {
83 PciDataIndex = GetPciDataIndex (Index, Segment, SourceId);
84 if (PciDataIndex != (UINTN)-1) {
85 DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered by Other Vtd(%d)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, Index));
86 return EFI_SUCCESS;
87 }
88 }
89 }
90
91 PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
92 if (PciDataIndex == (UINTN)-1) {
93 //
94 // Register new
95 //
96
97 if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) {
98 //
99 // Reallocate
100 //
101 NewPciDeviceData = AllocateZeroPool (sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER));
102 if (NewPciDeviceData == NULL) {
103 return EFI_OUT_OF_RESOURCES;
104 }
105 PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER;
106 if (PciDeviceInfo->PciDeviceData != NULL) {
107 CopyMem (NewPciDeviceData, PciDeviceInfo->PciDeviceData, sizeof(*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber);
108 FreePool (PciDeviceInfo->PciDeviceData);
109 }
110 PciDeviceInfo->PciDeviceData = NewPciDeviceData;
111 }
112
113 ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber);
114
115 PciSourceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciSourceId;
116 PciSourceId->Bits.Bus = SourceId.Bits.Bus;
117 PciSourceId->Bits.Device = SourceId.Bits.Device;
118 PciSourceId->Bits.Function = SourceId.Bits.Function;
119
120 DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
121
122 PciDeviceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciDeviceId;
123 if ((DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) ||
124 (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
125 PciDeviceId->VendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_VENDOR_ID_OFFSET));
126 PciDeviceId->DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_DEVICE_ID_OFFSET));
127 PciDeviceId->RevisionId = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_REVISION_ID_OFFSET));
128
129 DEBUG ((DEBUG_INFO, " (%04x:%04x:%02x", PciDeviceId->VendorId, PciDeviceId->DeviceId, PciDeviceId->RevisionId));
130
131 if (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
132 PciDeviceId->SubsystemVendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_VENDOR_ID_OFFSET));
133 PciDeviceId->SubsystemDeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_ID_OFFSET));
134 DEBUG ((DEBUG_INFO, ":%04x:%04x", PciDeviceId->SubsystemVendorId, PciDeviceId->SubsystemDeviceId));
135 }
136 DEBUG ((DEBUG_INFO, ")"));
137 }
138
139 PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType;
140
141 if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&
142 (DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
143 DEBUG ((DEBUG_INFO, " (*)"));
144 }
145 DEBUG ((DEBUG_INFO, "\n"));
146
147 PciDeviceInfo->PciDeviceDataNumber++;
148 } else {
149 if (CheckExist) {
150 DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
151 return EFI_ALREADY_STARTED;
152 }
153 }
154
155 return EFI_SUCCESS;
156 }
157
158 /**
159 The scan bus callback function to register PCI device.
160
161 @param[in] Context The context of the callback.
162 @param[in] Segment The segment of the source.
163 @param[in] Bus The bus of the source.
164 @param[in] Device The device of the source.
165 @param[in] Function The function of the source.
166
167 @retval EFI_SUCCESS The PCI device is registered.
168 **/
169 EFI_STATUS
170 EFIAPI
171 ScanBusCallbackRegisterPciDevice (
172 IN VOID *Context,
173 IN UINT16 Segment,
174 IN UINT8 Bus,
175 IN UINT8 Device,
176 IN UINT8 Function
177 )
178 {
179 VTD_SOURCE_ID SourceId;
180 UINTN VtdIndex;
181 UINT8 BaseClass;
182 UINT8 SubClass;
183 UINT8 DeviceType;
184 EFI_STATUS Status;
185
186 VtdIndex = (UINTN)Context;
187 SourceId.Bits.Bus = Bus;
188 SourceId.Bits.Device = Device;
189 SourceId.Bits.Function = Function;
190
191 DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT;
192 BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
193 if (BaseClass == PCI_CLASS_BRIDGE) {
194 SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
195 if (SubClass == PCI_CLASS_BRIDGE_P2P) {
196 DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE;
197 }
198 }
199
200 Status = RegisterPciDevice (VtdIndex, Segment, SourceId, DeviceType, FALSE);
201 return Status;
202 }
203
204 /**
205 Scan PCI bus and invoke callback function for each PCI devices under the bus.
206
207 @param[in] Context The context of the callback function.
208 @param[in] Segment The segment of the source.
209 @param[in] Bus The bus of the source.
210 @param[in] Callback The callback function in PCI scan.
211
212 @retval EFI_SUCCESS The PCI devices under the bus are scaned.
213 **/
214 EFI_STATUS
215 ScanPciBus (
216 IN VOID *Context,
217 IN UINT16 Segment,
218 IN UINT8 Bus,
219 IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback
220 )
221 {
222 UINT8 Device;
223 UINT8 Function;
224 UINT8 SecondaryBusNumber;
225 UINT8 HeaderType;
226 UINT8 BaseClass;
227 UINT8 SubClass;
228 UINT16 VendorID;
229 UINT16 DeviceID;
230 EFI_STATUS Status;
231
232 // Scan the PCI bus for devices
233 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
234 for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
235 VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
236 DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
237 if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
238 if (Function == 0) {
239 //
240 // If function 0 is not implemented, do not scan other functions.
241 //
242 break;
243 }
244 continue;
245 }
246
247 Status = Callback (Context, Segment, Bus, Device, Function);
248 if (EFI_ERROR (Status)) {
249 return Status;
250 }
251
252 BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
253 if (BaseClass == PCI_CLASS_BRIDGE) {
254 SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
255 if (SubClass == PCI_CLASS_BRIDGE_P2P) {
256 SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
257 DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));
258 if (SecondaryBusNumber != 0) {
259 Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);
260 if (EFI_ERROR (Status)) {
261 return Status;
262 }
263 }
264 }
265 }
266
267 if (Function == 0) {
268 HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
269 if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
270 //
271 // It is not a multi-function device, do not scan other functions.
272 //
273 break;
274 }
275 }
276 }
277 }
278
279 return EFI_SUCCESS;
280 }
281
282 /**
283 Dump the PCI device information managed by this VTd engine.
284
285 @param[in] VtdIndex The index of VTd engine.
286 **/
287 VOID
288 DumpPciDeviceInfo (
289 IN UINTN VtdIndex
290 )
291 {
292 UINTN Index;
293
294 DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
295 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,
296 mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag
297 ));
298 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
299 DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",
300 mVtdUnitInformation[VtdIndex].Segment,
301 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
302 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
303 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function
304 ));
305 }
306 }
307
308 /**
309 Find the VTd index by the Segment and SourceId.
310
311 @param[in] Segment The segment of the source.
312 @param[in] SourceId The SourceId of the source.
313 @param[out] ExtContextEntry The ExtContextEntry of the source.
314 @param[out] ContextEntry The ContextEntry of the source.
315
316 @return The index of the VTd engine.
317 @retval (UINTN)-1 The VTd engine is not found.
318 **/
319 UINTN
320 FindVtdIndexByPciDevice (
321 IN UINT16 Segment,
322 IN VTD_SOURCE_ID SourceId,
323 OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,
324 OUT VTD_CONTEXT_ENTRY **ContextEntry
325 )
326 {
327 UINTN VtdIndex;
328 VTD_ROOT_ENTRY *RootEntry;
329 VTD_CONTEXT_ENTRY *ContextEntryTable;
330 VTD_CONTEXT_ENTRY *ThisContextEntry;
331 VTD_EXT_ROOT_ENTRY *ExtRootEntry;
332 VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;
333 VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;
334 UINTN PciDataIndex;
335
336 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
337 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
338 continue;
339 }
340
341 PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
342 if (PciDataIndex == (UINTN)-1) {
343 continue;
344 }
345
346 // DEBUG ((DEBUG_INFO,"FindVtdIndex(0x%x) for S%04x B%02x D%02x F%02x\n", VtdIndex, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
347
348 if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {
349 ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
350 ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;
351 ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];
352 if (ThisExtContextEntry->Bits.AddressWidth == 0) {
353 continue;
354 }
355 *ExtContextEntry = ThisExtContextEntry;
356 *ContextEntry = NULL;
357 } else {
358 RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
359 ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;
360 ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];
361 if (ThisContextEntry->Bits.AddressWidth == 0) {
362 continue;
363 }
364 *ExtContextEntry = NULL;
365 *ContextEntry = ThisContextEntry;
366 }
367
368 return VtdIndex;
369 }
370
371 return (UINTN)-1;
372 }
373