]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/IntelVTdDxe/PciInfo.c
IntelSiliconPkg/IntelVTdDxe: Improve performance.
[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
17 Return the index of PCI descriptor.\r
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
23 @return The index of the PCI descriptor.\r
24 @retval (UINTN)-1 The PCI descriptor is not found.\r
25**/\r
26UINTN\r
27GetPciDescriptor (\r
28 IN UINTN VtdIndex,\r
29 IN UINT16 Segment,\r
30 IN VTD_SOURCE_ID SourceId\r
31 )\r
32{\r
33 UINTN Index;\r
34\r
35 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
36 return (UINTN)-1;\r
37 }\r
38\r
39 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
40 if ((mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus == SourceId.Bits.Bus) &&\r
41 (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device == SourceId.Bits.Device) &&\r
42 (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function == SourceId.Bits.Function) ) {\r
43 return Index;\r
44 }\r
45 }\r
46\r
47 return (UINTN)-1;\r
48}\r
49\r
50/**\r
51 Register PCI device to VTd engine as PCI descriptor.\r
52\r
53 @param[in] VtdIndex The index of VTd engine.\r
54 @param[in] Segment The segment of the source.\r
55 @param[in] SourceId The SourceId of the source.\r
56 @param[in] IsRealPciDevice TRUE: It is a real PCI device.\r
57 FALSE: It is not a real PCI device.\r
58 @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.\r
59 FALSE: SUCCESS will be returned if the PCI device is registered.\r
60\r
61 @retval EFI_SUCCESS The PCI device is registered.\r
62 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
63 @retval EFI_ALREADY_STARTED The device is already registered.\r
64**/\r
65EFI_STATUS\r
66RegisterPciDevice (\r
67 IN UINTN VtdIndex,\r
68 IN UINT16 Segment,\r
69 IN VTD_SOURCE_ID SourceId,\r
70 IN BOOLEAN IsRealPciDevice,\r
71 IN BOOLEAN CheckExist\r
72 )\r
73{\r
74 PCI_DEVICE_INFORMATION *PciDeviceInfo;\r
75 VTD_SOURCE_ID *PciDescriptor;\r
76 UINTN PciDescriptorIndex;\r
77 UINTN Index;\r
78 BOOLEAN *NewIsRealPciDevice;\r
79 VTD_SOURCE_ID *NewPciDescriptors;\r
4ad5f597 80 UINTN *NewAccessCount;\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
89 PciDescriptorIndex = GetPciDescriptor (Index, Segment, SourceId);\r
90 if (PciDescriptorIndex != (UINTN)-1) {\r
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
97 PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
98 if (PciDescriptorIndex == (UINTN)-1) {\r
99 //\r
100 // Register new\r
101 //\r
102\r
103 if (PciDeviceInfo->PciDescriptorNumber >= PciDeviceInfo->PciDescriptorMaxNumber) {\r
104 //\r
105 // Reallocate\r
106 //\r
107 NewIsRealPciDevice = AllocateZeroPool (sizeof(*NewIsRealPciDevice) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
108 if (NewIsRealPciDevice == NULL) {\r
109 return EFI_OUT_OF_RESOURCES;\r
110 }\r
111 NewPciDescriptors = AllocateZeroPool (sizeof(*NewPciDescriptors) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
112 if (NewPciDescriptors == NULL) {\r
113 FreePool (NewIsRealPciDevice);\r
114 return EFI_OUT_OF_RESOURCES;\r
115 }\r
4ad5f597
JY
116 NewAccessCount = AllocateZeroPool (sizeof(*NewAccessCount) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
117 if (NewAccessCount == NULL) {\r
118 FreePool (NewIsRealPciDevice);\r
119 FreePool (NewPciDescriptors);\r
120 return EFI_OUT_OF_RESOURCES;\r
121 }\r
c049fc99
JY
122 PciDeviceInfo->PciDescriptorMaxNumber += MAX_PCI_DESCRIPTORS;\r
123 if (PciDeviceInfo->IsRealPciDevice != NULL) {\r
124 CopyMem (NewIsRealPciDevice, PciDeviceInfo->IsRealPciDevice, sizeof(*NewIsRealPciDevice) * PciDeviceInfo->PciDescriptorNumber);\r
125 FreePool (PciDeviceInfo->IsRealPciDevice);\r
126 }\r
127 PciDeviceInfo->IsRealPciDevice = NewIsRealPciDevice;\r
128 if (PciDeviceInfo->PciDescriptors != NULL) {\r
129 CopyMem (NewPciDescriptors, PciDeviceInfo->PciDescriptors, sizeof(*NewPciDescriptors) * PciDeviceInfo->PciDescriptorNumber);\r
130 FreePool (PciDeviceInfo->PciDescriptors);\r
131 }\r
132 PciDeviceInfo->PciDescriptors = NewPciDescriptors;\r
4ad5f597
JY
133 if (PciDeviceInfo->AccessCount != NULL) {\r
134 CopyMem (NewAccessCount, PciDeviceInfo->AccessCount, sizeof(*NewAccessCount) * PciDeviceInfo->PciDescriptorNumber);\r
135 FreePool (PciDeviceInfo->AccessCount);\r
136 }\r
137 PciDeviceInfo->AccessCount = NewAccessCount;\r
c049fc99
JY
138 }\r
139\r
140 ASSERT (PciDeviceInfo->PciDescriptorNumber < PciDeviceInfo->PciDescriptorMaxNumber);\r
141\r
142 PciDescriptor = &PciDeviceInfo->PciDescriptors[PciDeviceInfo->PciDescriptorNumber];\r
143 PciDescriptor->Bits.Bus = SourceId.Bits.Bus;\r
144 PciDescriptor->Bits.Device = SourceId.Bits.Device;\r
145 PciDescriptor->Bits.Function = SourceId.Bits.Function;\r
146 PciDeviceInfo->IsRealPciDevice[PciDeviceInfo->PciDescriptorNumber] = IsRealPciDevice;\r
147\r
148 PciDeviceInfo->PciDescriptorNumber++;\r
149\r
150 DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
151 if (!IsRealPciDevice) {\r
152 DEBUG ((DEBUG_INFO, " (*)"));\r
153 }\r
154 DEBUG ((DEBUG_INFO, "\n"));\r
155 } else {\r
156 if (CheckExist) {\r
157 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
158 return EFI_ALREADY_STARTED;\r
159 }\r
160 }\r
161\r
162 return EFI_SUCCESS;\r
163}\r
164\r
165/**\r
166 Scan PCI bus and register PCI devices under the bus.\r
167\r
168 @param[in] VtdIndex The index of VTd engine.\r
169 @param[in] Segment The segment of the source.\r
170 @param[in] Bus The bus of the source.\r
171\r
172 @retval EFI_SUCCESS The PCI devices under the bus are registered.\r
173 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
174**/\r
175EFI_STATUS\r
176ScanPciBus (\r
177 IN UINTN VtdIndex,\r
178 IN UINT16 Segment,\r
179 IN UINT8 Bus\r
180 )\r
181{\r
182 UINT8 Device;\r
183 UINT8 Function;\r
184 UINT8 SecondaryBusNumber;\r
185 UINT8 HeaderType;\r
186 UINT8 BaseClass;\r
187 UINT8 SubClass;\r
188 UINT32 MaxFunction;\r
189 UINT16 VendorID;\r
190 UINT16 DeviceID;\r
191 EFI_STATUS Status;\r
192 VTD_SOURCE_ID SourceId;\r
193\r
194 // Scan the PCI bus for devices\r
195 for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {\r
196 HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));\r
197 MaxFunction = PCI_MAX_FUNC + 1;\r
198 if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {\r
199 MaxFunction = 1;\r
200 }\r
201 for (Function = 0; Function < MaxFunction; Function++) {\r
202 VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));\r
203 DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));\r
204 if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {\r
205 continue;\r
206 }\r
207\r
208 SourceId.Bits.Bus = Bus;\r
209 SourceId.Bits.Device = Device;\r
210 SourceId.Bits.Function = Function;\r
211 Status = RegisterPciDevice (VtdIndex, Segment, SourceId, TRUE, FALSE);\r
212 if (EFI_ERROR (Status)) {\r
213 return Status;\r
214 }\r
215\r
216 BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));\r
217 if (BaseClass == PCI_CLASS_BRIDGE) {\r
218 SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));\r
219 if (SubClass == PCI_CLASS_BRIDGE_P2P) {\r
220 SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
221 DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));\r
222 if (SecondaryBusNumber != 0) {\r
223 Status = ScanPciBus (VtdIndex, Segment, SecondaryBusNumber);\r
224 if (EFI_ERROR (Status)) {\r
225 return Status;\r
226 }\r
227 }\r
228 }\r
229 }\r
230 }\r
231 }\r
232\r
233 return EFI_SUCCESS;\r
234}\r
235\r
236/**\r
237 Dump the PCI device information managed by this VTd engine.\r
238\r
239 @param[in] VtdIndex The index of VTd engine.\r
240**/\r
241VOID\r
242DumpPciDeviceInfo (\r
243 IN UINTN VtdIndex\r
244 )\r
245{\r
246 UINTN Index;\r
247\r
248 DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",\r
249 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber,\r
250 mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag\r
251 ));\r
252 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
253 DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",\r
254 mVtdUnitInformation[VtdIndex].Segment,\r
255 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus,\r
256 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device,\r
257 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function\r
258 ));\r
259 }\r
260}\r
261\r
262/**\r
263 Find the VTd index by the Segment and SourceId.\r
264\r
265 @param[in] Segment The segment of the source.\r
266 @param[in] SourceId The SourceId of the source.\r
267 @param[out] ExtContextEntry The ExtContextEntry of the source.\r
268 @param[out] ContextEntry The ContextEntry of the source.\r
269\r
270 @return The index of the PCI descriptor.\r
271 @retval (UINTN)-1 The PCI descriptor is not found.\r
272**/\r
273UINTN\r
274FindVtdIndexByPciDevice (\r
275 IN UINT16 Segment,\r
276 IN VTD_SOURCE_ID SourceId,\r
277 OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,\r
278 OUT VTD_CONTEXT_ENTRY **ContextEntry\r
279 )\r
280{\r
281 UINTN VtdIndex;\r
282 VTD_ROOT_ENTRY *RootEntry;\r
283 VTD_CONTEXT_ENTRY *ContextEntryTable;\r
284 VTD_CONTEXT_ENTRY *ThisContextEntry;\r
285 VTD_EXT_ROOT_ENTRY *ExtRootEntry;\r
286 VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;\r
287 VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;\r
288 UINTN PciDescriptorIndex;\r
289\r
290 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
291 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
292 continue;\r
293 }\r
294\r
295 PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
296 if (PciDescriptorIndex == (UINTN)-1) {\r
297 continue;\r
298 }\r
299\r
300// 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
301\r
302 if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {\r
303 ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];\r
76c6f69c 304 ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;\r
c049fc99
JY
305 ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];\r
306 if (ThisExtContextEntry->Bits.AddressWidth == 0) {\r
307 continue;\r
308 }\r
309 *ExtContextEntry = ThisExtContextEntry;\r
310 *ContextEntry = NULL;\r
311 } else {\r
312 RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
76c6f69c 313 ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;\r
c049fc99
JY
314 ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];\r
315 if (ThisContextEntry->Bits.AddressWidth == 0) {\r
316 continue;\r
317 }\r
318 *ExtContextEntry = NULL;\r
319 *ContextEntry = ThisContextEntry;\r
320 }\r
321\r
322 return VtdIndex;\r
323 }\r
324\r
325 return (UINTN)-1;\r
326}\r
327\r