]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
098b02c1a154390b2bd421fd253d4ca5fbb00599
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AhciPei / DmaMem.c
1 /** @file
2 The DMA memory help function.
3
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "AhciPei.h"
18
19 /**
20 Get IOMMU PPI.
21
22 @return Pointer to IOMMU PPI.
23
24 **/
25 EDKII_IOMMU_PPI *
26 GetIoMmu (
27 VOID
28 )
29 {
30 EFI_STATUS Status;
31 EDKII_IOMMU_PPI *IoMmu;
32
33 IoMmu = NULL;
34 Status = PeiServicesLocatePpi (
35 &gEdkiiIoMmuPpiGuid,
36 0,
37 NULL,
38 (VOID **) &IoMmu
39 );
40 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
41 return IoMmu;
42 }
43
44 return NULL;
45 }
46
47 /**
48 Provides the controller-specific addresses required to access system memory from a
49 DMA bus master.
50
51 @param Operation Indicates if the bus master is going to read or write to system memory.
52 @param HostAddress The system memory address to map to the PCI controller.
53 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
54 that were mapped.
55 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
56 access the hosts HostAddress.
57 @param Mapping A resulting value to pass to Unmap().
58
59 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
60 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
61 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
62 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
63 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
64
65 **/
66 EFI_STATUS
67 IoMmuMap (
68 IN EDKII_IOMMU_OPERATION Operation,
69 IN VOID *HostAddress,
70 IN OUT UINTN *NumberOfBytes,
71 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
72 OUT VOID **Mapping
73 )
74 {
75 EFI_STATUS Status;
76 UINT64 Attribute;
77 EDKII_IOMMU_PPI *IoMmu;
78
79 IoMmu = GetIoMmu ();
80
81 if (IoMmu != NULL) {
82 Status = IoMmu->Map (
83 IoMmu,
84 Operation,
85 HostAddress,
86 NumberOfBytes,
87 DeviceAddress,
88 Mapping
89 );
90 if (EFI_ERROR (Status)) {
91 return EFI_OUT_OF_RESOURCES;
92 }
93 switch (Operation) {
94 case EdkiiIoMmuOperationBusMasterRead:
95 case EdkiiIoMmuOperationBusMasterRead64:
96 Attribute = EDKII_IOMMU_ACCESS_READ;
97 break;
98 case EdkiiIoMmuOperationBusMasterWrite:
99 case EdkiiIoMmuOperationBusMasterWrite64:
100 Attribute = EDKII_IOMMU_ACCESS_WRITE;
101 break;
102 case EdkiiIoMmuOperationBusMasterCommonBuffer:
103 case EdkiiIoMmuOperationBusMasterCommonBuffer64:
104 Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
105 break;
106 default:
107 ASSERT(FALSE);
108 return EFI_INVALID_PARAMETER;
109 }
110 Status = IoMmu->SetAttribute (
111 IoMmu,
112 *Mapping,
113 Attribute
114 );
115 if (EFI_ERROR (Status)) {
116 return Status;
117 }
118 } else {
119 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
120 *Mapping = NULL;
121 Status = EFI_SUCCESS;
122 }
123 return Status;
124 }
125
126 /**
127 Completes the Map() operation and releases any corresponding resources.
128
129 @param Mapping The mapping value returned from Map().
130
131 @retval EFI_SUCCESS The range was unmapped.
132 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
133 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
134 **/
135 EFI_STATUS
136 IoMmuUnmap (
137 IN VOID *Mapping
138 )
139 {
140 EFI_STATUS Status;
141 EDKII_IOMMU_PPI *IoMmu;
142
143 IoMmu = GetIoMmu ();
144
145 if (IoMmu != NULL) {
146 Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
147 Status = IoMmu->Unmap (IoMmu, Mapping);
148 } else {
149 Status = EFI_SUCCESS;
150 }
151 return Status;
152 }
153
154 /**
155 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
156 OperationBusMasterCommonBuffer64 mapping.
157
158 @param Pages The number of pages to allocate.
159 @param HostAddress A pointer to store the base system memory address of the
160 allocated range.
161 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
162 access the hosts HostAddress.
163 @param Mapping A resulting value to pass to Unmap().
164
165 @retval EFI_SUCCESS The requested memory pages were allocated.
166 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
167 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
168 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
169 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
170
171 **/
172 EFI_STATUS
173 IoMmuAllocateBuffer (
174 IN UINTN Pages,
175 OUT VOID **HostAddress,
176 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
177 OUT VOID **Mapping
178 )
179 {
180 EFI_STATUS Status;
181 UINTN NumberOfBytes;
182 EFI_PHYSICAL_ADDRESS HostPhyAddress;
183 EDKII_IOMMU_PPI *IoMmu;
184
185 *HostAddress = NULL;
186 *DeviceAddress = 0;
187
188 IoMmu = GetIoMmu ();
189
190 if (IoMmu != NULL) {
191 Status = IoMmu->AllocateBuffer (
192 IoMmu,
193 EfiBootServicesData,
194 Pages,
195 HostAddress,
196 0
197 );
198 if (EFI_ERROR (Status)) {
199 return EFI_OUT_OF_RESOURCES;
200 }
201
202 NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
203 Status = IoMmu->Map (
204 IoMmu,
205 EdkiiIoMmuOperationBusMasterCommonBuffer,
206 *HostAddress,
207 &NumberOfBytes,
208 DeviceAddress,
209 Mapping
210 );
211 if (EFI_ERROR (Status)) {
212 return EFI_OUT_OF_RESOURCES;
213 }
214 Status = IoMmu->SetAttribute (
215 IoMmu,
216 *Mapping,
217 EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
218 );
219 if (EFI_ERROR (Status)) {
220 return Status;
221 }
222 } else {
223 Status = PeiServicesAllocatePages (
224 EfiBootServicesData,
225 Pages,
226 &HostPhyAddress
227 );
228 if (EFI_ERROR (Status)) {
229 return EFI_OUT_OF_RESOURCES;
230 }
231 *HostAddress = (VOID *)(UINTN)HostPhyAddress;
232 *DeviceAddress = HostPhyAddress;
233 *Mapping = NULL;
234 }
235 return Status;
236 }
237
238 /**
239 Frees memory that was allocated with AllocateBuffer().
240
241 @param Pages The number of pages to free.
242 @param HostAddress The base system memory address of the allocated range.
243 @param Mapping The mapping value returned from Map().
244
245 @retval EFI_SUCCESS The requested memory pages were freed.
246 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
247 was not allocated with AllocateBuffer().
248
249 **/
250 EFI_STATUS
251 IoMmuFreeBuffer (
252 IN UINTN Pages,
253 IN VOID *HostAddress,
254 IN VOID *Mapping
255 )
256 {
257 EFI_STATUS Status;
258 EDKII_IOMMU_PPI *IoMmu;
259
260 IoMmu = GetIoMmu ();
261
262 if (IoMmu != NULL) {
263 Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
264 Status = IoMmu->Unmap (IoMmu, Mapping);
265 Status = IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
266 } else {
267 Status = EFI_SUCCESS;
268 }
269 return Status;
270 }