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.
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.
14 #include "DmaProtection.h"
17 Return the index of PCI descriptor.
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.
23 @return The index of the PCI descriptor.
24 @retval (UINTN)-1 The PCI descriptor is not found.
30 IN VTD_SOURCE_ID SourceId
35 if (Segment
!= mVtdUnitInformation
[VtdIndex
].Segment
) {
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
) ) {
51 Register PCI device to VTd engine as PCI descriptor.
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.
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.
69 IN VTD_SOURCE_ID SourceId
,
70 IN BOOLEAN IsRealPciDevice
,
74 PCI_DEVICE_INFORMATION
*PciDeviceInfo
;
75 VTD_SOURCE_ID
*PciDescriptor
;
76 UINTN PciDescriptorIndex
;
78 BOOLEAN
*NewIsRealPciDevice
;
79 VTD_SOURCE_ID
*NewPciDescriptors
;
80 UINTN
*NewAccessCount
;
82 PciDeviceInfo
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
;
84 if (PciDeviceInfo
->IncludeAllFlag
) {
86 // Do not register device in other VTD Unit
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
));
97 PciDescriptorIndex
= GetPciDescriptor (VtdIndex
, Segment
, SourceId
);
98 if (PciDescriptorIndex
== (UINTN
)-1) {
103 if (PciDeviceInfo
->PciDescriptorNumber
>= PciDeviceInfo
->PciDescriptorMaxNumber
) {
107 NewIsRealPciDevice
= AllocateZeroPool (sizeof(*NewIsRealPciDevice
) * (PciDeviceInfo
->PciDescriptorMaxNumber
+ MAX_PCI_DESCRIPTORS
));
108 if (NewIsRealPciDevice
== NULL
) {
109 return EFI_OUT_OF_RESOURCES
;
111 NewPciDescriptors
= AllocateZeroPool (sizeof(*NewPciDescriptors
) * (PciDeviceInfo
->PciDescriptorMaxNumber
+ MAX_PCI_DESCRIPTORS
));
112 if (NewPciDescriptors
== NULL
) {
113 FreePool (NewIsRealPciDevice
);
114 return EFI_OUT_OF_RESOURCES
;
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
;
122 PciDeviceInfo
->PciDescriptorMaxNumber
+= MAX_PCI_DESCRIPTORS
;
123 if (PciDeviceInfo
->IsRealPciDevice
!= NULL
) {
124 CopyMem (NewIsRealPciDevice
, PciDeviceInfo
->IsRealPciDevice
, sizeof(*NewIsRealPciDevice
) * PciDeviceInfo
->PciDescriptorNumber
);
125 FreePool (PciDeviceInfo
->IsRealPciDevice
);
127 PciDeviceInfo
->IsRealPciDevice
= NewIsRealPciDevice
;
128 if (PciDeviceInfo
->PciDescriptors
!= NULL
) {
129 CopyMem (NewPciDescriptors
, PciDeviceInfo
->PciDescriptors
, sizeof(*NewPciDescriptors
) * PciDeviceInfo
->PciDescriptorNumber
);
130 FreePool (PciDeviceInfo
->PciDescriptors
);
132 PciDeviceInfo
->PciDescriptors
= NewPciDescriptors
;
133 if (PciDeviceInfo
->AccessCount
!= NULL
) {
134 CopyMem (NewAccessCount
, PciDeviceInfo
->AccessCount
, sizeof(*NewAccessCount
) * PciDeviceInfo
->PciDescriptorNumber
);
135 FreePool (PciDeviceInfo
->AccessCount
);
137 PciDeviceInfo
->AccessCount
= NewAccessCount
;
140 ASSERT (PciDeviceInfo
->PciDescriptorNumber
< PciDeviceInfo
->PciDescriptorMaxNumber
);
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
;
148 PciDeviceInfo
->PciDescriptorNumber
++;
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
, " (*)"));
154 DEBUG ((DEBUG_INFO
, "\n"));
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
;
166 Scan PCI bus and register PCI devices under the bus.
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.
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.
184 UINT8 SecondaryBusNumber
;
192 VTD_SOURCE_ID SourceId
;
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) {
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) {
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
)) {
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
)) {
237 Dump the PCI device information managed by this VTd engine.
239 @param[in] VtdIndex The index of VTd engine.
248 DEBUG ((DEBUG_INFO
,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
249 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDescriptorNumber
,
250 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.IncludeAllFlag
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
263 Find the VTd index by the Segment and SourceId.
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.
270 @return The index of the PCI descriptor.
271 @retval (UINTN)-1 The PCI descriptor is not found.
274 FindVtdIndexByPciDevice (
276 IN VTD_SOURCE_ID SourceId
,
277 OUT VTD_EXT_CONTEXT_ENTRY
**ExtContextEntry
,
278 OUT VTD_CONTEXT_ENTRY
**ContextEntry
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
;
290 for (VtdIndex
= 0; VtdIndex
< mVtdUnitNumber
; VtdIndex
++) {
291 if (Segment
!= mVtdUnitInformation
[VtdIndex
].Segment
) {
295 PciDescriptorIndex
= GetPciDescriptor (VtdIndex
, Segment
, SourceId
);
296 if (PciDescriptorIndex
== (UINTN
)-1) {
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));
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) {
309 *ExtContextEntry
= ThisExtContextEntry
;
310 *ContextEntry
= NULL
;
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) {
318 *ExtContextEntry
= NULL
;
319 *ContextEntry
= ThisContextEntry
;