]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / EmmcBlockIoPei / EmmcHcMem.c
1 /** @file
2
3 Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "EmmcBlockIoPei.h"
10
11 /**
12 Allocate a block of memory to be used by the buffer pool.
13
14 @param Pages How many pages to allocate.
15
16 @return The allocated memory block or NULL if failed.
17
18 **/
19 EMMC_PEIM_MEM_BLOCK *
20 EmmcPeimAllocMemBlock (
21 IN UINTN Pages
22 )
23 {
24 EMMC_PEIM_MEM_BLOCK *Block;
25 VOID *BufHost;
26 VOID *Mapping;
27 EFI_PHYSICAL_ADDRESS MappedAddr;
28 EFI_STATUS Status;
29 VOID *TempPtr;
30
31 TempPtr = NULL;
32 Block = NULL;
33
34 Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_BLOCK), &TempPtr);
35 if (EFI_ERROR (Status)) {
36 return NULL;
37 }
38
39 ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_BLOCK));
40
41 //
42 // each bit in the bit array represents EMMC_PEIM_MEM_UNIT
43 // bytes of memory in the memory block.
44 //
45 ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
46
47 Block = (EMMC_PEIM_MEM_BLOCK *)(UINTN)TempPtr;
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
49 Block->BitsLen = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8);
50
51 Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
52 if (EFI_ERROR (Status)) {
53 return NULL;
54 }
55
56 ZeroMem ((VOID *)(UINTN)TempPtr, Block->BitsLen);
57
58 Block->Bits = (UINT8 *)(UINTN)TempPtr;
59
60 Status = IoMmuAllocateBuffer (
61 Pages,
62 &BufHost,
63 &MappedAddr,
64 &Mapping
65 );
66 if (EFI_ERROR (Status)) {
67 return NULL;
68 }
69
70 ZeroMem ((VOID *)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));
71
72 Block->BufHost = (UINT8 *)(UINTN)BufHost;
73 Block->Buf = (UINT8 *)(UINTN)MappedAddr;
74 Block->Mapping = Mapping;
75 Block->Next = NULL;
76
77 return Block;
78 }
79
80 /**
81 Free the memory block from the memory pool.
82
83 @param Pool The memory pool to free the block from.
84 @param Block The memory block to free.
85
86 **/
87 VOID
88 EmmcPeimFreeMemBlock (
89 IN EMMC_PEIM_MEM_POOL *Pool,
90 IN EMMC_PEIM_MEM_BLOCK *Block
91 )
92 {
93 ASSERT ((Pool != NULL) && (Block != NULL));
94
95 IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
96 }
97
98 /**
99 Alloc some memory from the block.
100
101 @param Block The memory block to allocate memory from.
102 @param Units Number of memory units to allocate.
103
104 @return The pointer to the allocated memory. If couldn't allocate the needed memory,
105 the return value is NULL.
106
107 **/
108 VOID *
109 EmmcPeimAllocMemFromBlock (
110 IN EMMC_PEIM_MEM_BLOCK *Block,
111 IN UINTN Units
112 )
113 {
114 UINTN Byte;
115 UINT8 Bit;
116 UINTN StartByte;
117 UINT8 StartBit;
118 UINTN Available;
119 UINTN Count;
120
121 ASSERT ((Block != 0) && (Units != 0));
122
123 StartByte = 0;
124 StartBit = 0;
125 Available = 0;
126
127 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
128 //
129 // If current bit is zero, the corresponding memory unit is
130 // available, otherwise we need to restart our searching.
131 // Available counts the consecutive number of zero bit.
132 //
133 if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
134 Available++;
135
136 if (Available >= Units) {
137 break;
138 }
139
140 EMMC_PEIM_NEXT_BIT (Byte, Bit);
141 } else {
142 EMMC_PEIM_NEXT_BIT (Byte, Bit);
143
144 Available = 0;
145 StartByte = Byte;
146 StartBit = Bit;
147 }
148 }
149
150 if (Available < Units) {
151 return NULL;
152 }
153
154 //
155 // Mark the memory as allocated
156 //
157 Byte = StartByte;
158 Bit = StartBit;
159
160 for (Count = 0; Count < Units; Count++) {
161 ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
162
163 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)EMMC_PEIM_MEM_BIT (Bit));
164 EMMC_PEIM_NEXT_BIT (Byte, Bit);
165 }
166
167 return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT;
168 }
169
170 /**
171 Insert the memory block to the pool's list of the blocks.
172
173 @param Head The head of the memory pool's block list.
174 @param Block The memory block to insert.
175
176 **/
177 VOID
178 EmmcPeimInsertMemBlockToPool (
179 IN EMMC_PEIM_MEM_BLOCK *Head,
180 IN EMMC_PEIM_MEM_BLOCK *Block
181 )
182 {
183 ASSERT ((Head != NULL) && (Block != NULL));
184 Block->Next = Head->Next;
185 Head->Next = Block;
186 }
187
188 /**
189 Is the memory block empty?
190
191 @param Block The memory block to check.
192
193 @retval TRUE The memory block is empty.
194 @retval FALSE The memory block isn't empty.
195
196 **/
197 BOOLEAN
198 EmmcPeimIsMemBlockEmpty (
199 IN EMMC_PEIM_MEM_BLOCK *Block
200 )
201 {
202 UINTN Index;
203
204 for (Index = 0; Index < Block->BitsLen; Index++) {
205 if (Block->Bits[Index] != 0) {
206 return FALSE;
207 }
208 }
209
210 return TRUE;
211 }
212
213 /**
214 Initialize the memory management pool for the host controller.
215
216 @param Private The Emmc Peim driver private data.
217
218 @retval EFI_SUCCESS The memory pool is initialized.
219 @retval Others Fail to init the memory pool.
220
221 **/
222 EFI_STATUS
223 EmmcPeimInitMemPool (
224 IN EMMC_PEIM_HC_PRIVATE_DATA *Private
225 )
226 {
227 EMMC_PEIM_MEM_POOL *Pool;
228 EFI_STATUS Status;
229 VOID *TempPtr;
230
231 TempPtr = NULL;
232 Pool = NULL;
233
234 Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr);
235 if (EFI_ERROR (Status)) {
236 return EFI_OUT_OF_RESOURCES;
237 }
238
239 ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL));
240
241 Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr);
242
243 Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES);
244
245 if (Pool->Head == NULL) {
246 return EFI_OUT_OF_RESOURCES;
247 }
248
249 Private->Pool = Pool;
250 return EFI_SUCCESS;
251 }
252
253 /**
254 Release the memory management pool.
255
256 @param Pool The memory pool to free.
257
258 @retval EFI_DEVICE_ERROR Fail to free the memory pool.
259 @retval EFI_SUCCESS The memory pool is freed.
260
261 **/
262 EFI_STATUS
263 EmmcPeimFreeMemPool (
264 IN EMMC_PEIM_MEM_POOL *Pool
265 )
266 {
267 EMMC_PEIM_MEM_BLOCK *Block;
268
269 ASSERT (Pool->Head != NULL);
270
271 //
272 // Unlink all the memory blocks from the pool, then free them.
273 //
274 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
275 EmmcPeimFreeMemBlock (Pool, Block);
276 }
277
278 EmmcPeimFreeMemBlock (Pool, Pool->Head);
279
280 return EFI_SUCCESS;
281 }
282
283 /**
284 Allocate some memory from the host controller's memory pool
285 which can be used to communicate with host controller.
286
287 @param Pool The host controller's memory pool.
288 @param Size Size of the memory to allocate.
289
290 @return The allocated memory or NULL.
291
292 **/
293 VOID *
294 EmmcPeimAllocateMem (
295 IN EMMC_PEIM_MEM_POOL *Pool,
296 IN UINTN Size
297 )
298 {
299 EMMC_PEIM_MEM_BLOCK *Head;
300 EMMC_PEIM_MEM_BLOCK *Block;
301 EMMC_PEIM_MEM_BLOCK *NewBlock;
302 VOID *Mem;
303 UINTN AllocSize;
304 UINTN Pages;
305
306 Mem = NULL;
307 AllocSize = EMMC_PEIM_MEM_ROUND (Size);
308 Head = Pool->Head;
309 ASSERT (Head != NULL);
310
311 //
312 // First check whether current memory blocks can satisfy the allocation.
313 //
314 for (Block = Head; Block != NULL; Block = Block->Next) {
315 Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT);
316
317 if (Mem != NULL) {
318 ZeroMem (Mem, Size);
319 break;
320 }
321 }
322
323 if (Mem != NULL) {
324 return Mem;
325 }
326
327 //
328 // Create a new memory block if there is not enough memory
329 // in the pool. If the allocation size is larger than the
330 // default page number, just allocate a large enough memory
331 // block. Otherwise allocate default pages.
332 //
333 if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) {
334 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
335 } else {
336 Pages = EMMC_PEIM_MEM_DEFAULT_PAGES;
337 }
338
339 NewBlock = EmmcPeimAllocMemBlock (Pages);
340 if (NewBlock == NULL) {
341 return NULL;
342 }
343
344 //
345 // Add the new memory block to the pool, then allocate memory from it
346 //
347 EmmcPeimInsertMemBlockToPool (Head, NewBlock);
348 Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT);
349
350 if (Mem != NULL) {
351 ZeroMem (Mem, Size);
352 }
353
354 return Mem;
355 }
356
357 /**
358 Free the allocated memory back to the memory pool.
359
360 @param Pool The memory pool of the host controller.
361 @param Mem The memory to free.
362 @param Size The size of the memory to free.
363
364 **/
365 VOID
366 EmmcPeimFreeMem (
367 IN EMMC_PEIM_MEM_POOL *Pool,
368 IN VOID *Mem,
369 IN UINTN Size
370 )
371 {
372 EMMC_PEIM_MEM_BLOCK *Head;
373 EMMC_PEIM_MEM_BLOCK *Block;
374 UINT8 *ToFree;
375 UINTN AllocSize;
376 UINTN Byte;
377 UINTN Bit;
378 UINTN Count;
379
380 Head = Pool->Head;
381 AllocSize = EMMC_PEIM_MEM_ROUND (Size);
382 ToFree = (UINT8 *)Mem;
383
384 for (Block = Head; Block != NULL; Block = Block->Next) {
385 //
386 // scan the memory block list for the memory block that
387 // completely contains the memory to free.
388 //
389 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
390 //
391 // compute the start byte and bit in the bit array
392 //
393 Byte = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8;
394 Bit = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8;
395
396 //
397 // reset associated bits in bit array
398 //
399 for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) {
400 ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
401
402 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit));
403 EMMC_PEIM_NEXT_BIT (Byte, Bit);
404 }
405
406 break;
407 }
408 }
409
410 //
411 // If Block == NULL, it means that the current memory isn't
412 // in the host controller's pool. This is critical because
413 // the caller has passed in a wrong memory point
414 //
415 ASSERT (Block != NULL);
416
417 //
418 // Release the current memory block if it is empty and not the head
419 //
420 if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) {
421 EmmcPeimFreeMemBlock (Pool, Block);
422 }
423
424 return;
425 }