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