summaryrefslogtreecommitdiffstats
path: root/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c')
-rw-r--r--IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
new file mode 100644
index 0000000000..36750b3f1d
--- /dev/null
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
@@ -0,0 +1,369 @@
+/** @file
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DmaProtection.h"
+
+/**
+ Return the index of PCI data.
+
+ @param[in] VtdIndex The index used to identify a VTd engine.
+ @param[in] Segment The Segment used to identify a VTd engine.
+ @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
+
+ @return The index of the PCI data.
+ @retval (UINTN)-1 The PCI data is not found.
+**/
+UINTN
+GetPciDataIndex (
+ IN UINTN VtdIndex,
+ IN UINT16 Segment,
+ IN VTD_SOURCE_ID SourceId
+ )
+{
+ UINTN Index;
+ VTD_SOURCE_ID *PciSourceId;
+
+ if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
+ return (UINTN)-1;
+ }
+
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+ PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
+ if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) &&
+ (PciSourceId->Bits.Device == SourceId.Bits.Device) &&
+ (PciSourceId->Bits.Function == SourceId.Bits.Function) ) {
+ return Index;
+ }
+ }
+
+ return (UINTN)-1;
+}
+
+/**
+ Register PCI device to VTd engine.
+
+ @param[in] VtdIndex The index of VTd engine.
+ @param[in] Segment The segment of the source.
+ @param[in] SourceId The SourceId of the source.
+ @param[in] DeviceType The DMAR device scope type.
+ @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered.
+ FALSE: SUCCESS will be returned if the PCI device is registered.
+
+ @retval EFI_SUCCESS The PCI device is registered.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device.
+ @retval EFI_ALREADY_STARTED The device is already registered.
+**/
+EFI_STATUS
+RegisterPciDevice (
+ IN UINTN VtdIndex,
+ IN UINT16 Segment,
+ IN VTD_SOURCE_ID SourceId,
+ IN UINT8 DeviceType,
+ IN BOOLEAN CheckExist
+ )
+{
+ PCI_DEVICE_INFORMATION *PciDeviceInfo;
+ VTD_SOURCE_ID *PciSourceId;
+ UINTN PciDataIndex;
+ UINTN Index;
+ PCI_DEVICE_DATA *NewPciDeviceData;
+ EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId;
+
+ PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;
+
+ if (PciDeviceInfo->IncludeAllFlag) {
+ //
+ // Do not register device in other VTD Unit
+ //
+ for (Index = 0; Index < VtdIndex; Index++) {
+ PciDataIndex = GetPciDataIndex (Index, Segment, SourceId);
+ if (PciDataIndex != (UINTN)-1) {
+ 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));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
+ if (PciDataIndex == (UINTN)-1) {
+ //
+ // Register new
+ //
+
+ if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) {
+ //
+ // Reallocate
+ //
+ NewPciDeviceData = AllocateZeroPool (sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER));
+ if (NewPciDeviceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER;
+ if (PciDeviceInfo->PciDeviceData != NULL) {
+ CopyMem (NewPciDeviceData, PciDeviceInfo->PciDeviceData, sizeof(*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber);
+ FreePool (PciDeviceInfo->PciDeviceData);
+ }
+ PciDeviceInfo->PciDeviceData = NewPciDeviceData;
+ }
+
+ ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber);
+
+ PciSourceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciSourceId;
+ PciSourceId->Bits.Bus = SourceId.Bits.Bus;
+ PciSourceId->Bits.Device = SourceId.Bits.Device;
+ PciSourceId->Bits.Function = SourceId.Bits.Function;
+
+ DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+ PciDeviceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciDeviceId;
+ if ((DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) ||
+ (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
+ PciDeviceId->VendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_VENDOR_ID_OFFSET));
+ PciDeviceId->DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_DEVICE_ID_OFFSET));
+ PciDeviceId->RevisionId = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_REVISION_ID_OFFSET));
+
+ DEBUG ((DEBUG_INFO, " (%04x:%04x:%02x", PciDeviceId->VendorId, PciDeviceId->DeviceId, PciDeviceId->RevisionId));
+
+ if (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
+ PciDeviceId->SubsystemVendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_VENDOR_ID_OFFSET));
+ PciDeviceId->SubsystemDeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_ID_OFFSET));
+ DEBUG ((DEBUG_INFO, ":%04x:%04x", PciDeviceId->SubsystemVendorId, PciDeviceId->SubsystemDeviceId));
+ }
+ DEBUG ((DEBUG_INFO, ")"));
+ }
+
+ PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType;
+
+ if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&
+ (DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
+ DEBUG ((DEBUG_INFO, " (*)"));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ PciDeviceInfo->PciDeviceDataNumber++;
+ } else {
+ if (CheckExist) {
+ 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));
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The scan bus callback function to register PCI device.
+
+ @param[in] Context The context of the callback.
+ @param[in] Segment The segment of the source.
+ @param[in] Bus The bus of the source.
+ @param[in] Device The device of the source.
+ @param[in] Function The function of the source.
+
+ @retval EFI_SUCCESS The PCI device is registered.
+**/
+EFI_STATUS
+EFIAPI
+ScanBusCallbackRegisterPciDevice (
+ IN VOID *Context,
+ IN UINT16 Segment,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function
+ )
+{
+ VTD_SOURCE_ID SourceId;
+ UINTN VtdIndex;
+ UINT8 BaseClass;
+ UINT8 SubClass;
+ UINT8 DeviceType;
+ EFI_STATUS Status;
+
+ VtdIndex = (UINTN)Context;
+ SourceId.Bits.Bus = Bus;
+ SourceId.Bits.Device = Device;
+ SourceId.Bits.Function = Function;
+
+ DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT;
+ BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
+ if (BaseClass == PCI_CLASS_BRIDGE) {
+ SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
+ if (SubClass == PCI_CLASS_BRIDGE_P2P) {
+ DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE;
+ }
+ }
+
+ Status = RegisterPciDevice (VtdIndex, Segment, SourceId, DeviceType, FALSE);
+ return Status;
+}
+
+/**
+ Scan PCI bus and invoke callback function for each PCI devices under the bus.
+
+ @param[in] Context The context of the callback function.
+ @param[in] Segment The segment of the source.
+ @param[in] Bus The bus of the source.
+ @param[in] Callback The callback function in PCI scan.
+
+ @retval EFI_SUCCESS The PCI devices under the bus are scaned.
+**/
+EFI_STATUS
+ScanPciBus (
+ IN VOID *Context,
+ IN UINT16 Segment,
+ IN UINT8 Bus,
+ IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback
+ )
+{
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 SecondaryBusNumber;
+ UINT8 HeaderType;
+ UINT8 BaseClass;
+ UINT8 SubClass;
+ UINT32 MaxFunction;
+ UINT16 VendorID;
+ UINT16 DeviceID;
+ EFI_STATUS Status;
+
+ // Scan the PCI bus for devices
+ for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {
+ HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
+ MaxFunction = PCI_MAX_FUNC + 1;
+ if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
+ MaxFunction = 1;
+ }
+ for (Function = 0; Function < MaxFunction; Function++) {
+ VendorID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
+ DeviceID = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
+ if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
+ continue;
+ }
+
+ Status = Callback (Context, Segment, Bus, Device, Function);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
+ if (BaseClass == PCI_CLASS_BRIDGE) {
+ SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
+ if (SubClass == PCI_CLASS_BRIDGE_P2P) {
+ SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+ DEBUG ((DEBUG_INFO," ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));
+ if (SecondaryBusNumber != 0) {
+ Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dump the PCI device information managed by this VTd engine.
+
+ @param[in] VtdIndex The index of VTd engine.
+**/
+VOID
+DumpPciDeviceInfo (
+ IN UINTN VtdIndex
+ )
+{
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag
+ ));
+ for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+ DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n",
+ mVtdUnitInformation[VtdIndex].Segment,
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
+ mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function
+ ));
+ }
+}
+
+/**
+ Find the VTd index by the Segment and SourceId.
+
+ @param[in] Segment The segment of the source.
+ @param[in] SourceId The SourceId of the source.
+ @param[out] ExtContextEntry The ExtContextEntry of the source.
+ @param[out] ContextEntry The ContextEntry of the source.
+
+ @return The index of the VTd engine.
+ @retval (UINTN)-1 The VTd engine is not found.
+**/
+UINTN
+FindVtdIndexByPciDevice (
+ IN UINT16 Segment,
+ IN VTD_SOURCE_ID SourceId,
+ OUT VTD_EXT_CONTEXT_ENTRY **ExtContextEntry,
+ OUT VTD_CONTEXT_ENTRY **ContextEntry
+ )
+{
+ UINTN VtdIndex;
+ VTD_ROOT_ENTRY *RootEntry;
+ VTD_CONTEXT_ENTRY *ContextEntryTable;
+ VTD_CONTEXT_ENTRY *ThisContextEntry;
+ VTD_EXT_ROOT_ENTRY *ExtRootEntry;
+ VTD_EXT_CONTEXT_ENTRY *ExtContextEntryTable;
+ VTD_EXT_CONTEXT_ENTRY *ThisExtContextEntry;
+ UINTN PciDataIndex;
+
+ for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+ if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
+ continue;
+ }
+
+ PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
+ if (PciDataIndex == (UINTN)-1) {
+ continue;
+ }
+
+// 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));
+
+ if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {
+ ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
+ ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;
+ ThisExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];
+ if (ThisExtContextEntry->Bits.AddressWidth == 0) {
+ continue;
+ }
+ *ExtContextEntry = ThisExtContextEntry;
+ *ContextEntry = NULL;
+ } else {
+ RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
+ ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;
+ ThisContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];
+ if (ThisContextEntry->Bits.AddressWidth == 0) {
+ continue;
+ }
+ *ExtContextEntry = NULL;
+ *ContextEntry = ThisContextEntry;
+ }
+
+ return VtdIndex;
+ }
+
+ return (UINTN)-1;
+}
+