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 data.
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 data.
24 @retval (UINTN)-1 The PCI data is not found.
30 IN VTD_SOURCE_ID SourceId
34 VTD_SOURCE_ID
*PciSourceId
;
36 if (Segment
!= mVtdUnitInformation
[VtdIndex
].Segment
) {
40 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
41 PciSourceId
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
;
42 if ((PciSourceId
->Bits
.Bus
== SourceId
.Bits
.Bus
) &&
43 (PciSourceId
->Bits
.Device
== SourceId
.Bits
.Device
) &&
44 (PciSourceId
->Bits
.Function
== SourceId
.Bits
.Function
) ) {
53 Register PCI device to VTd engine.
55 @param[in] VtdIndex The index of VTd engine.
56 @param[in] Segment The segment of the source.
57 @param[in] SourceId The SourceId of the source.
58 @param[in] DeviceType The DMAR device scope type.
59 @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.
60 FALSE: SUCCESS will be returned if the PCI device is registered.
62 @retval EFI_SUCCESS The PCI device is registered.
63 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.
64 @retval EFI_ALREADY_STARTED The device is already registered.
70 IN VTD_SOURCE_ID SourceId
,
75 PCI_DEVICE_INFORMATION
*PciDeviceInfo
;
76 VTD_SOURCE_ID
*PciSourceId
;
79 PCI_DEVICE_DATA
*NewPciDeviceData
;
80 EDKII_PLATFORM_VTD_PCI_DEVICE_ID
*PciDeviceId
;
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 PciDataIndex
= GetPciDataIndex (Index
, Segment
, SourceId
);
90 if (PciDataIndex
!= (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 PciDataIndex
= GetPciDataIndex (VtdIndex
, Segment
, SourceId
);
98 if (PciDataIndex
== (UINTN
)-1) {
103 if (PciDeviceInfo
->PciDeviceDataNumber
>= PciDeviceInfo
->PciDeviceDataMaxNumber
) {
107 NewPciDeviceData
= AllocateZeroPool (sizeof(*NewPciDeviceData
) * (PciDeviceInfo
->PciDeviceDataMaxNumber
+ MAX_VTD_PCI_DATA_NUMBER
));
108 if (NewPciDeviceData
== NULL
) {
109 return EFI_OUT_OF_RESOURCES
;
111 PciDeviceInfo
->PciDeviceDataMaxNumber
+= MAX_VTD_PCI_DATA_NUMBER
;
112 if (PciDeviceInfo
->PciDeviceData
!= NULL
) {
113 CopyMem (NewPciDeviceData
, PciDeviceInfo
->PciDeviceData
, sizeof(*NewPciDeviceData
) * PciDeviceInfo
->PciDeviceDataNumber
);
114 FreePool (PciDeviceInfo
->PciDeviceData
);
116 PciDeviceInfo
->PciDeviceData
= NewPciDeviceData
;
119 ASSERT (PciDeviceInfo
->PciDeviceDataNumber
< PciDeviceInfo
->PciDeviceDataMaxNumber
);
121 PciSourceId
= &PciDeviceInfo
->PciDeviceData
[PciDeviceInfo
->PciDeviceDataNumber
].PciSourceId
;
122 PciSourceId
->Bits
.Bus
= SourceId
.Bits
.Bus
;
123 PciSourceId
->Bits
.Device
= SourceId
.Bits
.Device
;
124 PciSourceId
->Bits
.Function
= SourceId
.Bits
.Function
;
126 DEBUG ((DEBUG_INFO
, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
));
128 PciDeviceId
= &PciDeviceInfo
->PciDeviceData
[PciDeviceInfo
->PciDeviceDataNumber
].PciDeviceId
;
129 if ((DeviceType
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
) ||
130 (DeviceType
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
)) {
131 PciDeviceId
->VendorId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_VENDOR_ID_OFFSET
));
132 PciDeviceId
->DeviceId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_DEVICE_ID_OFFSET
));
133 PciDeviceId
->RevisionId
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_REVISION_ID_OFFSET
));
135 DEBUG ((DEBUG_INFO
, " (%04x:%04x:%02x", PciDeviceId
->VendorId
, PciDeviceId
->DeviceId
, PciDeviceId
->RevisionId
));
137 if (DeviceType
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
) {
138 PciDeviceId
->SubsystemVendorId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_SUBSYSTEM_VENDOR_ID_OFFSET
));
139 PciDeviceId
->SubsystemDeviceId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_SUBSYSTEM_ID_OFFSET
));
140 DEBUG ((DEBUG_INFO
, ":%04x:%04x", PciDeviceId
->SubsystemVendorId
, PciDeviceId
->SubsystemDeviceId
));
142 DEBUG ((DEBUG_INFO
, ")"));
145 PciDeviceInfo
->PciDeviceData
[PciDeviceInfo
->PciDeviceDataNumber
].DeviceType
= DeviceType
;
147 if ((DeviceType
!= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
) &&
148 (DeviceType
!= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
)) {
149 DEBUG ((DEBUG_INFO
, " (*)"));
151 DEBUG ((DEBUG_INFO
, "\n"));
153 PciDeviceInfo
->PciDeviceDataNumber
++;
156 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
));
157 return EFI_ALREADY_STARTED
;
165 The scan bus callback function to register PCI device.
167 @param[in] Context The context of the callback.
168 @param[in] Segment The segment of the source.
169 @param[in] Bus The bus of the source.
170 @param[in] Device The device of the source.
171 @param[in] Function The function of the source.
173 @retval EFI_SUCCESS The PCI device is registered.
177 ScanBusCallbackRegisterPciDevice (
185 VTD_SOURCE_ID SourceId
;
192 VtdIndex
= (UINTN
)Context
;
193 SourceId
.Bits
.Bus
= Bus
;
194 SourceId
.Bits
.Device
= Device
;
195 SourceId
.Bits
.Function
= Function
;
197 DeviceType
= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
;
198 BaseClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 2));
199 if (BaseClass
== PCI_CLASS_BRIDGE
) {
200 SubClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 1));
201 if (SubClass
== PCI_CLASS_BRIDGE_P2P
) {
202 DeviceType
= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
;
206 Status
= RegisterPciDevice (VtdIndex
, Segment
, SourceId
, DeviceType
, FALSE
);
211 Scan PCI bus and invoke callback function for each PCI devices under the bus.
213 @param[in] Context The context of the callback function.
214 @param[in] Segment The segment of the source.
215 @param[in] Bus The bus of the source.
216 @param[in] Callback The callback function in PCI scan.
218 @retval EFI_SUCCESS The PCI devices under the bus are scaned.
225 IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback
230 UINT8 SecondaryBusNumber
;
239 // Scan the PCI bus for devices
240 for (Device
= 0; Device
< PCI_MAX_DEVICE
+ 1; Device
++) {
241 HeaderType
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, 0, PCI_HEADER_TYPE_OFFSET
));
242 MaxFunction
= PCI_MAX_FUNC
+ 1;
243 if ((HeaderType
& HEADER_TYPE_MULTI_FUNCTION
) == 0x00) {
246 for (Function
= 0; Function
< MaxFunction
; Function
++) {
247 VendorID
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_VENDOR_ID_OFFSET
));
248 DeviceID
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_DEVICE_ID_OFFSET
));
249 if (VendorID
== 0xFFFF && DeviceID
== 0xFFFF) {
253 Status
= Callback (Context
, Segment
, Bus
, Device
, Function
);
254 if (EFI_ERROR (Status
)) {
258 BaseClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 2));
259 if (BaseClass
== PCI_CLASS_BRIDGE
) {
260 SubClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 1));
261 if (SubClass
== PCI_CLASS_BRIDGE_P2P
) {
262 SecondaryBusNumber
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
));
263 DEBUG ((DEBUG_INFO
," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment
, Bus
, Device
, Function
, SecondaryBusNumber
));
264 if (SecondaryBusNumber
!= 0) {
265 Status
= ScanPciBus (Context
, Segment
, SecondaryBusNumber
, Callback
);
266 if (EFI_ERROR (Status
)) {
279 Dump the PCI device information managed by this VTd engine.
281 @param[in] VtdIndex The index of VTd engine.
290 DEBUG ((DEBUG_INFO
,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
291 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
,
292 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.IncludeAllFlag
294 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
295 DEBUG ((DEBUG_INFO
," S%04x B%02x D%02x F%02x\n",
296 mVtdUnitInformation
[VtdIndex
].Segment
,
297 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
.Bits
.Bus
,
298 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
.Bits
.Device
,
299 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
.Bits
.Function
305 Find the VTd index by the Segment and SourceId.
307 @param[in] Segment The segment of the source.
308 @param[in] SourceId The SourceId of the source.
309 @param[out] ExtContextEntry The ExtContextEntry of the source.
310 @param[out] ContextEntry The ContextEntry of the source.
312 @return The index of the VTd engine.
313 @retval (UINTN)-1 The VTd engine is not found.
316 FindVtdIndexByPciDevice (
318 IN VTD_SOURCE_ID SourceId
,
319 OUT VTD_EXT_CONTEXT_ENTRY
**ExtContextEntry
,
320 OUT VTD_CONTEXT_ENTRY
**ContextEntry
324 VTD_ROOT_ENTRY
*RootEntry
;
325 VTD_CONTEXT_ENTRY
*ContextEntryTable
;
326 VTD_CONTEXT_ENTRY
*ThisContextEntry
;
327 VTD_EXT_ROOT_ENTRY
*ExtRootEntry
;
328 VTD_EXT_CONTEXT_ENTRY
*ExtContextEntryTable
;
329 VTD_EXT_CONTEXT_ENTRY
*ThisExtContextEntry
;
332 for (VtdIndex
= 0; VtdIndex
< mVtdUnitNumber
; VtdIndex
++) {
333 if (Segment
!= mVtdUnitInformation
[VtdIndex
].Segment
) {
337 PciDataIndex
= GetPciDataIndex (VtdIndex
, Segment
, SourceId
);
338 if (PciDataIndex
== (UINTN
)-1) {
342 // 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));
344 if (mVtdUnitInformation
[VtdIndex
].ExtRootEntryTable
!= 0) {
345 ExtRootEntry
= &mVtdUnitInformation
[VtdIndex
].ExtRootEntryTable
[SourceId
.Index
.RootIndex
];
346 ExtContextEntryTable
= (VTD_EXT_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(ExtRootEntry
->Bits
.LowerContextTablePointerLo
, ExtRootEntry
->Bits
.LowerContextTablePointerHi
) ;
347 ThisExtContextEntry
= &ExtContextEntryTable
[SourceId
.Index
.ContextIndex
];
348 if (ThisExtContextEntry
->Bits
.AddressWidth
== 0) {
351 *ExtContextEntry
= ThisExtContextEntry
;
352 *ContextEntry
= NULL
;
354 RootEntry
= &mVtdUnitInformation
[VtdIndex
].RootEntryTable
[SourceId
.Index
.RootIndex
];
355 ContextEntryTable
= (VTD_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(RootEntry
->Bits
.ContextTablePointerLo
, RootEntry
->Bits
.ContextTablePointerHi
) ;
356 ThisContextEntry
= &ContextEntryTable
[SourceId
.Index
.ContextIndex
];
357 if (ThisContextEntry
->Bits
.AddressWidth
== 0) {
360 *ExtContextEntry
= NULL
;
361 *ContextEntry
= ThisContextEntry
;