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