]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
IntelSiliconPkg IntelVTdDxe: Optimize when func 0 is not implemented
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / PciInfo.c
CommitLineData
c049fc99
JY
1/** @file\r
2\r
e69d7e99 3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
c049fc99
JY
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
e69d7e99
SZ
250 if (Function == 0) {\r
251 //\r
252 // If function 0 is not implemented, do not scan other functions.\r
253 //\r
254 break;\r
255 }\r
c049fc99
JY
256 continue;\r
257 }\r
258\r
f77d35c7 259 Status = Callback (Context, Segment, Bus, Device, Function);\r
c049fc99
JY
260 if (EFI_ERROR (Status)) {\r
261 return Status;\r
262 }\r
263\r
264 BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));\r
265 if (BaseClass == PCI_CLASS_BRIDGE) {\r
266 SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));\r
267 if (SubClass == PCI_CLASS_BRIDGE_P2P) {\r
268 SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
269 DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));\r
270 if (SecondaryBusNumber != 0) {\r
f77d35c7 271 Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);\r
c049fc99
JY
272 if (EFI_ERROR (Status)) {\r
273 return Status;\r
274 }\r
275 }\r
276 }\r
277 }\r
278 }\r
279 }\r
280\r
281 return EFI_SUCCESS;\r
282}\r
283\r
284/**\r
285 Dump the PCI device information managed by this VTd engine.\r
286\r
287 @param[in] VtdIndex The index of VTd engine.\r
288**/\r
289VOID\r
290DumpPciDeviceInfo (\r
291 IN UINTN VtdIndex\r
292 )\r
293{\r
294 UINTN Index;\r
295\r
296 DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",\r
f77d35c7 297 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,\r
c049fc99
JY
298 mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag\r
299 ));\r
f77d35c7 300 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {\r
c049fc99
JY
301 DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",\r
302 mVtdUnitInformation[VtdIndex].Segment,\r
f77d35c7
JY
303 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,\r
304 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,\r
305 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function\r
c049fc99
JY
306 ));\r
307 }\r
308}\r
309\r
310/**\r
311 Find the VTd index by the Segment and SourceId.\r
312\r
313 @param[in] Segment The segment of the source.\r
314 @param[in] SourceId The SourceId of the source.\r
315 @param[out] ExtContextEntry The ExtContextEntry of the source.\r
316 @param[out] ContextEntry The ContextEntry of the source.\r
317\r
f77d35c7
JY
318 @return The index of the VTd engine.\r
319 @retval (UINTN)-1 The VTd engine is not found.\r
c049fc99
JY
320**/\r
321UINTN\r
322FindVtdIndexByPciDevice (\r
323 IN UINT16 Segment,\r
324 IN VTD_SOURCE_ID SourceId,\r
325 OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,\r
326 OUT VTD_CONTEXT_ENTRY **ContextEntry\r
327 )\r
328{\r
329 UINTN VtdIndex;\r
330 VTD_ROOT_ENTRY *RootEntry;\r
331 VTD_CONTEXT_ENTRY *ContextEntryTable;\r
332 VTD_CONTEXT_ENTRY *ThisContextEntry;\r
333 VTD_EXT_ROOT_ENTRY *ExtRootEntry;\r
334 VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;\r
335 VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;\r
f77d35c7 336 UINTN PciDataIndex;\r
c049fc99
JY
337\r
338 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
339 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
340 continue;\r
341 }\r
342\r
f77d35c7
JY
343 PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);\r
344 if (PciDataIndex == (UINTN)-1) {\r
c049fc99
JY
345 continue;\r
346 }\r
347\r
348// 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
349\r
350 if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {\r
351 ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];\r
76c6f69c 352 ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;\r
c049fc99
JY
353 ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];\r
354 if (ThisExtContextEntry->Bits.AddressWidth == 0) {\r
355 continue;\r
356 }\r
357 *ExtContextEntry = ThisExtContextEntry;\r
358 *ContextEntry = NULL;\r
359 } else {\r
360 RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
76c6f69c 361 ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;\r
c049fc99
JY
362 ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];\r
363 if (ThisContextEntry->Bits.AddressWidth == 0) {\r
364 continue;\r
365 }\r
366 *ExtContextEntry = NULL;\r
367 *ContextEntry = ThisContextEntry;\r
368 }\r
369\r
370 return VtdIndex;\r
371 }\r
372\r
373 return (UINTN)-1;\r
374}\r
375\r