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