The responsibility of PciBus driver is to set IOMMU attribute,
because only PciBus knows which device submits DMA access request.

PciBus driver assumes that PciHostBridge driver can allocate
IOMMU page aligned memory, if IOMMU protocol exists.

Cc: Ruiyu Ni <ruiyu...@intel.com>
Cc: Leo Duran <leo.du...@amd.com>
Cc: Brijesh Singh <brijesh.si...@amd.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen....@intel.com>
---
 MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c      |  12 +++
 MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h      |  10 ++
 MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf |   1 +
 MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c       | 100 ++++++++++++++++++++
 4 files changed, 123 insertions(+)

diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c 
b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
index f3be47a..c9ee4de 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
@@ -42,6 +42,8 @@ UINT64                                        gAllZero        
     = 0;
 
 EFI_PCI_PLATFORM_PROTOCOL                     *gPciPlatformProtocol;
 EFI_PCI_OVERRIDE_PROTOCOL                     *gPciOverrideProtocol;
+EDKII_IOMMU_PROTOCOL                          *gIoMmuProtocol;
+UINTN                                         mIoMmuPageSize = 1;
 
 
 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL 
mPciHotPlugRequest = {
@@ -256,6 +258,16 @@ PciBusDriverBindingStart (
   }
 
   gBS->LocateProtocol (
+        &gEdkiiIoMmuProtocolGuid,
+        NULL,
+        (VOID **) &gIoMmuProtocol
+        );
+  if (gIoMmuProtocol != NULL) {
+    gIoMmuProtocol->GetPageSize (gIoMmuProtocol, &mIoMmuPageSize);
+    ASSERT ((mIoMmuPageSize & (mIoMmuPageSize - 1)) == 0);
+  }
+
+  gBS->LocateProtocol (
          &gEfiIncompatiblePciDeviceSupportProtocolGuid,
          NULL,
          (VOID **) &gIncompatiblePciDeviceSupport
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h 
b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
index 39ba8b9..6f96696 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
@@ -32,6 +32,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 #include <Protocol/IncompatiblePciDeviceSupport.h>
 #include <Protocol/PciOverride.h>
 #include <Protocol/PciEnumerationComplete.h>
+#include <Protocol/IoMmu.h>
 
 #include <Library/DebugLib.h>
 #include <Library/UefiDriverEntryPoint.h>
@@ -304,6 +305,13 @@ struct _PCI_IO_DEVICE {
   CR (a, PCI_IO_DEVICE, LoadFile2, PCI_IO_DEVICE_SIGNATURE)
 
 
+#define PCI_IO_MAP_INFO_SIGNATURE  SIGNATURE_32 ('p', 'm', 'a', 'p')
+typedef struct {
+  UINT32                                    Signature;
+  UINTN                                     NumberOfBytes;
+  EFI_PHYSICAL_ADDRESS                      DeviceAddress;
+  VOID                                      *PciRootBridgeIoMapping;
+} PCI_IO_MAP_INFO;
 
 //
 // Global Variables
@@ -319,6 +327,8 @@ extern UINT64                                       gAllOne;
 extern UINT64                                       gAllZero;
 extern EFI_PCI_PLATFORM_PROTOCOL                    *gPciPlatformProtocol;
 extern EFI_PCI_OVERRIDE_PROTOCOL                    *gPciOverrideProtocol;
+extern EDKII_IOMMU_PROTOCOL                         *gIoMmuProtocol;
+extern UINTN                                        mIoMmuPageSize;
 extern BOOLEAN                                      mReserveIsaAliases;
 extern BOOLEAN                                      mReserveVgaAliases;
 
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf 
b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
index a3ab11f..5da094f 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
@@ -95,6 +95,7 @@
   gEfiPciRootBridgeIoProtocolGuid                 ## TO_START
   gEfiIncompatiblePciDeviceSupportProtocolGuid    ## SOMETIMES_CONSUMES
   gEfiLoadFile2ProtocolGuid                       ## SOMETIMES_PRODUCES
+  gEdkiiIoMmuProtocolGuid                         ## SOMETIMES_CONSUMES
 
 [FeaturePcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport      ## CONSUMES
diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c 
b/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
index f72598d..01786c1 100644
--- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
+++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
@@ -967,6 +967,8 @@ PciIoMap (
 {
   EFI_STATUS    Status;
   PCI_IO_DEVICE *PciIoDevice;
+  PCI_IO_MAP_INFO       *PciIoMapInfo;
+  UINT64                IoMmuAttribute;
 
   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
 
@@ -999,6 +1001,46 @@ PciIoMap (
       );
   }
 
+  if (gIoMmuProtocol != NULL) {
+    if (!EFI_ERROR(Status)) {
+      PciIoMapInfo = AllocatePool (sizeof(*PciIoMapInfo));
+      if (PciIoMapInfo == NULL) {
+        PciIoDevice->PciRootBridgeIo->Unmap (PciIoDevice->PciRootBridgeIo, 
*Mapping);
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      PciIoMapInfo->Signature              = PCI_IO_MAP_INFO_SIGNATURE;
+      PciIoMapInfo->NumberOfBytes          = *NumberOfBytes;
+      PciIoMapInfo->DeviceAddress          = *DeviceAddress;
+      PciIoMapInfo->PciRootBridgeIoMapping = *Mapping;
+      *Mapping = PciIoMapInfo;
+
+      switch (Operation) {
+      case EfiPciIoOperationBusMasterRead:
+        IoMmuAttribute = EDKII_IOMMU_ATTRIBUTE_READ;
+        break;
+      case EfiPciIoOperationBusMasterWrite:
+        IoMmuAttribute = EDKII_IOMMU_ATTRIBUTE_WRITE;
+        break;
+      case EfiPciIoOperationBusMasterCommonBuffer:
+        IoMmuAttribute = EDKII_IOMMU_ATTRIBUTE_READ | 
EDKII_IOMMU_ATTRIBUTE_WRITE;
+        break;
+      default:
+        ASSERT(FALSE);
+        return Status;
+      }
+      //
+      // PciHostBridge should map IOMMU page aligned HostAddress.
+      //
+      gIoMmuProtocol->SetAttribute (
+                        gIoMmuProtocol,
+                        PciIoDevice->Handle,
+                        PciIoMapInfo->DeviceAddress,
+                        ALIGN_VALUE(PciIoMapInfo->NumberOfBytes, 
mIoMmuPageSize),
+                        IoMmuAttribute
+                        );
+    }
+  }
   return Status;
 }
 
@@ -1021,9 +1063,19 @@ PciIoUnmap (
 {
   EFI_STATUS    Status;
   PCI_IO_DEVICE *PciIoDevice;
+  PCI_IO_MAP_INFO *PciIoMapInfo;
 
   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
 
+  PciIoMapInfo = NULL;
+  if (gIoMmuProtocol != NULL) {
+    PciIoMapInfo = Mapping;
+    if (PciIoMapInfo->Signature != PCI_IO_MAP_INFO_SIGNATURE) {
+      return EFI_INVALID_PARAMETER;
+    }
+    Mapping = PciIoMapInfo->PciRootBridgeIoMapping;
+  }
+
   Status = PciIoDevice->PciRootBridgeIo->Unmap (
                                           PciIoDevice->PciRootBridgeIo,
                                           Mapping
@@ -1037,6 +1089,22 @@ PciIoUnmap (
       );
   }
 
+  if (gIoMmuProtocol != NULL) {
+    if (!EFI_ERROR(Status)) {
+      //
+      // PciHostBridge should map IOMMU page aligned HostAddress.
+      //
+      gIoMmuProtocol->SetAttribute (
+                        gIoMmuProtocol,
+                        PciIoDevice->Handle,
+                        PciIoMapInfo->DeviceAddress,
+                        ALIGN_VALUE(PciIoMapInfo->NumberOfBytes, 
mIoMmuPageSize),
+                        0
+                        );
+      FreePool (PciIoMapInfo);
+    }
+  }
+
   return Status;
 }
 
@@ -1073,6 +1141,7 @@ PciIoAllocateBuffer (
 {
   EFI_STATUS    Status;
   PCI_IO_DEVICE *PciIoDevice;
+  UINTN         Size;
 
   if ((Attributes &
       (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | 
EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) != 0){
@@ -1102,6 +1171,21 @@ PciIoAllocateBuffer (
       );
   }
 
+  if (gIoMmuProtocol != NULL) {
+    if (!EFI_ERROR(Status)) {
+      //
+      // PciHostBridge should allocate IOMMU page aligned HostAddress.
+      //
+      Size = EFI_PAGES_TO_SIZE(Pages);
+      gIoMmuProtocol->SetAttribute (
+                        gIoMmuProtocol,
+                        PciIoDevice->Handle,
+                        (UINTN)*HostAddress,
+                        ALIGN_VALUE(Size, mIoMmuPageSize),
+                        EDKII_IOMMU_ATTRIBUTE_READ | 
EDKII_IOMMU_ATTRIBUTE_WRITE
+                        );
+    }
+  }
   return Status;
 }
 
@@ -1127,6 +1211,7 @@ PciIoFreeBuffer (
 {
   EFI_STATUS    Status;
   PCI_IO_DEVICE *PciIoDevice;
+  UINTN         Size;
 
   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
 
@@ -1144,6 +1229,21 @@ PciIoFreeBuffer (
       );
   }
 
+  if (gIoMmuProtocol != NULL) {
+    if (!EFI_ERROR(Status)) {
+      //
+      // PciHostBridge should allocate IOMMU page aligned HostAddress.
+      //
+      Size = EFI_PAGES_TO_SIZE(Pages);
+      gIoMmuProtocol->SetAttribute (
+                        gIoMmuProtocol,
+                        PciIoDevice->Handle,
+                        (UINTN)HostAddress,
+                        ALIGN_VALUE(Size, mIoMmuPageSize),
+                        0
+                        );
+    }
+  }
   return Status;
 }
 
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to