]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/ArmDmaLib/ArmDmaLib.c
Sync up ArmPkg with patch from mailing list. Changed name of BdsLib.h to BdsUnixLib...
[mirror_edk2.git] / ArmPkg / Library / ArmDmaLib / ArmDmaLib.c
CommitLineData
938f46b4 1/** @file\r
2 Generic ARM implementation of DmaLib.h\r
3\r
4 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
5 \r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Base.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/DmaLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UncachedMemoryAllocationLib.h>\r
22#include <Library/IoLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/ArmLib.h>\r
25\r
26#include <Protocol/Cpu.h>\r
27\r
28typedef struct {\r
29 EFI_PHYSICAL_ADDRESS HostAddress;\r
30 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
31 UINTN NumberOfBytes;\r
32 DMA_MAP_OPERATION Operation;\r
33 BOOLEAN DoubleBuffer;\r
34} MAP_INFO_INSTANCE;\r
35\r
36\r
37\r
38EFI_CPU_ARCH_PROTOCOL *gCpu;\r
39UINTN gCacheAlignment = 0;\r
40\r
41\r
42\r
43\r
44/** \r
45 Provides the DMA controller-specific addresses needed to access system memory.\r
46 \r
47 Operation is relative to the DMA bus master.\r
48 \r
49 @param Operation Indicates if the bus master is going to read or write to system memory.\r
50 @param HostAddress The system memory address to map to the DMA controller.\r
51 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
52 that were mapped. \r
53 @param DeviceAddress The resulting map address for the bus master controller to use to\r
54 access the hosts HostAddress. \r
55 @param Mapping A resulting value to pass to Unmap().\r
56 \r
57 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
58 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. \r
59 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
60 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
61 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
62 \r
63**/\r
64EFI_STATUS\r
65EFIAPI\r
66DmaMap (\r
67 IN DMA_MAP_OPERATION Operation,\r
68 IN VOID *HostAddress,\r
69 IN OUT UINTN *NumberOfBytes,\r
70 OUT PHYSICAL_ADDRESS *DeviceAddress,\r
71 OUT VOID **Mapping\r
72 )\r
73{\r
74 EFI_STATUS Status;\r
75 MAP_INFO_INSTANCE *Map;\r
76 VOID *Buffer;\r
77\r
78 if ( HostAddress == NULL || NumberOfBytes == NULL || \r
79 DeviceAddress == NULL || Mapping == NULL ) {\r
80 return EFI_INVALID_PARAMETER;\r
81 }\r
82 \r
83\r
84 if (Operation >= MapOperationMaximum) {\r
85 return EFI_INVALID_PARAMETER;\r
86 }\r
87\r
88 *DeviceAddress = ConvertToPhysicalAddress (HostAddress);\r
89\r
90 // Remember range so we can flush on the other side\r
91 Map = AllocatePool (sizeof (MAP_INFO_INSTANCE));\r
92 if (Map == NULL) {\r
93 return EFI_OUT_OF_RESOURCES;\r
94 }\r
95 \r
96 *Mapping = Map;\r
97\r
3ea3ff88 98 if ((((UINTN)HostAddress & (gCacheAlignment - 1)) != 0) ||\r
99 ((*NumberOfBytes % gCacheAlignment) != 0)) {\r
100 //\r
101 // If the buffer does not fill entire cache lines we must double buffer into \r
102 // uncached memory. Device (PCI) address becomes uncached page.\r
103 //\r
938f46b4 104 Map->DoubleBuffer = TRUE;\r
105 Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer);\r
106 if (EFI_ERROR (Status)) {\r
107 return Status;\r
108 }\r
109 \r
110 *DeviceAddress = (PHYSICAL_ADDRESS)(UINTN)Buffer;\r
111 \r
112 } else {\r
113 Map->DoubleBuffer = FALSE;\r
114 }\r
115\r
938f46b4 116 Map->HostAddress = (UINTN)HostAddress;\r
117 Map->DeviceAddress = *DeviceAddress;\r
118 Map->NumberOfBytes = *NumberOfBytes;\r
119 Map->Operation = Operation;\r
120\r
121 if (Map->DoubleBuffer) {\r
122 if (Map->Operation == MapOperationBusMasterWrite) {\r
123 CopyMem ((VOID *)(UINTN)Map->DeviceAddress, (VOID *)(UINTN)Map->HostAddress, Map->NumberOfBytes);\r
124 }\r
125 } else {\r
126 // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate\r
127 if (Map->Operation == MapOperationBusMasterWrite || Map->Operation == MapOperationBusMasterRead) {\r
128 gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);\r
129 }\r
130 }\r
131 \r
132 return EFI_SUCCESS;\r
133}\r
134\r
135\r
136/** \r
137 Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or DmaMapBusMasterCommonBuffer()\r
138 operation and releases any corresponding resources.\r
139 \r
140 @param Mapping The mapping value returned from DmaMap*().\r
141 \r
142 @retval EFI_SUCCESS The range was unmapped.\r
143 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
144 \r
145**/\r
146EFI_STATUS\r
147EFIAPI\r
148DmaUnmap (\r
149 IN VOID *Mapping\r
150 )\r
151{\r
152 MAP_INFO_INSTANCE *Map;\r
153 \r
154 if (Mapping == NULL) {\r
155 ASSERT (FALSE);\r
156 return EFI_INVALID_PARAMETER;\r
157 }\r
158 \r
159 Map = (MAP_INFO_INSTANCE *)Mapping;\r
160 \r
161 if (Map->DoubleBuffer) {\r
162 if (Map->Operation == MapOperationBusMasterRead) {\r
163 CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes);\r
164 }\r
165 \r
166 DmaFreeBuffer (EFI_SIZE_TO_PAGES (Map->NumberOfBytes), (VOID *)(UINTN)Map->DeviceAddress);\r
167 \r
168 } else {\r
169 if (Map->Operation == MapOperationBusMasterWrite) {\r
170 //\r
171 // Make sure we read buffer from uncached memory and not the cache\r
172 //\r
173 gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
174 }\r
175 }\r
176 \r
177 FreePool (Map);\r
178\r
179 return EFI_SUCCESS;\r
180}\r
181\r
182/** \r
183 Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer.\r
184 mapping. \r
185 \r
186 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
187 EfiRuntimeServicesData. \r
188 @param Pages The number of pages to allocate. \r
189 @param HostAddress A pointer to store the base system memory address of the\r
190 allocated range. \r
191\r
192 @retval EFI_SUCCESS The requested memory pages were allocated.\r
193 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
194 MEMORY_WRITE_COMBINE and MEMORY_CACHED. \r
195 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
196 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. \r
197 \r
198**/\r
199EFI_STATUS\r
200EFIAPI\r
201DmaAllocateBuffer (\r
202 IN EFI_MEMORY_TYPE MemoryType,\r
203 IN UINTN Pages,\r
204 OUT VOID **HostAddress\r
205 )\r
206{\r
207 if (HostAddress == NULL) {\r
208 return EFI_INVALID_PARAMETER;\r
209 }\r
210\r
211 //\r
212 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData\r
213 //\r
214 // We used uncached memory to keep coherency\r
215 //\r
216 if (MemoryType == EfiBootServicesData) {\r
217 *HostAddress = UncachedAllocatePages (Pages);\r
1bfda055 218 } else if (MemoryType == EfiRuntimeServicesData) {\r
938f46b4 219 *HostAddress = UncachedAllocateRuntimePages (Pages);\r
220 } else {\r
221 return EFI_INVALID_PARAMETER;\r
222 }\r
223\r
224 return EFI_SUCCESS;\r
225}\r
226\r
227\r
228/** \r
229 Frees memory that was allocated with DmaAllocateBuffer().\r
230 \r
231 @param Pages The number of pages to free. \r
232 @param HostAddress The base system memory address of the allocated range. \r
233 \r
234 @retval EFI_SUCCESS The requested memory pages were freed.\r
235 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
236 was not allocated with DmaAllocateBuffer().\r
237 \r
238**/\r
239EFI_STATUS\r
240EFIAPI\r
241DmaFreeBuffer (\r
242 IN UINTN Pages,\r
243 IN VOID *HostAddress\r
244 )\r
245{\r
246 if (HostAddress == NULL) {\r
247 return EFI_INVALID_PARAMETER;\r
248 } \r
249 \r
250 UncachedFreePages (HostAddress, Pages);\r
251 return EFI_SUCCESS;\r
252}\r
253\r
254\r
255EFI_STATUS\r
256EFIAPI\r
257ArmDmaLibConstructor (\r
258 IN EFI_HANDLE ImageHandle,\r
259 IN EFI_SYSTEM_TABLE *SystemTable\r
260 )\r
261{\r
262 EFI_STATUS Status;\r
263\r
264 // Get the Cpu protocol for later use\r
265 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);\r
266 ASSERT_EFI_ERROR(Status);\r
267\r
268 gCacheAlignment = ArmDataCacheLineLength ();\r
269 \r
270 return Status;\r
271}\r
272\r