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