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