Add DMA Lib for generic ARM cache coherency model.
authorandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>
Sat, 29 May 2010 00:34:43 +0000 (00:34 +0000)
committerandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>
Sat, 29 May 2010 00:34:43 +0000 (00:34 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10556 6f19259b-4bc3-4df7-8a09-765794883524

ArmPkg/Library/ArmDmaLib/ArmDmaLib.c [new file with mode: 0755]
ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf [new file with mode: 0755]

diff --git a/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c b/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c
new file mode 100755 (executable)
index 0000000..9467fa5
--- /dev/null
@@ -0,0 +1,269 @@
+/** @file\r
+  Generic ARM implementation of DmaLib.h\r
+\r
+  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+  \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 <Base.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DmaLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UncachedMemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/ArmLib.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS      HostAddress;\r
+  EFI_PHYSICAL_ADDRESS      DeviceAddress;\r
+  UINTN                     NumberOfBytes;\r
+  DMA_MAP_OPERATION         Operation;\r
+  BOOLEAN                   DoubleBuffer;\r
+} MAP_INFO_INSTANCE;\r
+\r
+\r
+\r
+EFI_CPU_ARCH_PROTOCOL      *gCpu;\r
+UINTN                      gCacheAlignment = 0;\r
+\r
+\r
+\r
+\r
+/**                                                                 \r
+  Provides the DMA controller-specific addresses needed to access system memory.\r
+  \r
+  Operation is relative to the 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 DMA 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 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
+EFIAPI\r
+DmaMap (\r
+  IN     DMA_MAP_OPERATION              Operation,\r
+  IN     VOID                           *HostAddress,\r
+  IN OUT UINTN                          *NumberOfBytes,\r
+  OUT    PHYSICAL_ADDRESS               *DeviceAddress,\r
+  OUT    VOID                           **Mapping\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  MAP_INFO_INSTANCE     *Map;\r
+  VOID                  *Buffer;\r
+\r
+  if ( HostAddress == NULL || NumberOfBytes == NULL || \r
+       DeviceAddress == NULL || Mapping == NULL ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+\r
+  if (Operation >= MapOperationMaximum) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *DeviceAddress = ConvertToPhysicalAddress (HostAddress);\r
+\r
+  // Remember range so we can flush on the other side\r
+  Map = AllocatePool (sizeof (MAP_INFO_INSTANCE));\r
+  if (Map == NULL) {\r
+    return  EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  *Mapping = Map;\r
+\r
+  if (((UINTN)HostAddress & (gCacheAlignment - 1)) != 0) {\r
+    Map->DoubleBuffer  = TRUE;\r
+    Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
+    *DeviceAddress = (PHYSICAL_ADDRESS)(UINTN)Buffer;\r
+    \r
+  } else {\r
+    Map->DoubleBuffer  = FALSE;\r
+  }\r
+\r
+  *NumberOfBytes &= *NumberOfBytes & ~(gCacheAlignment - 1); // Only do it on full cache lines\r
+  \r
+  Map->HostAddress   = (UINTN)HostAddress;\r
+  Map->DeviceAddress = *DeviceAddress;\r
+  Map->NumberOfBytes = *NumberOfBytes;\r
+  Map->Operation     = Operation;\r
+\r
+  if (Map->DoubleBuffer) {\r
+    if (Map->Operation == MapOperationBusMasterWrite) {\r
+      CopyMem ((VOID *)(UINTN)Map->DeviceAddress, (VOID *)(UINTN)Map->HostAddress, Map->NumberOfBytes);\r
+    }\r
+  } else {\r
+    // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate\r
+    if (Map->Operation == MapOperationBusMasterWrite || Map->Operation == MapOperationBusMasterRead) {\r
+      gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,  Map->NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);\r
+    }\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**                                                                 \r
+  Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or DmaMapBusMasterCommonBuffer()\r
+  operation and releases any corresponding resources.\r
+            \r
+  @param  Mapping               The mapping value returned from DmaMap*().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+                                   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaUnmap (\r
+  IN  VOID                         *Mapping\r
+  )\r
+{\r
+  MAP_INFO_INSTANCE *Map;\r
+  \r
+  if (Mapping == NULL) {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  Map = (MAP_INFO_INSTANCE *)Mapping;\r
+  \r
+  if (Map->DoubleBuffer) {\r
+    if (Map->Operation == MapOperationBusMasterRead) {\r
+      CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes);\r
+    }\r
+    \r
+    DmaFreeBuffer (EFI_SIZE_TO_PAGES (Map->NumberOfBytes), (VOID *)(UINTN)Map->DeviceAddress);\r
+  \r
+  } else {\r
+    if (Map->Operation == MapOperationBusMasterWrite) {\r
+      //\r
+      // Make sure we read buffer from uncached memory and not the cache\r
+      //\r
+      gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
+    }\r
+  }\r
+  \r
+  FreePool (Map);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**                                                                 \r
+  Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer.\r
+  mapping.                                                                       \r
+            \r
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
+                                EfiRuntimeServicesData.                               \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
+\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
+EFIAPI\r
+DmaAllocateBuffer (\r
+  IN  EFI_MEMORY_TYPE              MemoryType,\r
+  IN  UINTN                        Pages,\r
+  OUT VOID                         **HostAddress\r
+  )\r
+{\r
+  if (HostAddress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData\r
+  //\r
+  // We used uncached memory to keep coherency\r
+  //\r
+  if (MemoryType == EfiBootServicesData) {\r
+    *HostAddress = UncachedAllocatePages (Pages);\r
+  } else if (MemoryType != EfiRuntimeServicesData) {\r
+    *HostAddress = UncachedAllocateRuntimePages (Pages);\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**                                                                 \r
+  Frees memory that was allocated with DmaAllocateBuffer().\r
+            \r
+  @param  Pages                 The number of pages to free.                                \r
+  @param  HostAddress           The base system memory address of the allocated range.                                    \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 DmaAllocateBuffer().\r
+                                     \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaFreeBuffer (\r
+  IN  UINTN                        Pages,\r
+  IN  VOID                         *HostAddress\r
+  )\r
+{\r
+  if (HostAddress == NULL) {\r
+     return EFI_INVALID_PARAMETER;\r
+  } \r
+  \r
+  UncachedFreePages (HostAddress, Pages);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ArmDmaLibConstructor (\r
+  IN EFI_HANDLE       ImageHandle,\r
+  IN EFI_SYSTEM_TABLE *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  // Get the Cpu protocol for later use\r
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  gCacheAlignment = ArmDataCacheLineLength ();\r
+  \r
+  return Status;\r
+}\r
+\r
diff --git a/ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf b/ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf
new file mode 100755 (executable)
index 0000000..5c809ba
--- /dev/null
@@ -0,0 +1,50 @@
+#/** @file\r
+#  \r
+#  Copyright (c) 2008 - 2010, Apple Inc. 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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = ArmDmaLib\r
+  FILE_GUID                      = F1BD6B36-B705-43aa-8A28-33F58ED85EFB\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = DmaLib \r
+  CONSTRUCTOR                    = ArmDmaLibConstructor\r
+\r
+[Sources.common]\r
+  ArmDmaLib.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  ArmPkg/ArmPkg.dec\r
+  \r
+\r
+[LibraryClasses]\r
+  DebugLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  UncachedMemoryAllocationLib\r
+  IoLib\r
+  BaseMemoryLib\r
+  ArmLib\r
+  \r
+  \r
+[Protocols]\r
+  gEfiCpuArchProtocolGuid\r
+  \r
+[Guids]\r
\r
+[Pcd]\r
+\r
+[Depex]\r
+  gEfiCpuArchProtocolGuid
\ No newline at end of file