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