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