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