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