]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciHostBridge.c
index ef0c4f2a5e7bbbd607844dc120b9c3e51fb68125..4ab9415c96003e56c107011829a082f379db9975 100644 (file)
@@ -2,14 +2,8 @@
 \r
   Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.\r
 \r
-Copyright (c) 1999 - 2016, 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
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -17,8 +11,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "PciRootBridge.h"\r
 #include "PciHostResource.h"\r
 \r
-\r
-EFI_METRONOME_ARCH_PROTOCOL *mMetronome;\r
 EFI_CPU_IO2_PROTOCOL        *mCpuIo;\r
 \r
 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {\r
@@ -28,6 +20,43 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
   L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"\r
 };\r
 \r
+EDKII_IOMMU_PROTOCOL        *mIoMmu;\r
+EFI_EVENT                   mIoMmuEvent;\r
+VOID                        *mIoMmuRegistration;\r
+\r
+/**\r
+  This routine gets translation offset from a root bridge instance by resource type.\r
+\r
+  @param RootBridge The Root Bridge Instance for the resources.\r
+  @param ResourceType The Resource Type of the translation offset.\r
+\r
+  @retval The Translation Offset of the specified resource.\r
+**/\r
+UINT64\r
+GetTranslationByResourceType (\r
+  IN  PCI_ROOT_BRIDGE_INSTANCE     *RootBridge,\r
+  IN  PCI_RESOURCE_TYPE            ResourceType\r
+  )\r
+{\r
+  switch (ResourceType) {\r
+    case TypeIo:\r
+      return RootBridge->Io.Translation;\r
+    case TypeMem32:\r
+      return RootBridge->Mem.Translation;\r
+    case TypePMem32:\r
+      return RootBridge->PMem.Translation;\r
+    case TypeMem64:\r
+      return RootBridge->MemAbove4G.Translation;\r
+    case TypePMem64:\r
+      return RootBridge->PMemAbove4G.Translation;\r
+    case TypeBus:\r
+      return RootBridge->Bus.Translation;\r
+    default:\r
+      ASSERT (FALSE);\r
+      return 0;\r
+  }\r
+}\r
+\r
 /**\r
   Ensure the compatibility of an IO space descriptor with the IO aperture.\r
 \r
@@ -312,6 +341,28 @@ FreeMemorySpaceMap:
   return Status;\r
 }\r
 \r
+/**\r
+  Event notification that is fired when IOMMU protocol is installed.\r
+\r
+  @param  Event                 The Event that is being processed.\r
+  @param  Context               Event Context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IoMmuProtocolCallback (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+  EFI_STATUS   Status;\r
+\r
+  Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);\r
+  if (!EFI_ERROR(Status)) {\r
+    gBS->CloseEvent (mIoMmuEvent);\r
+  }\r
+}\r
+\r
 /**\r
 \r
   Entry point of this driver.\r
@@ -338,14 +389,15 @@ InitializePciHostBridge (
   UINTN                       Index;\r
   PCI_ROOT_BRIDGE_APERTURE    *MemApertures[4];\r
   UINTN                       MemApertureIndex;\r
+  BOOLEAN                     ResourceAssigned;\r
+  LIST_ENTRY                  *Link;\r
+  UINT64                      HostAddress;\r
 \r
   RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);\r
   if ((RootBridges == NULL) || (RootBridgeCount == 0)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);\r
-  ASSERT_EFI_ERROR (Status);\r
   Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -358,27 +410,7 @@ InitializePciHostBridge (
   HostBridge->Signature        = PCI_HOST_BRIDGE_SIGNATURE;\r
   HostBridge->CanRestarted     = TRUE;\r
   InitializeListHead (&HostBridge->RootBridges);\r
-\r
-  HostBridge->ResAlloc.NotifyPhase          = NotifyPhase;\r
-  HostBridge->ResAlloc.GetNextRootBridge    = GetNextRootBridge;\r
-  HostBridge->ResAlloc.GetAllocAttributes   = GetAttributes;\r
-  HostBridge->ResAlloc.StartBusEnumeration  = StartBusEnumeration;\r
-  HostBridge->ResAlloc.SetBusNumbers        = SetBusNumbers;\r
-  HostBridge->ResAlloc.SubmitResources      = SubmitResources;\r
-  HostBridge->ResAlloc.GetProposedResources = GetProposedResources;\r
-  HostBridge->ResAlloc.PreprocessController = PreprocessController;\r
-\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &HostBridge->Handle,\r
-                  &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,\r
-                  NULL\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (HostBridge);\r
-    PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);\r
-    return Status;\r
-  }\r
+  ResourceAssigned             = FALSE;\r
 \r
   //\r
   // Create Root Bridge Device Handle in this Host Bridge\r
@@ -387,18 +419,46 @@ InitializePciHostBridge (
     //\r
     // Create Root Bridge Handle Instance\r
     //\r
-    RootBridge = CreateRootBridge (&RootBridges[Index], HostBridge->Handle);\r
+    RootBridge = CreateRootBridge (&RootBridges[Index]);\r
     ASSERT (RootBridge != NULL);\r
     if (RootBridge == NULL) {\r
       continue;\r
     }\r
 \r
-    if (RootBridges[Index].Io.Limit > RootBridges[Index].Io.Base) {\r
+    //\r
+    // Make sure all root bridges share the same ResourceAssigned value.\r
+    //\r
+    if (Index == 0) {\r
+      ResourceAssigned = RootBridges[Index].ResourceAssigned;\r
+    } else {\r
+      ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);\r
+    }\r
+\r
+    if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {\r
+      //\r
+      // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+      // For GCD resource manipulation, we need to use host address.\r
+      //\r
+      HostAddress = TO_HOST_ADDRESS (RootBridges[Index].Io.Base,\r
+        RootBridges[Index].Io.Translation);\r
+\r
       Status = AddIoSpace (\r
-                 RootBridges[Index].Io.Base,\r
+                 HostAddress,\r
                  RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1\r
                  );\r
       ASSERT_EFI_ERROR (Status);\r
+      if (ResourceAssigned) {\r
+        Status = gDS->AllocateIoSpace (\r
+                        EfiGcdAllocateAddress,\r
+                        EfiGcdIoTypeIo,\r
+                        0,\r
+                        RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,\r
+                        &HostAddress,\r
+                        gImageHandle,\r
+                        NULL\r
+                        );\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
     }\r
 \r
     //\r
@@ -412,25 +472,77 @@ InitializePciHostBridge (
     MemApertures[2] = &RootBridges[Index].PMem;\r
     MemApertures[3] = &RootBridges[Index].PMemAbove4G;\r
 \r
-    for (MemApertureIndex = 0; MemApertureIndex < sizeof (MemApertures) / sizeof (MemApertures[0]); MemApertureIndex++) {\r
-      if (MemApertures[MemApertureIndex]->Limit > MemApertures[MemApertureIndex]->Base) {\r
+    for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {\r
+      if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {\r
+        //\r
+        // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+        // For GCD resource manipulation, we need to use host address.\r
+        //\r
+        HostAddress = TO_HOST_ADDRESS (MemApertures[MemApertureIndex]->Base,\r
+          MemApertures[MemApertureIndex]->Translation);\r
         Status = AddMemoryMappedIoSpace (\r
-                   MemApertures[MemApertureIndex]->Base,\r
+                   HostAddress,\r
                    MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
                    EFI_MEMORY_UC\r
                    );\r
         ASSERT_EFI_ERROR (Status);\r
         Status = gDS->SetMemorySpaceAttributes (\r
-                        MemApertures[MemApertureIndex]->Base,\r
+                        HostAddress,\r
                         MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
                         EFI_MEMORY_UC\r
                         );\r
-        ASSERT_EFI_ERROR (Status);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));\r
+        }\r
+        if (ResourceAssigned) {\r
+          Status = gDS->AllocateMemorySpace (\r
+                          EfiGcdAllocateAddress,\r
+                          EfiGcdMemoryTypeMemoryMappedIo,\r
+                          0,\r
+                          MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
+                          &HostAddress,\r
+                          gImageHandle,\r
+                          NULL\r
+                          );\r
+          ASSERT_EFI_ERROR (Status);\r
+        }\r
       }\r
     }\r
     //\r
     // Insert Root Bridge Handle Instance\r
     //\r
+    InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);\r
+  }\r
+\r
+  //\r
+  // When resources were assigned, it's not needed to expose\r
+  // PciHostBridgeResourceAllocation protocol.\r
+  //\r
+  if (!ResourceAssigned) {\r
+    HostBridge->ResAlloc.NotifyPhase = NotifyPhase;\r
+    HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;\r
+    HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;\r
+    HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;\r
+    HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;\r
+    HostBridge->ResAlloc.SubmitResources = SubmitResources;\r
+    HostBridge->ResAlloc.GetProposedResources = GetProposedResources;\r
+    HostBridge->ResAlloc.PreprocessController = PreprocessController;\r
+\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &HostBridge->Handle,\r
+                    &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  for (Link = GetFirstNode (&HostBridge->RootBridges)\r
+       ; !IsNull (&HostBridge->RootBridges, Link)\r
+       ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
+       ) {\r
+    RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
+    RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;\r
+\r
     Status = gBS->InstallMultipleProtocolInterfaces (\r
                     &RootBridge->Handle,\r
                     &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,\r
@@ -438,9 +550,19 @@ InitializePciHostBridge (
                     NULL\r
                     );\r
     ASSERT_EFI_ERROR (Status);\r
-    InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);\r
   }\r
   PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    mIoMmuEvent = EfiCreateProtocolNotifyEvent (\r
+                    &gEdkiiIoMmuProtocolGuid,\r
+                    TPL_CALLBACK,\r
+                    IoMmuProtocolCallback,\r
+                    NULL,\r
+                    &mIoMmuRegistration\r
+                    );\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -489,7 +611,8 @@ ResourceConflict (
       Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
       Descriptor->AddrRangeMin = ResAllocNode->Base;\r
       Descriptor->AddrRangeMax = ResAllocNode->Alignment;\r
-      Descriptor->AddrLen = ResAllocNode->Length;\r
+      Descriptor->AddrLen      = ResAllocNode->Length;\r
+      Descriptor->SpecificFlag = 0;\r
       switch (ResAllocNode->Type) {\r
 \r
       case TypeIo:\r
@@ -568,6 +691,11 @@ AllocateResource (
   if (BaseAddress < Limit) {\r
     //\r
     // Have to make sure Aligment is handled since we are doing direct address allocation\r
+    // Strictly speaking, alignment requirement should be applied to device\r
+    // address instead of host address which is used in GCD manipulation below,\r
+    // but as we restrict the alignment of Translation to be larger than any BAR\r
+    // alignment in the root bridge, we can simplify the situation and consider\r
+    // the same alignment requirement is also applied to host address.\r
     //\r
     BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));\r
 \r
@@ -626,7 +754,6 @@ NotifyPhase (
   PCI_ROOT_BRIDGE_INSTANCE              *RootBridge;\r
   LIST_ENTRY                            *Link;\r
   EFI_PHYSICAL_ADDRESS                  BaseAddress;\r
-  UINT64                                AddrLen;\r
   UINTN                                 BitsOfAlignment;\r
   UINT64                                Alignment;\r
   EFI_STATUS                            Status;\r
@@ -636,6 +763,7 @@ NotifyPhase (
   PCI_RESOURCE_TYPE                     Index2;\r
   BOOLEAN                               ResNodeHandled[TypeMax];\r
   UINT64                                MaxAlignment;\r
+  UINT64                                Translation;\r
 \r
   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
 \r
@@ -733,19 +861,47 @@ NotifyPhase (
 \r
           ASSERT (Index < TypeMax);\r
           ResNodeHandled[Index] = TRUE;\r
-          AddrLen = RootBridge->ResAllocNode[Index].Length;\r
           Alignment = RootBridge->ResAllocNode[Index].Alignment;\r
           BitsOfAlignment = LowBitSet64 (Alignment + 1);\r
           BaseAddress = MAX_UINT64;\r
 \r
+          //\r
+          // RESTRICTION: To simplify the situation, we require the alignment of\r
+          // Translation must be larger than any BAR alignment in the same root\r
+          // bridge, so that resource allocation alignment can be applied to\r
+          // both device address and host address.\r
+          //\r
+          Translation = GetTranslationByResourceType (RootBridge, Index);\r
+          if ((Translation & Alignment) != 0) {\r
+            DEBUG ((DEBUG_ERROR, "[%a:%d] Translation %lx is not aligned to %lx!\n",\r
+              __FUNCTION__, __LINE__, Translation, Alignment\r
+              ));\r
+            ASSERT ((Translation & Alignment) == 0);\r
+            //\r
+            // This may be caused by too large alignment or too small\r
+            // Translation; pick the 1st possibility and return out of resource,\r
+            // which can also go thru the same process for out of resource\r
+            // outside the loop.\r
+            //\r
+            ReturnStatus = EFI_OUT_OF_RESOURCES;\r
+            continue;\r
+          }\r
+\r
           switch (Index) {\r
           case TypeIo:\r
+            //\r
+            // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+            // For AllocateResource is manipulating GCD resource, we need to use\r
+            // host address here.\r
+            //\r
             BaseAddress = AllocateResource (\r
                             FALSE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (15, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
-                            RootBridge->Io.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
+                              RootBridge->Io.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->Io.Limit,\r
+                              RootBridge->Io.Translation)\r
                             );\r
             break;\r
 \r
@@ -754,8 +910,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (63, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
-                            RootBridge->MemAbove4G.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
+                              RootBridge->MemAbove4G.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->MemAbove4G.Limit,\r
+                              RootBridge->MemAbove4G.Translation)\r
                             );\r
             if (BaseAddress != MAX_UINT64) {\r
               break;\r
@@ -769,8 +927,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (31, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
-                            RootBridge->Mem.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
+                              RootBridge->Mem.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->Mem.Limit,\r
+                              RootBridge->Mem.Translation)\r
                             );\r
             break;\r
 \r
@@ -779,8 +939,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (63, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
-                            RootBridge->PMemAbove4G.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
+                              RootBridge->PMemAbove4G.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->PMemAbove4G.Limit,\r
+                              RootBridge->PMemAbove4G.Translation)\r
                             );\r
             if (BaseAddress != MAX_UINT64) {\r
               break;\r
@@ -793,8 +955,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (31, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
-                            RootBridge->PMem.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
+                              RootBridge->PMem.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->PMem.Limit,\r
+                              RootBridge->PMem.Translation)\r
                             );\r
             break;\r
 \r
@@ -1108,9 +1272,6 @@ SetBusNumbers (
   PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;\r
   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
   EFI_ACPI_END_TAG_DESCRIPTOR       *End;\r
-  UINTN                     BusStart;\r
-  UINTN                     BusEnd;\r
-  UINTN                     BusLen;\r
 \r
   if (Configuration == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1136,9 +1297,6 @@ SetBusNumbers (
        ) {\r
     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
     if (RootBridgeHandle == RootBridge->Handle) {\r
-      BusStart  = (UINTN) Descriptor->AddrRangeMin;\r
-      BusLen    = (UINTN) Descriptor->AddrLen;\r
-      BusEnd    = BusStart + BusLen - 1;\r
 \r
       if (Descriptor->AddrLen == 0) {\r
         return EFI_INVALID_PARAMETER;\r
@@ -1343,7 +1501,14 @@ GetProposedResources (
           Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
           Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;\r
           Descriptor->GenFlag               = 0;\r
-          Descriptor->AddrRangeMin          = RootBridge->ResAllocNode[Index].Base;\r
+          //\r
+          // AddrRangeMin in Resource Descriptor here should be device address\r
+          // instead of host address, or else PCI bus driver cannot set correct\r
+          // address into PCI BAR registers.\r
+          // Base in ResAllocNode is a host address, so conversion is needed.\r
+          //\r
+          Descriptor->AddrRangeMin          = TO_DEVICE_ADDRESS (RootBridge->ResAllocNode[Index].Base,\r
+            GetTranslationByResourceType (RootBridge, Index));\r
           Descriptor->AddrRangeMax          = 0;\r
           Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;\r
           Descriptor->AddrLen               = RootBridge->ResAllocNode[Index].Length;\r