]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
MdeModulePkg: Reproduce builds across source format changes
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / DmaMem.c
CommitLineData
b575ca32
JY
1/** @file\r
2The DMA memory help function.\r
3\r
4Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
5\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
b575ca32
JY
7\r
8**/\r
9\r
10#include "XhcPeim.h"\r
11\r
12EDKII_IOMMU_PPI *mIoMmu;\r
13\r
14/**\r
15 Provides the controller-specific addresses required to access system memory from a\r
16 DMA bus master.\r
17\r
18 @param Operation Indicates if the bus master is going to read or write to system memory.\r
19 @param HostAddress The system memory address to map to the PCI controller.\r
20 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
21 that were mapped.\r
22 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
23 access the hosts HostAddress.\r
24 @param Mapping A resulting value to pass to Unmap().\r
25\r
26 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
27 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
28 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
29 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
30 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
31\r
32**/\r
33EFI_STATUS\r
34IoMmuMap (\r
35 IN EDKII_IOMMU_OPERATION Operation,\r
36 IN VOID *HostAddress,\r
37 IN OUT UINTN *NumberOfBytes,\r
38 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
39 OUT VOID **Mapping\r
40 )\r
41{\r
42 EFI_STATUS Status;\r
43 UINT64 Attribute;\r
44\r
45 if (mIoMmu != NULL) {\r
46 Status = mIoMmu->Map (\r
47 mIoMmu,\r
48 Operation,\r
49 HostAddress,\r
50 NumberOfBytes,\r
51 DeviceAddress,\r
52 Mapping\r
53 );\r
54 if (EFI_ERROR (Status)) {\r
55 return EFI_OUT_OF_RESOURCES;\r
56 }\r
57 switch (Operation) {\r
58 case EdkiiIoMmuOperationBusMasterRead:\r
59 case EdkiiIoMmuOperationBusMasterRead64:\r
60 Attribute = EDKII_IOMMU_ACCESS_READ;\r
61 break;\r
62 case EdkiiIoMmuOperationBusMasterWrite:\r
63 case EdkiiIoMmuOperationBusMasterWrite64:\r
64 Attribute = EDKII_IOMMU_ACCESS_WRITE;\r
65 break;\r
66 case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
67 case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
68 Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;\r
69 break;\r
70 default:\r
71 ASSERT(FALSE);\r
72 return EFI_INVALID_PARAMETER;\r
73 }\r
74 Status = mIoMmu->SetAttribute (\r
75 mIoMmu,\r
76 *Mapping,\r
77 Attribute\r
78 );\r
79 if (EFI_ERROR (Status)) {\r
80 return Status;\r
81 }\r
82 } else {\r
83 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
84 *Mapping = NULL;\r
85 Status = EFI_SUCCESS;\r
86 }\r
87 return Status;\r
88}\r
89\r
90/**\r
91 Completes the Map() operation and releases any corresponding resources.\r
92\r
93 @param Mapping The mapping value returned from Map().\r
94\r
95 @retval EFI_SUCCESS The range was unmapped.\r
96 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
97 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
98**/\r
99EFI_STATUS\r
100IoMmuUnmap (\r
101 IN VOID *Mapping\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105\r
106 if (mIoMmu != NULL) {\r
107 Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);\r
108 Status = mIoMmu->Unmap (mIoMmu, Mapping);\r
109 } else {\r
110 Status = EFI_SUCCESS;\r
111 }\r
112 return Status;\r
113}\r
114\r
115/**\r
116 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
117 OperationBusMasterCommonBuffer64 mapping.\r
118\r
119 @param Pages The number of pages to allocate.\r
120 @param HostAddress A pointer to store the base system memory address of the\r
121 allocated range.\r
122 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
123 access the hosts HostAddress.\r
124 @param Mapping A resulting value to pass to Unmap().\r
125\r
126 @retval EFI_SUCCESS The requested memory pages were allocated.\r
127 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
128 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
129 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
130 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
131\r
132**/\r
133EFI_STATUS\r
134IoMmuAllocateBuffer (\r
135 IN UINTN Pages,\r
136 OUT VOID **HostAddress,\r
137 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
138 OUT VOID **Mapping\r
139 )\r
140{\r
141 EFI_STATUS Status;\r
142 UINTN NumberOfBytes;\r
143 EFI_PHYSICAL_ADDRESS HostPhyAddress;\r
144\r
145 *HostAddress = NULL;\r
146 *DeviceAddress = 0;\r
147\r
148 if (mIoMmu != NULL) {\r
149 Status = mIoMmu->AllocateBuffer (\r
150 mIoMmu,\r
151 EfiBootServicesData,\r
152 Pages,\r
153 HostAddress,\r
154 0\r
155 );\r
156 if (EFI_ERROR (Status)) {\r
157 return EFI_OUT_OF_RESOURCES;\r
158 }\r
159\r
160 NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);\r
161 Status = mIoMmu->Map (\r
162 mIoMmu,\r
163 EdkiiIoMmuOperationBusMasterCommonBuffer,\r
164 *HostAddress,\r
165 &NumberOfBytes,\r
166 DeviceAddress,\r
167 Mapping\r
168 );\r
169 if (EFI_ERROR (Status)) {\r
170 return EFI_OUT_OF_RESOURCES;\r
171 }\r
172 Status = mIoMmu->SetAttribute (\r
173 mIoMmu,\r
174 *Mapping,\r
175 EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
176 );\r
177 if (EFI_ERROR (Status)) {\r
178 return Status;\r
179 }\r
180 } else {\r
181 Status = PeiServicesAllocatePages (\r
182 EfiBootServicesData,\r
183 Pages,\r
184 &HostPhyAddress\r
185 );\r
186 if (EFI_ERROR (Status)) {\r
187 return EFI_OUT_OF_RESOURCES;\r
188 }\r
189 *HostAddress = (VOID *)(UINTN)HostPhyAddress;\r
190 *DeviceAddress = HostPhyAddress;\r
191 *Mapping = NULL;\r
192 }\r
193 return Status;\r
194}\r
195\r
196/**\r
197 Frees memory that was allocated with AllocateBuffer().\r
198\r
199 @param Pages The number of pages to free.\r
200 @param HostAddress The base system memory address of the allocated range.\r
201 @param Mapping The mapping value returned from Map().\r
202\r
203 @retval EFI_SUCCESS The requested memory pages were freed.\r
204 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
205 was not allocated with AllocateBuffer().\r
206\r
207**/\r
208EFI_STATUS\r
209IoMmuFreeBuffer (\r
210 IN UINTN Pages,\r
211 IN VOID *HostAddress,\r
212 IN VOID *Mapping\r
213 )\r
214{\r
215 EFI_STATUS Status;\r
216\r
217 if (mIoMmu != NULL) {\r
218 Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);\r
219 Status = mIoMmu->Unmap (mIoMmu, Mapping);\r
220 Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);\r
221 } else {\r
222 Status = EFI_SUCCESS;\r
223 }\r
224 return Status;\r
225}\r
226\r
2bbbdeee
AS
227/**\r
228 Allocates aligned pages that are suitable for an OperationBusMasterCommonBuffer or\r
229 OperationBusMasterCommonBuffer64 mapping.\r
230\r
231 @param Pages The number of pages to allocate.\r
232 @param Alignment The requested alignment of the allocation. Must be a power of two.\r
233 @param HostAddress A pointer to store the base system memory address of the\r
234 allocated range.\r
235 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
236 access the hosts HostAddress.\r
237 @param Mapping A resulting value to pass to Unmap().\r
238\r
239 @retval EFI_SUCCESS The requested memory pages were allocated.\r
240 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
241 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
242 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
243 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
244\r
245**/\r
246EFI_STATUS\r
247IoMmuAllocateAlignedBuffer (\r
248 IN UINTN Pages,\r
249 IN UINTN Alignment,\r
250 OUT VOID **HostAddress,\r
251 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
252 OUT VOID **Mapping\r
253 )\r
254{\r
255 EFI_STATUS Status;\r
256 VOID *Memory;\r
257 UINTN AlignedMemory;\r
258 UINTN AlignmentMask;\r
259 UINTN UnalignedPages;\r
260 UINTN RealPages;\r
261 UINTN NumberOfBytes;\r
262 EFI_PHYSICAL_ADDRESS HostPhyAddress;\r
263\r
264 *HostAddress = NULL;\r
265 *DeviceAddress = 0;\r
266 AlignmentMask = Alignment - 1;\r
267\r
268 //\r
269 // Calculate the total number of pages since alignment is larger than page size.\r
270 //\r
271 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
272\r
273 //\r
274 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
275 //\r
276 ASSERT (RealPages > Pages);\r
277\r
278 if (mIoMmu != NULL) {\r
279 Status = mIoMmu->AllocateBuffer (\r
280 mIoMmu,\r
281 EfiBootServicesData,\r
282 RealPages,\r
283 HostAddress,\r
284 0\r
285 );\r
286 if (EFI_ERROR (Status)) {\r
287 return EFI_OUT_OF_RESOURCES;\r
288 }\r
289 Memory = *HostAddress;\r
290 AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
291 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
292 if (UnalignedPages > 0) {\r
293 //\r
294 // Free first unaligned page(s).\r
295 //\r
296 Status = mIoMmu->FreeBuffer (\r
297 mIoMmu,\r
298 UnalignedPages,\r
299 Memory);\r
300 if (EFI_ERROR (Status)) {\r
301 return Status;\r
302 }\r
303 }\r
304 Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
305 UnalignedPages = RealPages - Pages - UnalignedPages;\r
306 if (UnalignedPages > 0) {\r
307 //\r
308 // Free last unaligned page(s).\r
309 //\r
310 Status = mIoMmu->FreeBuffer (\r
311 mIoMmu,\r
312 UnalignedPages,\r
313 Memory);\r
314 if (EFI_ERROR (Status)) {\r
315 return Status;\r
316 }\r
317 }\r
318 *HostAddress = (VOID *) AlignedMemory;\r
319 NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);\r
320 Status = mIoMmu->Map (\r
321 mIoMmu,\r
322 EdkiiIoMmuOperationBusMasterCommonBuffer,\r
323 *HostAddress,\r
324 &NumberOfBytes,\r
325 DeviceAddress,\r
326 Mapping\r
327 );\r
328 if (EFI_ERROR (Status)) {\r
329 return EFI_OUT_OF_RESOURCES;\r
330 }\r
331 Status = mIoMmu->SetAttribute (\r
332 mIoMmu,\r
333 *Mapping,\r
334 EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
335 );\r
336 if (EFI_ERROR (Status)) {\r
337 return Status;\r
338 }\r
339 } else {\r
340 Status = PeiServicesAllocatePages (\r
341 EfiBootServicesData,\r
342 RealPages,\r
343 &HostPhyAddress\r
344 );\r
345 if (EFI_ERROR (Status)) {\r
346 return EFI_OUT_OF_RESOURCES;\r
347 }\r
348 *HostAddress = (VOID *)(((UINTN) HostPhyAddress + AlignmentMask) & ~AlignmentMask);\r
349 *DeviceAddress = ((UINTN) HostPhyAddress + AlignmentMask) & ~AlignmentMask;\r
350 *Mapping = NULL;\r
351 }\r
352 return Status;\r
353}\r
354\r
b575ca32
JY
355/**\r
356 Initialize IOMMU.\r
357**/\r
358VOID\r
359IoMmuInit (\r
360 VOID\r
361 )\r
362{\r
363 PeiServicesLocatePpi (\r
364 &gEdkiiIoMmuPpiGuid,\r
365 0,\r
366 NULL,\r
367 (VOID **)&mIoMmu\r
368 );\r
369}\r
370\r