]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AhciPei / DmaMem.c
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c b/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
new file mode 100644 (file)
index 0000000..098b02c
--- /dev/null
@@ -0,0 +1,270 @@
+/** @file\r
+  The DMA memory help function.\r
+\r
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions\r
+  of the BSD License which accompanies this distribution.  The\r
+  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 "AhciPei.h"\r
+\r
+/**\r
+  Get IOMMU PPI.\r
+\r
+  @return Pointer to IOMMU PPI.\r
+\r
+**/\r
+EDKII_IOMMU_PPI *\r
+GetIoMmu (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  EDKII_IOMMU_PPI    *IoMmu;\r
+\r
+  IoMmu  = NULL;\r
+  Status = PeiServicesLocatePpi (\r
+             &gEdkiiIoMmuPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &IoMmu\r
+             );\r
+  if (!EFI_ERROR (Status) && (IoMmu != NULL)) {\r
+    return IoMmu;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Provides the controller-specific addresses required to access system memory from a\r
+  DMA bus master.\r
+\r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
+                                access the hosts HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuMap (\r
+  IN  EDKII_IOMMU_OPERATION Operation,\r
+  IN VOID                   *HostAddress,\r
+  IN  OUT UINTN             *NumberOfBytes,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **Mapping\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  UINT64             Attribute;\r
+  EDKII_IOMMU_PPI    *IoMmu;\r
+\r
+  IoMmu = GetIoMmu ();\r
+\r
+  if (IoMmu != NULL) {\r
+    Status = IoMmu->Map (\r
+                     IoMmu,\r
+                     Operation,\r
+                     HostAddress,\r
+                     NumberOfBytes,\r
+                     DeviceAddress,\r
+                     Mapping\r
+                     );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    switch (Operation) {\r
+    case EdkiiIoMmuOperationBusMasterRead:\r
+    case EdkiiIoMmuOperationBusMasterRead64:\r
+      Attribute = EDKII_IOMMU_ACCESS_READ;\r
+      break;\r
+    case EdkiiIoMmuOperationBusMasterWrite:\r
+    case EdkiiIoMmuOperationBusMasterWrite64:\r
+      Attribute = EDKII_IOMMU_ACCESS_WRITE;\r
+      break;\r
+    case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+    case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+      Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;\r
+      break;\r
+    default:\r
+      ASSERT(FALSE);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    Status = IoMmu->SetAttribute (\r
+                      IoMmu,\r
+                      *Mapping,\r
+                      Attribute\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
+    *Mapping = NULL;\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Completes the Map() operation and releases any corresponding resources.\r
+\r
+  @param  Mapping               The mapping value returned from Map().\r
+\r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+**/\r
+EFI_STATUS\r
+IoMmuUnmap (\r
+  IN VOID                  *Mapping\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  EDKII_IOMMU_PPI    *IoMmu;\r
+\r
+  IoMmu = GetIoMmu ();\r
+\r
+  if (IoMmu != NULL) {\r
+    Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+    Status = IoMmu->Unmap (IoMmu, Mapping);\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+  OperationBusMasterCommonBuffer64 mapping.\r
+\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
+                                access the hosts HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+  IN UINTN                  Pages,\r
+  OUT VOID                  **HostAddress,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **Mapping\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 NumberOfBytes;\r
+  EFI_PHYSICAL_ADDRESS  HostPhyAddress;\r
+  EDKII_IOMMU_PPI       *IoMmu;\r
+\r
+  *HostAddress = NULL;\r
+  *DeviceAddress = 0;\r
+\r
+  IoMmu = GetIoMmu ();\r
+\r
+  if (IoMmu != NULL) {\r
+    Status = IoMmu->AllocateBuffer (\r
+                      IoMmu,\r
+                      EfiBootServicesData,\r
+                      Pages,\r
+                      HostAddress,\r
+                      0\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);\r
+    Status = IoMmu->Map (\r
+                      IoMmu,\r
+                      EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+                      *HostAddress,\r
+                      &NumberOfBytes,\r
+                      DeviceAddress,\r
+                      Mapping\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = IoMmu->SetAttribute (\r
+                      IoMmu,\r
+                      *Mapping,\r
+                      EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesData,\r
+               Pages,\r
+               &HostPhyAddress\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    *HostAddress = (VOID *)(UINTN)HostPhyAddress;\r
+    *DeviceAddress = HostPhyAddress;\r
+    *Mapping = NULL;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Frees memory that was allocated with AllocateBuffer().\r
+\r
+  @param  Pages                 The number of pages to free.\r
+  @param  HostAddress           The base system memory address of the allocated range.\r
+  @param  Mapping               The mapping value returned from Map().\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with AllocateBuffer().\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuFreeBuffer (\r
+  IN UINTN                  Pages,\r
+  IN VOID                   *HostAddress,\r
+  IN VOID                   *Mapping\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  EDKII_IOMMU_PPI    *IoMmu;\r
+\r
+  IoMmu = GetIoMmu ();\r
+\r
+  if (IoMmu != NULL) {\r
+    Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+    Status = IoMmu->Unmap (IoMmu, Mapping);\r
+    Status = IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r