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