3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "DmaProtection.h"
11 Return the index of PCI data.
13 @param[in] VtdIndex The index used to identify a VTd engine.
14 @param[in] Segment The Segment used to identify a VTd engine.
15 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
17 @return The index of the PCI data.
18 @retval (UINTN)-1 The PCI data is not found.
24 IN VTD_SOURCE_ID SourceId
28 VTD_SOURCE_ID
*PciSourceId
;
30 if (Segment
!= mVtdUnitInformation
[VtdIndex
].Segment
) {
34 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
35 PciSourceId
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
;
36 if ((PciSourceId
->Bits
.Bus
== SourceId
.Bits
.Bus
) &&
37 (PciSourceId
->Bits
.Device
== SourceId
.Bits
.Device
) &&
38 (PciSourceId
->Bits
.Function
== SourceId
.Bits
.Function
) ) {
47 Register PCI device to VTd engine.
49 @param[in] VtdIndex The index of VTd engine.
50 @param[in] Segment The segment of the source.
51 @param[in] SourceId The SourceId of the source.
52 @param[in] DeviceType The DMAR device scope type.
53 @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.
54 FALSE: SUCCESS will be returned if the PCI device is registered.
56 @retval EFI_SUCCESS The PCI device is registered.
57 @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.
58 @retval EFI_ALREADY_STARTED The device is already registered.
64 IN VTD_SOURCE_ID SourceId
,
69 PCI_DEVICE_INFORMATION
*PciDeviceInfo
;
70 VTD_SOURCE_ID
*PciSourceId
;
73 PCI_DEVICE_DATA
*NewPciDeviceData
;
74 EDKII_PLATFORM_VTD_PCI_DEVICE_ID
*PciDeviceId
;
76 PciDeviceInfo
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
;
78 if (PciDeviceInfo
->IncludeAllFlag
) {
80 // Do not register device in other VTD Unit
82 for (Index
= 0; Index
< VtdIndex
; Index
++) {
83 PciDataIndex
= GetPciDataIndex (Index
, Segment
, SourceId
);
84 if (PciDataIndex
!= (UINTN
)-1) {
85 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 PciDataIndex
= GetPciDataIndex (VtdIndex
, Segment
, SourceId
);
92 if (PciDataIndex
== (UINTN
)-1) {
97 if (PciDeviceInfo
->PciDeviceDataNumber
>= PciDeviceInfo
->PciDeviceDataMaxNumber
) {
101 NewPciDeviceData
= AllocateZeroPool (sizeof(*NewPciDeviceData
) * (PciDeviceInfo
->PciDeviceDataMaxNumber
+ MAX_VTD_PCI_DATA_NUMBER
));
102 if (NewPciDeviceData
== NULL
) {
103 return EFI_OUT_OF_RESOURCES
;
105 PciDeviceInfo
->PciDeviceDataMaxNumber
+= MAX_VTD_PCI_DATA_NUMBER
;
106 if (PciDeviceInfo
->PciDeviceData
!= NULL
) {
107 CopyMem (NewPciDeviceData
, PciDeviceInfo
->PciDeviceData
, sizeof(*NewPciDeviceData
) * PciDeviceInfo
->PciDeviceDataNumber
);
108 FreePool (PciDeviceInfo
->PciDeviceData
);
110 PciDeviceInfo
->PciDeviceData
= NewPciDeviceData
;
113 ASSERT (PciDeviceInfo
->PciDeviceDataNumber
< PciDeviceInfo
->PciDeviceDataMaxNumber
);
115 PciSourceId
= &PciDeviceInfo
->PciDeviceData
[PciDeviceInfo
->PciDeviceDataNumber
].PciSourceId
;
116 PciSourceId
->Bits
.Bus
= SourceId
.Bits
.Bus
;
117 PciSourceId
->Bits
.Device
= SourceId
.Bits
.Device
;
118 PciSourceId
->Bits
.Function
= SourceId
.Bits
.Function
;
120 DEBUG ((DEBUG_INFO
, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
));
122 PciDeviceId
= &PciDeviceInfo
->PciDeviceData
[PciDeviceInfo
->PciDeviceDataNumber
].PciDeviceId
;
123 if ((DeviceType
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
) ||
124 (DeviceType
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
)) {
125 PciDeviceId
->VendorId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_VENDOR_ID_OFFSET
));
126 PciDeviceId
->DeviceId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_DEVICE_ID_OFFSET
));
127 PciDeviceId
->RevisionId
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_REVISION_ID_OFFSET
));
129 DEBUG ((DEBUG_INFO
, " (%04x:%04x:%02x", PciDeviceId
->VendorId
, PciDeviceId
->DeviceId
, PciDeviceId
->RevisionId
));
131 if (DeviceType
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
) {
132 PciDeviceId
->SubsystemVendorId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_SUBSYSTEM_VENDOR_ID_OFFSET
));
133 PciDeviceId
->SubsystemDeviceId
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
, PCI_SUBSYSTEM_ID_OFFSET
));
134 DEBUG ((DEBUG_INFO
, ":%04x:%04x", PciDeviceId
->SubsystemVendorId
, PciDeviceId
->SubsystemDeviceId
));
136 DEBUG ((DEBUG_INFO
, ")"));
139 PciDeviceInfo
->PciDeviceData
[PciDeviceInfo
->PciDeviceDataNumber
].DeviceType
= DeviceType
;
141 if ((DeviceType
!= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
) &&
142 (DeviceType
!= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
)) {
143 DEBUG ((DEBUG_INFO
, " (*)"));
145 DEBUG ((DEBUG_INFO
, "\n"));
147 PciDeviceInfo
->PciDeviceDataNumber
++;
150 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
));
151 return EFI_ALREADY_STARTED
;
159 The scan bus callback function to register PCI device.
161 @param[in] Context The context of the callback.
162 @param[in] Segment The segment of the source.
163 @param[in] Bus The bus of the source.
164 @param[in] Device The device of the source.
165 @param[in] Function The function of the source.
167 @retval EFI_SUCCESS The PCI device is registered.
171 ScanBusCallbackRegisterPciDevice (
179 VTD_SOURCE_ID SourceId
;
186 VtdIndex
= (UINTN
)Context
;
187 SourceId
.Bits
.Bus
= Bus
;
188 SourceId
.Bits
.Device
= Device
;
189 SourceId
.Bits
.Function
= Function
;
191 DeviceType
= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
;
192 BaseClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 2));
193 if (BaseClass
== PCI_CLASS_BRIDGE
) {
194 SubClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 1));
195 if (SubClass
== PCI_CLASS_BRIDGE_P2P
) {
196 DeviceType
= EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
;
200 Status
= RegisterPciDevice (VtdIndex
, Segment
, SourceId
, DeviceType
, FALSE
);
205 Scan PCI bus and invoke callback function for each PCI devices under the bus.
207 @param[in] Context The context of the callback function.
208 @param[in] Segment The segment of the source.
209 @param[in] Bus The bus of the source.
210 @param[in] Callback The callback function in PCI scan.
212 @retval EFI_SUCCESS The PCI devices under the bus are scaned.
219 IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback
224 UINT8 SecondaryBusNumber
;
232 // Scan the PCI bus for devices
233 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
234 for (Function
= 0; Function
<= PCI_MAX_FUNC
; Function
++) {
235 VendorID
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_VENDOR_ID_OFFSET
));
236 DeviceID
= PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_DEVICE_ID_OFFSET
));
237 if (VendorID
== 0xFFFF && DeviceID
== 0xFFFF) {
240 // If function 0 is not implemented, do not scan other functions.
247 Status
= Callback (Context
, Segment
, Bus
, Device
, Function
);
248 if (EFI_ERROR (Status
)) {
252 BaseClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 2));
253 if (BaseClass
== PCI_CLASS_BRIDGE
) {
254 SubClass
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_CLASSCODE_OFFSET
+ 1));
255 if (SubClass
== PCI_CLASS_BRIDGE_P2P
) {
256 SecondaryBusNumber
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, Function
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
));
257 DEBUG ((DEBUG_INFO
," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment
, Bus
, Device
, Function
, SecondaryBusNumber
));
258 if (SecondaryBusNumber
!= 0) {
259 Status
= ScanPciBus (Context
, Segment
, SecondaryBusNumber
, Callback
);
260 if (EFI_ERROR (Status
)) {
268 HeaderType
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment
, Bus
, Device
, 0, PCI_HEADER_TYPE_OFFSET
));
269 if ((HeaderType
& HEADER_TYPE_MULTI_FUNCTION
) == 0x00) {
271 // It is not a multi-function device, do not scan other functions.
283 Dump the PCI device information managed by this VTd engine.
285 @param[in] VtdIndex The index of VTd engine.
294 DEBUG ((DEBUG_INFO
,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
295 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
,
296 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.IncludeAllFlag
298 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
299 DEBUG ((DEBUG_INFO
," S%04x B%02x D%02x F%02x\n",
300 mVtdUnitInformation
[VtdIndex
].Segment
,
301 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
.Bits
.Bus
,
302 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
.Bits
.Device
,
303 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
.Bits
.Function
309 Find the VTd index by the Segment and SourceId.
311 @param[in] Segment The segment of the source.
312 @param[in] SourceId The SourceId of the source.
313 @param[out] ExtContextEntry The ExtContextEntry of the source.
314 @param[out] ContextEntry The ContextEntry of the source.
316 @return The index of the VTd engine.
317 @retval (UINTN)-1 The VTd engine is not found.
320 FindVtdIndexByPciDevice (
322 IN VTD_SOURCE_ID SourceId
,
323 OUT VTD_EXT_CONTEXT_ENTRY
**ExtContextEntry
,
324 OUT VTD_CONTEXT_ENTRY
**ContextEntry
328 VTD_ROOT_ENTRY
*RootEntry
;
329 VTD_CONTEXT_ENTRY
*ContextEntryTable
;
330 VTD_CONTEXT_ENTRY
*ThisContextEntry
;
331 VTD_EXT_ROOT_ENTRY
*ExtRootEntry
;
332 VTD_EXT_CONTEXT_ENTRY
*ExtContextEntryTable
;
333 VTD_EXT_CONTEXT_ENTRY
*ThisExtContextEntry
;
336 for (VtdIndex
= 0; VtdIndex
< mVtdUnitNumber
; VtdIndex
++) {
337 if (Segment
!= mVtdUnitInformation
[VtdIndex
].Segment
) {
341 PciDataIndex
= GetPciDataIndex (VtdIndex
, Segment
, SourceId
);
342 if (PciDataIndex
== (UINTN
)-1) {
346 // 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));
348 if (mVtdUnitInformation
[VtdIndex
].ExtRootEntryTable
!= 0) {
349 ExtRootEntry
= &mVtdUnitInformation
[VtdIndex
].ExtRootEntryTable
[SourceId
.Index
.RootIndex
];
350 ExtContextEntryTable
= (VTD_EXT_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(ExtRootEntry
->Bits
.LowerContextTablePointerLo
, ExtRootEntry
->Bits
.LowerContextTablePointerHi
) ;
351 ThisExtContextEntry
= &ExtContextEntryTable
[SourceId
.Index
.ContextIndex
];
352 if (ThisExtContextEntry
->Bits
.AddressWidth
== 0) {
355 *ExtContextEntry
= ThisExtContextEntry
;
356 *ContextEntry
= NULL
;
358 RootEntry
= &mVtdUnitInformation
[VtdIndex
].RootEntryTable
[SourceId
.Index
.RootIndex
];
359 ContextEntryTable
= (VTD_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(RootEntry
->Bits
.ContextTablePointerLo
, RootEntry
->Bits
.ContextTablePointerHi
) ;
360 ThisContextEntry
= &ContextEntryTable
[SourceId
.Index
.ContextIndex
];
361 if (ThisContextEntry
->Bits
.AddressWidth
== 0) {
364 *ExtContextEntry
= NULL
;
365 *ContextEntry
= ThisContextEntry
;