MdeModulePkg/PciHostBridge: Add IOMMU support.
authorJiewen Yao <jiewen.yao@intel.com>
Sat, 29 Apr 2017 08:23:58 +0000 (16:23 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Wed, 17 May 2017 08:05:15 +0000 (16:05 +0800)
If IOMMU protocol is installed, PciHostBridge just calls
IOMMU AllocateBuffer/FreeBuffer/Map/Unmap.

PciHostBridge does not set IOMMU access attribute,
because it does not know which device request the DMA.
This work is done by PciBus driver.

Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Leo Duran <leo.duran@amd.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Previous patch Tested-by: Brijesh Singh <brijesh.singh@amd.com>
Previous patch Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Leo Duran <leo.duran@amd.com>
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c

index 9005dee..70726a6 100644 (file)
@@ -28,6 +28,10 @@ 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        *mIoMmuProtocol;\r
+EFI_EVENT                   mIoMmuEvent;\r
+VOID                        *mIoMmuRegistration;\r
+\r
 /**\r
   Ensure the compatibility of an IO space descriptor with the IO aperture.\r
 \r
@@ -312,6 +316,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 **)&mIoMmuProtocol);\r
+  if (!EFI_ERROR(Status)) {\r
+    gBS->CloseEvent (mIoMmuEvent);\r
+  }\r
+}\r
+\r
 /**\r
 \r
   Entry point of this driver.\r
@@ -489,6 +515,17 @@ InitializePciHostBridge (
     ASSERT_EFI_ERROR (Status);\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
index d8b0439..42bd8a2 100644 (file)
@@ -41,6 +41,7 @@
   BaseMemoryLib\r
   BaseLib\r
   PciSegmentLib\r
+  UefiLib\r
   PciHostBridgeLib\r
 \r
 [Protocols]\r
@@ -49,6 +50,7 @@
   gEfiDevicePathProtocolGuid                      ## BY_START\r
   gEfiPciRootBridgeIoProtocolGuid                 ## BY_START\r
   gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START\r
+  gEdkiiIoMmuProtocolGuid                         ## SOMETIMES_CONSUMES\r
 \r
 [Depex]\r
   gEfiCpuIo2ProtocolGuid AND\r
index 13185b4..1fec88b 100644 (file)
@@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/CpuIo2.h>\r
 #include <Protocol/DevicePath.h>\r
 #include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/IoMmu.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/DevicePathLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
@@ -34,6 +35,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/PciSegmentLib.h>\r
+#include <Library/UefiLib.h>\r
 #include "PciHostResource.h"\r
 \r
 \r
index 8af131b..068295b 100644 (file)
@@ -17,6 +17,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "PciRootBridge.h"\r
 #include "PciHostResource.h"\r
 \r
+extern EDKII_IOMMU_PROTOCOL        *mIoMmuProtocol;\r
+\r
 #define NO_MAPPING  (VOID *) (UINTN) -1\r
 \r
 //\r
@@ -1072,6 +1074,26 @@ RootBridgeIoMap (
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
+  if (mIoMmuProtocol != NULL) {\r
+    if (!RootBridge->DmaAbove4G) {\r
+      //\r
+      // Clear 64bit support\r
+      //\r
+      if (Operation > EfiPciOperationBusMasterCommonBuffer) {\r
+        Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);\r
+      }\r
+    }\r
+    Status = mIoMmuProtocol->Map (\r
+                               mIoMmuProtocol,\r
+                               Operation,\r
+                               HostAddress,\r
+                               NumberOfBytes,\r
+                               DeviceAddress,\r
+                               Mapping\r
+                               );\r
+    return Status;\r
+  }\r
+\r
   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
   if ((!RootBridge->DmaAbove4G ||\r
        (Operation != EfiPciOperationBusMasterRead64 &&\r
@@ -1194,8 +1216,18 @@ RootBridgeIoUnmap (
   MAP_INFO                 *MapInfo;\r
   LIST_ENTRY               *Link;\r
   PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
+  EFI_STATUS                Status;\r
+\r
+  if (mIoMmuProtocol != NULL) {\r
+    Status = mIoMmuProtocol->Unmap (\r
+                               mIoMmuProtocol,\r
+                               Mapping\r
+                               );\r
+    return Status;\r
+  }\r
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+\r
   //\r
   // See if the Map() operation associated with this Unmap() required a mapping\r
   // buffer. If a mapping buffer was not required, then this function simply\r
@@ -1312,6 +1344,24 @@ RootBridgeIoAllocateBuffer (
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
+  if (mIoMmuProtocol != NULL) {\r
+    if (!RootBridge->DmaAbove4G) {\r
+      //\r
+      // Clear DUAL_ADDRESS_CYCLE\r
+      //\r
+      Attributes &= ~EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
+    }\r
+    Status = mIoMmuProtocol->AllocateBuffer (\r
+                               mIoMmuProtocol,\r
+                               Type,\r
+                               MemoryType,\r
+                               Pages,\r
+                               HostAddress,\r
+                               Attributes\r
+                               );\r
+    return Status;\r
+  }\r
+\r
   AllocateType = AllocateAnyPages;\r
   if (!RootBridge->DmaAbove4G ||\r
       (Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
@@ -1356,6 +1406,17 @@ RootBridgeIoFreeBuffer (
   OUT VOID                             *HostAddress\r
   )\r
 {\r
+  EFI_STATUS                Status;\r
+\r
+  if (mIoMmuProtocol != NULL) {\r
+    Status = mIoMmuProtocol->FreeBuffer (\r
+                               mIoMmuProtocol,\r
+                               Pages,\r
+                               HostAddress\r
+                               );\r
+    return Status;\r
+  }\r
+\r
   return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\r
 }\r
 \r