]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/IntelVTdDxe/PciInfo.c
IntelSiliconPkg: Add VTd driver.
[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
80\r
81 PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;\r
82\r
83 if (PciDeviceInfo->IncludeAllFlag) {\r
84 //\r
85 // Do not register device in other VTD Unit\r
86 //\r
87 for (Index = 0; Index < VtdIndex; Index++) {\r
88 PciDescriptorIndex = GetPciDescriptor (Index, Segment, SourceId);\r
89 if (PciDescriptorIndex != (UINTN)-1) {\r
90 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
91 return EFI_SUCCESS;\r
92 }\r
93 }\r
94 }\r
95\r
96 PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
97 if (PciDescriptorIndex == (UINTN)-1) {\r
98 //\r
99 // Register new\r
100 //\r
101\r
102 if (PciDeviceInfo->PciDescriptorNumber >= PciDeviceInfo->PciDescriptorMaxNumber) {\r
103 //\r
104 // Reallocate\r
105 //\r
106 NewIsRealPciDevice = AllocateZeroPool (sizeof(*NewIsRealPciDevice) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
107 if (NewIsRealPciDevice == NULL) {\r
108 return EFI_OUT_OF_RESOURCES;\r
109 }\r
110 NewPciDescriptors = AllocateZeroPool (sizeof(*NewPciDescriptors) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
111 if (NewPciDescriptors == NULL) {\r
112 FreePool (NewIsRealPciDevice);\r
113 return EFI_OUT_OF_RESOURCES;\r
114 }\r
115 PciDeviceInfo->PciDescriptorMaxNumber += MAX_PCI_DESCRIPTORS;\r
116 if (PciDeviceInfo->IsRealPciDevice != NULL) {\r
117 CopyMem (NewIsRealPciDevice, PciDeviceInfo->IsRealPciDevice, sizeof(*NewIsRealPciDevice) * PciDeviceInfo->PciDescriptorNumber);\r
118 FreePool (PciDeviceInfo->IsRealPciDevice);\r
119 }\r
120 PciDeviceInfo->IsRealPciDevice = NewIsRealPciDevice;\r
121 if (PciDeviceInfo->PciDescriptors != NULL) {\r
122 CopyMem (NewPciDescriptors, PciDeviceInfo->PciDescriptors, sizeof(*NewPciDescriptors) * PciDeviceInfo->PciDescriptorNumber);\r
123 FreePool (PciDeviceInfo->PciDescriptors);\r
124 }\r
125 PciDeviceInfo->PciDescriptors = NewPciDescriptors;\r
126 }\r
127\r
128 ASSERT (PciDeviceInfo->PciDescriptorNumber < PciDeviceInfo->PciDescriptorMaxNumber);\r
129\r
130 PciDescriptor = &PciDeviceInfo->PciDescriptors[PciDeviceInfo->PciDescriptorNumber];\r
131 PciDescriptor->Bits.Bus = SourceId.Bits.Bus;\r
132 PciDescriptor->Bits.Device = SourceId.Bits.Device;\r
133 PciDescriptor->Bits.Function = SourceId.Bits.Function;\r
134 PciDeviceInfo->IsRealPciDevice[PciDeviceInfo->PciDescriptorNumber] = IsRealPciDevice;\r
135\r
136 PciDeviceInfo->PciDescriptorNumber++;\r
137\r
138 DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
139 if (!IsRealPciDevice) {\r
140 DEBUG ((DEBUG_INFO, " (*)"));\r
141 }\r
142 DEBUG ((DEBUG_INFO, "\n"));\r
143 } else {\r
144 if (CheckExist) {\r
145 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
146 return EFI_ALREADY_STARTED;\r
147 }\r
148 }\r
149\r
150 return EFI_SUCCESS;\r
151}\r
152\r
153/**\r
154 Scan PCI bus and register PCI devices under the bus.\r
155\r
156 @param[in] VtdIndex The index of VTd engine.\r
157 @param[in] Segment The segment of the source.\r
158 @param[in] Bus The bus of the source.\r
159\r
160 @retval EFI_SUCCESS The PCI devices under the bus are registered.\r
161 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.\r
162**/\r
163EFI_STATUS\r
164ScanPciBus (\r
165 IN UINTN VtdIndex,\r
166 IN UINT16 Segment,\r
167 IN UINT8 Bus\r
168 )\r
169{\r
170 UINT8 Device;\r
171 UINT8 Function;\r
172 UINT8 SecondaryBusNumber;\r
173 UINT8 HeaderType;\r
174 UINT8 BaseClass;\r
175 UINT8 SubClass;\r
176 UINT32 MaxFunction;\r
177 UINT16 VendorID;\r
178 UINT16 DeviceID;\r
179 EFI_STATUS Status;\r
180 VTD_SOURCE_ID SourceId;\r
181\r
182 // Scan the PCI bus for devices\r
183 for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {\r
184 HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));\r
185 MaxFunction = PCI_MAX_FUNC + 1;\r
186 if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {\r
187 MaxFunction = 1;\r
188 }\r
189 for (Function = 0; Function < MaxFunction; Function++) {\r
190 VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));\r
191 DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));\r
192 if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {\r
193 continue;\r
194 }\r
195\r
196 SourceId.Bits.Bus = Bus;\r
197 SourceId.Bits.Device = Device;\r
198 SourceId.Bits.Function = Function;\r
199 Status = RegisterPciDevice (VtdIndex, Segment, SourceId, TRUE, FALSE);\r
200 if (EFI_ERROR (Status)) {\r
201 return Status;\r
202 }\r
203\r
204 BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));\r
205 if (BaseClass == PCI_CLASS_BRIDGE) {\r
206 SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));\r
207 if (SubClass == PCI_CLASS_BRIDGE_P2P) {\r
208 SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
209 DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));\r
210 if (SecondaryBusNumber != 0) {\r
211 Status = ScanPciBus (VtdIndex, Segment, SecondaryBusNumber);\r
212 if (EFI_ERROR (Status)) {\r
213 return Status;\r
214 }\r
215 }\r
216 }\r
217 }\r
218 }\r
219 }\r
220\r
221 return EFI_SUCCESS;\r
222}\r
223\r
224/**\r
225 Dump the PCI device information managed by this VTd engine.\r
226\r
227 @param[in] VtdIndex The index of VTd engine.\r
228**/\r
229VOID\r
230DumpPciDeviceInfo (\r
231 IN UINTN VtdIndex\r
232 )\r
233{\r
234 UINTN Index;\r
235\r
236 DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",\r
237 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber,\r
238 mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag\r
239 ));\r
240 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
241 DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",\r
242 mVtdUnitInformation[VtdIndex].Segment,\r
243 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus,\r
244 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device,\r
245 mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function\r
246 ));\r
247 }\r
248}\r
249\r
250/**\r
251 Find the VTd index by the Segment and SourceId.\r
252\r
253 @param[in] Segment The segment of the source.\r
254 @param[in] SourceId The SourceId of the source.\r
255 @param[out] ExtContextEntry The ExtContextEntry of the source.\r
256 @param[out] ContextEntry The ContextEntry of the source.\r
257\r
258 @return The index of the PCI descriptor.\r
259 @retval (UINTN)-1 The PCI descriptor is not found.\r
260**/\r
261UINTN\r
262FindVtdIndexByPciDevice (\r
263 IN UINT16 Segment,\r
264 IN VTD_SOURCE_ID SourceId,\r
265 OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,\r
266 OUT VTD_CONTEXT_ENTRY **ContextEntry\r
267 )\r
268{\r
269 UINTN VtdIndex;\r
270 VTD_ROOT_ENTRY *RootEntry;\r
271 VTD_CONTEXT_ENTRY *ContextEntryTable;\r
272 VTD_CONTEXT_ENTRY *ThisContextEntry;\r
273 VTD_EXT_ROOT_ENTRY *ExtRootEntry;\r
274 VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;\r
275 VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;\r
276 UINTN PciDescriptorIndex;\r
277\r
278 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
279 if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
280 continue;\r
281 }\r
282\r
283 PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
284 if (PciDescriptorIndex == (UINTN)-1) {\r
285 continue;\r
286 }\r
287\r
288// 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
289\r
290 if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {\r
291 ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];\r
292 ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)LShiftU64 (ExtRootEntry->Bits.LowerContextTablePointer, 12) ;\r
293 ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];\r
294 if (ThisExtContextEntry->Bits.AddressWidth == 0) {\r
295 continue;\r
296 }\r
297 *ExtContextEntry = ThisExtContextEntry;\r
298 *ContextEntry = NULL;\r
299 } else {\r
300 RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
301 ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)LShiftU64 (RootEntry->Bits.ContextTablePointer, 12) ;\r
302 ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];\r
303 if (ThisContextEntry->Bits.AddressWidth == 0) {\r
304 continue;\r
305 }\r
306 *ExtContextEntry = NULL;\r
307 *ContextEntry = ThisContextEntry;\r
308 }\r
309\r
310 return VtdIndex;\r
311 }\r
312\r
313 return (UINTN)-1;\r
314}\r
315\r