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