]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
IntelSiliconPkg/IntelVTdDxe: Move to feature dir.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / PciInfo.c
1 /** @file
2
3 Copyright (c) 2017, 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 UINT32 MaxFunction;
235 UINT16 VendorID;
236 UINT16 DeviceID;
237 EFI_STATUS Status;
238
239 // Scan the PCI bus for devices
240 for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {
241 HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
242 MaxFunction = PCI_MAX_FUNC + 1;
243 if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
244 MaxFunction = 1;
245 }
246 for (Function = 0; Function < MaxFunction; Function++) {
247 VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
248 DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
249 if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
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 }
274
275 return EFI_SUCCESS;
276 }
277
278 /**
279 Dump the PCI device information managed by this VTd engine.
280
281 @param[in] VtdIndex The index of VTd engine.
282 **/
283 VOID
284 DumpPciDeviceInfo (
285 IN UINTN VtdIndex
286 )
287 {
288 UINTN Index;
289
290 DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
291 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,
292 mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag
293 ));
294 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
295 DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",
296 mVtdUnitInformation[VtdIndex].Segment,
297 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
298 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
299 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function
300 ));
301 }
302 }
303
304 /**
305 Find the VTd index by the Segment and SourceId.
306
307 @param[in] Segment The segment of the source.
308 @param[in] SourceId The SourceId of the source.
309 @param[out] ExtContextEntry The ExtContextEntry of the source.
310 @param[out] ContextEntry The ContextEntry of the source.
311
312 @return The index of the VTd engine.
313 @retval (UINTN)-1 The VTd engine is not found.
314 **/
315 UINTN
316 FindVtdIndexByPciDevice (
317 IN UINT16 Segment,
318 IN VTD_SOURCE_ID SourceId,
319 OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,
320 OUT VTD_CONTEXT_ENTRY **ContextEntry
321 )
322 {
323 UINTN VtdIndex;
324 VTD_ROOT_ENTRY *RootEntry;
325 VTD_CONTEXT_ENTRY *ContextEntryTable;
326 VTD_CONTEXT_ENTRY *ThisContextEntry;
327 VTD_EXT_ROOT_ENTRY *ExtRootEntry;
328 VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;
329 VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;
330 UINTN PciDataIndex;
331
332 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
333 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
334 continue;
335 }
336
337 PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
338 if (PciDataIndex == (UINTN)-1) {
339 continue;
340 }
341
342 // 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));
343
344 if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {
345 ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
346 ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;
347 ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];
348 if (ThisExtContextEntry->Bits.AddressWidth == 0) {
349 continue;
350 }
351 *ExtContextEntry = ThisExtContextEntry;
352 *ContextEntry = NULL;
353 } else {
354 RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
355 ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;
356 ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];
357 if (ThisContextEntry->Bits.AddressWidth == 0) {
358 continue;
359 }
360 *ExtContextEntry = NULL;
361 *ContextEntry = ThisContextEntry;
362 }
363
364 return VtdIndex;
365 }
366
367 return (UINTN)-1;
368 }
369