]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/IntelVTdDxe/PciInfo.c
IntelSiliconPkg: Add VTd driver.
[mirror_edk2.git] / IntelSiliconPkg / IntelVTdDxe / PciInfo.c
diff --git a/IntelSiliconPkg/IntelVTdDxe/PciInfo.c b/IntelSiliconPkg/IntelVTdDxe/PciInfo.c
new file mode 100644 (file)
index 0000000..ea84317
--- /dev/null
@@ -0,0 +1,315 @@
+/** @file\r
+\r
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DmaProtection.h"\r
+\r
+/**\r
+  Return the index of PCI descriptor.\r
+\r
+  @param[in]  VtdIndex          The index used to identify a VTd engine.\r
+  @param[in]  Segment           The Segment used to identify a VTd engine.\r
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.\r
+\r
+  @return The index of the PCI descriptor.\r
+  @retval (UINTN)-1  The PCI descriptor is not found.\r
+**/\r
+UINTN\r
+GetPciDescriptor (\r
+  IN UINTN          VtdIndex,\r
+  IN UINT16         Segment,\r
+  IN VTD_SOURCE_ID  SourceId\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
+    return (UINTN)-1;\r
+  }\r
+\r
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
+    if ((mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus == SourceId.Bits.Bus) &&\r
+        (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device == SourceId.Bits.Device) &&\r
+        (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function == SourceId.Bits.Function) ) {\r
+      return Index;\r
+    }\r
+  }\r
+\r
+  return (UINTN)-1;\r
+}\r
+\r
+/**\r
+  Register PCI device to VTd engine as PCI descriptor.\r
+\r
+  @param[in]  VtdIndex              The index of VTd engine.\r
+  @param[in]  Segment               The segment of the source.\r
+  @param[in]  SourceId              The SourceId of the source.\r
+  @param[in]  IsRealPciDevice       TRUE: It is a real PCI device.\r
+                                    FALSE: It is not a real PCI device.\r
+  @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.\r
+                                    FALSE: SUCCESS will be returned if the PCI device is registered.\r
+\r
+  @retval EFI_SUCCESS           The PCI device is registered.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.\r
+  @retval EFI_ALREADY_STARTED   The device is already registered.\r
+**/\r
+EFI_STATUS\r
+RegisterPciDevice (\r
+  IN UINTN          VtdIndex,\r
+  IN UINT16         Segment,\r
+  IN VTD_SOURCE_ID  SourceId,\r
+  IN BOOLEAN        IsRealPciDevice,\r
+  IN BOOLEAN        CheckExist\r
+  )\r
+{\r
+  PCI_DEVICE_INFORMATION  *PciDeviceInfo;\r
+  VTD_SOURCE_ID           *PciDescriptor;\r
+  UINTN                   PciDescriptorIndex;\r
+  UINTN                   Index;\r
+  BOOLEAN                 *NewIsRealPciDevice;\r
+  VTD_SOURCE_ID           *NewPciDescriptors;\r
+\r
+  PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;\r
+\r
+  if (PciDeviceInfo->IncludeAllFlag) {\r
+    //\r
+    // Do not register device in other VTD Unit\r
+    //\r
+    for (Index = 0; Index < VtdIndex; Index++) {\r
+      PciDescriptorIndex = GetPciDescriptor (Index, Segment, SourceId);\r
+      if (PciDescriptorIndex != (UINTN)-1) {\r
+        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));\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+  if (PciDescriptorIndex == (UINTN)-1) {\r
+    //\r
+    // Register new\r
+    //\r
+\r
+    if (PciDeviceInfo->PciDescriptorNumber >= PciDeviceInfo->PciDescriptorMaxNumber) {\r
+      //\r
+      // Reallocate\r
+      //\r
+      NewIsRealPciDevice = AllocateZeroPool (sizeof(*NewIsRealPciDevice) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
+      if (NewIsRealPciDevice == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      NewPciDescriptors = AllocateZeroPool (sizeof(*NewPciDescriptors) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));\r
+      if (NewPciDescriptors == NULL) {\r
+        FreePool (NewIsRealPciDevice);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      PciDeviceInfo->PciDescriptorMaxNumber += MAX_PCI_DESCRIPTORS;\r
+      if (PciDeviceInfo->IsRealPciDevice != NULL) {\r
+        CopyMem (NewIsRealPciDevice, PciDeviceInfo->IsRealPciDevice, sizeof(*NewIsRealPciDevice) * PciDeviceInfo->PciDescriptorNumber);\r
+        FreePool (PciDeviceInfo->IsRealPciDevice);\r
+      }\r
+      PciDeviceInfo->IsRealPciDevice = NewIsRealPciDevice;\r
+      if (PciDeviceInfo->PciDescriptors != NULL) {\r
+        CopyMem (NewPciDescriptors, PciDeviceInfo->PciDescriptors, sizeof(*NewPciDescriptors) * PciDeviceInfo->PciDescriptorNumber);\r
+        FreePool (PciDeviceInfo->PciDescriptors);\r
+      }\r
+      PciDeviceInfo->PciDescriptors = NewPciDescriptors;\r
+    }\r
+\r
+    ASSERT (PciDeviceInfo->PciDescriptorNumber < PciDeviceInfo->PciDescriptorMaxNumber);\r
+\r
+    PciDescriptor = &PciDeviceInfo->PciDescriptors[PciDeviceInfo->PciDescriptorNumber];\r
+    PciDescriptor->Bits.Bus = SourceId.Bits.Bus;\r
+    PciDescriptor->Bits.Device = SourceId.Bits.Device;\r
+    PciDescriptor->Bits.Function = SourceId.Bits.Function;\r
+    PciDeviceInfo->IsRealPciDevice[PciDeviceInfo->PciDescriptorNumber] = IsRealPciDevice;\r
+\r
+    PciDeviceInfo->PciDescriptorNumber++;\r
+\r
+    DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
+    if (!IsRealPciDevice) {\r
+      DEBUG ((DEBUG_INFO, " (*)"));\r
+    }\r
+    DEBUG ((DEBUG_INFO, "\n"));\r
+  } else {\r
+    if (CheckExist) {\r
+      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));\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scan PCI bus and register PCI devices under the bus.\r
+\r
+  @param[in]  VtdIndex              The index of VTd engine.\r
+  @param[in]  Segment               The segment of the source.\r
+  @param[in]  Bus                   The bus of the source.\r
+\r
+  @retval EFI_SUCCESS           The PCI devices under the bus are registered.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.\r
+**/\r
+EFI_STATUS\r
+ScanPciBus (\r
+  IN UINTN          VtdIndex,\r
+  IN UINT16         Segment,\r
+  IN UINT8          Bus\r
+  )\r
+{\r
+  UINT8                   Device;\r
+  UINT8                   Function;\r
+  UINT8                   SecondaryBusNumber;\r
+  UINT8                   HeaderType;\r
+  UINT8                   BaseClass;\r
+  UINT8                   SubClass;\r
+  UINT32                  MaxFunction;\r
+  UINT16                  VendorID;\r
+  UINT16                  DeviceID;\r
+  EFI_STATUS              Status;\r
+  VTD_SOURCE_ID           SourceId;\r
+\r
+  // Scan the PCI bus for devices\r
+  for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {\r
+    HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));\r
+    MaxFunction = PCI_MAX_FUNC + 1;\r
+    if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {\r
+      MaxFunction = 1;\r
+    }\r
+    for (Function = 0; Function < MaxFunction; Function++) {\r
+      VendorID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));\r
+      DeviceID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));\r
+      if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {\r
+        continue;\r
+      }\r
+\r
+      SourceId.Bits.Bus = Bus;\r
+      SourceId.Bits.Device = Device;\r
+      SourceId.Bits.Function = Function;\r
+      Status = RegisterPciDevice (VtdIndex, Segment, SourceId, TRUE, FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));\r
+      if (BaseClass == PCI_CLASS_BRIDGE) {\r
+        SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));\r
+        if (SubClass == PCI_CLASS_BRIDGE_P2P) {\r
+          SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+          DEBUG ((DEBUG_INFO,"  ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));\r
+          if (SecondaryBusNumber != 0) {\r
+            Status = ScanPciBus (VtdIndex, Segment, SecondaryBusNumber);\r
+            if (EFI_ERROR (Status)) {\r
+              return Status;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Dump the PCI device information managed by this VTd engine.\r
+\r
+  @param[in]  VtdIndex              The index of VTd engine.\r
+**/\r
+VOID\r
+DumpPciDeviceInfo (\r
+  IN UINTN  VtdIndex\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",\r
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber,\r
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag\r
+    ));\r
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
+    DEBUG ((DEBUG_INFO,"  S%04x B%02x D%02x F%02x\n",\r
+      mVtdUnitInformation[VtdIndex].Segment,\r
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus,\r
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device,\r
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function\r
+      ));\r
+  }\r
+}\r
+\r
+/**\r
+  Find the VTd index by the Segment and SourceId.\r
+\r
+  @param[in]  Segment               The segment of the source.\r
+  @param[in]  SourceId              The SourceId of the source.\r
+  @param[out] ExtContextEntry       The ExtContextEntry of the source.\r
+  @param[out] ContextEntry          The ContextEntry of the source.\r
+\r
+  @return The index of the PCI descriptor.\r
+  @retval (UINTN)-1  The PCI descriptor is not found.\r
+**/\r
+UINTN\r
+FindVtdIndexByPciDevice (\r
+  IN  UINT16                  Segment,\r
+  IN  VTD_SOURCE_ID           SourceId,\r
+  OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,\r
+  OUT VTD_CONTEXT_ENTRY       **ContextEntry\r
+  )\r
+{\r
+  UINTN                   VtdIndex;\r
+  VTD_ROOT_ENTRY          *RootEntry;\r
+  VTD_CONTEXT_ENTRY       *ContextEntryTable;\r
+  VTD_CONTEXT_ENTRY       *ThisContextEntry;\r
+  VTD_EXT_ROOT_ENTRY      *ExtRootEntry;\r
+  VTD_EXT_CONTEXT_ENTRY   *ExtContextEntryTable;\r
+  VTD_EXT_CONTEXT_ENTRY   *ThisExtContextEntry;\r
+  UINTN                   PciDescriptorIndex;\r
+\r
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
+    if (Segment != mVtdUnitInformation[VtdIndex].Segment) {\r
+      continue;\r
+    }\r
+\r
+    PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);\r
+    if (PciDescriptorIndex == (UINTN)-1) {\r
+      continue;\r
+    }\r
+\r
+//    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));\r
+\r
+    if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {\r
+      ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];\r
+      ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)LShiftU64 (ExtRootEntry->Bits.LowerContextTablePointer, 12) ;\r
+      ThisExtContextEntry  = &ExtContextEntryTable[SourceId.Index.ContextIndex];\r
+      if (ThisExtContextEntry->Bits.AddressWidth == 0) {\r
+        continue;\r
+      }\r
+      *ExtContextEntry = ThisExtContextEntry;\r
+      *ContextEntry    = NULL;\r
+    } else {\r
+      RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
+      ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)LShiftU64 (RootEntry->Bits.ContextTablePointer, 12) ;\r
+      ThisContextEntry  = &ContextEntryTable[SourceId.Index.ContextIndex];\r
+      if (ThisContextEntry->Bits.AddressWidth == 0) {\r
+        continue;\r
+      }\r
+      *ExtContextEntry = NULL;\r
+      *ContextEntry    = ThisContextEntry;\r
+    }\r
+\r
+    return VtdIndex;\r
+  }\r
+\r
+  return (UINTN)-1;\r
+}\r
+\r