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