]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdBlockIoPei / SdHcMem.c
CommitLineData
48555339
FT
1/** @file\r
2\r
77af8668 3Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
48555339 4\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
48555339
FT
6\r
7**/\r
8\r
9#include "SdBlockIoPei.h"\r
10\r
11/**\r
12 Allocate a block of memory to be used by the buffer pool.\r
13\r
14 @param Pages How many pages to allocate.\r
15\r
16 @return The allocated memory block or NULL if failed.\r
17\r
18**/\r
19SD_PEIM_MEM_BLOCK *\r
20SdPeimAllocMemBlock (\r
21 IN UINTN Pages\r
22 )\r
23{\r
24 SD_PEIM_MEM_BLOCK *Block;\r
77af8668
HW
25 VOID *BufHost;\r
26 VOID *Mapping;\r
27 EFI_PHYSICAL_ADDRESS MappedAddr;\r
48555339
FT
28 EFI_STATUS Status;\r
29 VOID *TempPtr;\r
48555339
FT
30\r
31 TempPtr = NULL;\r
32 Block = NULL;\r
33\r
34 Status = PeiServicesAllocatePool (sizeof(SD_PEIM_MEM_BLOCK), &TempPtr);\r
35 if (EFI_ERROR (Status)) {\r
36 return NULL;\r
37 }\r
38\r
39 ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(SD_PEIM_MEM_BLOCK));\r
40\r
41 //\r
42 // each bit in the bit array represents SD_PEIM_MEM_UNIT\r
43 // bytes of memory in the memory block.\r
44 //\r
45 ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
46\r
47 Block = (SD_PEIM_MEM_BLOCK*)(UINTN)TempPtr;\r
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
49 Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);\r
50\r
51 Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
52 if (EFI_ERROR (Status)) {\r
53 return NULL;\r
54 }\r
55\r
56 ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);\r
57\r
58 Block->Bits = (UINT8*)(UINTN)TempPtr;\r
59\r
77af8668 60 Status = IoMmuAllocateBuffer (\r
48555339 61 Pages,\r
77af8668
HW
62 &BufHost,\r
63 &MappedAddr,\r
64 &Mapping\r
48555339
FT
65 );\r
66 if (EFI_ERROR (Status)) {\r
67 return NULL;\r
68 }\r
69\r
77af8668 70 ZeroMem ((VOID*)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));\r
48555339 71\r
77af8668
HW
72 Block->BufHost = (UINT8 *) (UINTN) BufHost;\r
73 Block->Buf = (UINT8 *) (UINTN) MappedAddr;\r
74 Block->Mapping = Mapping;\r
75 Block->Next = NULL;\r
48555339
FT
76\r
77 return Block;\r
78}\r
79\r
80/**\r
81 Free the memory block from the memory pool.\r
82\r
83 @param Pool The memory pool to free the block from.\r
84 @param Block The memory block to free.\r
85\r
86**/\r
87VOID\r
88SdPeimFreeMemBlock (\r
89 IN SD_PEIM_MEM_POOL *Pool,\r
90 IN SD_PEIM_MEM_BLOCK *Block\r
91 )\r
92{\r
93 ASSERT ((Pool != NULL) && (Block != NULL));\r
77af8668
HW
94\r
95 IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);\r
48555339
FT
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
109SdPeimAllocMemFromBlock (\r
110 IN SD_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 (!SD_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 SD_PEIM_NEXT_BIT (Byte, Bit);\r
141\r
142 } else {\r
143 SD_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 (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
163\r
164 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) SD_PEIM_MEM_BIT (Bit));\r
165 SD_PEIM_NEXT_BIT (Byte, Bit);\r
166 }\r
167\r
168 return Block->Buf + (StartByte * 8 + StartBit) * SD_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
179SdPeimInsertMemBlockToPool (\r
180 IN SD_PEIM_MEM_BLOCK *Head,\r
181 IN SD_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
199SdPeimIsMemBlockEmpty (\r
200 IN SD_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
48555339 215\r
48555339
FT
216\r
217/**\r
218 Initialize the memory management pool for the host controller.\r
219\r
220 @param Private The Sd Peim driver private data.\r
221\r
222 @retval EFI_SUCCESS The memory pool is initialized.\r
223 @retval Others Fail to init the memory pool.\r
224\r
225**/\r
226EFI_STATUS\r
227SdPeimInitMemPool (\r
228 IN SD_PEIM_HC_PRIVATE_DATA *Private\r
229 )\r
230{\r
231 SD_PEIM_MEM_POOL *Pool;\r
232 EFI_STATUS Status;\r
233 VOID *TempPtr;\r
234\r
235 TempPtr = NULL;\r
236 Pool = NULL;\r
237\r
238 Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);\r
239 if (EFI_ERROR (Status)) {\r
240 return EFI_OUT_OF_RESOURCES;\r
241 }\r
242\r
243 ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));\r
244\r
245 Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
246\r
247 Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);\r
248\r
249 if (Pool->Head == NULL) {\r
250 return EFI_OUT_OF_RESOURCES;\r
251 }\r
252\r
253 Private->Pool = Pool;\r
254 return EFI_SUCCESS;\r
255}\r
256\r
257/**\r
258 Release the memory management pool.\r
259\r
260 @param Pool The memory pool to free.\r
261\r
262 @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
263 @retval EFI_SUCCESS The memory pool is freed.\r
264\r
265**/\r
266EFI_STATUS\r
267SdPeimFreeMemPool (\r
268 IN SD_PEIM_MEM_POOL *Pool\r
269 )\r
270{\r
271 SD_PEIM_MEM_BLOCK *Block;\r
272\r
273 ASSERT (Pool->Head != NULL);\r
274\r
275 //\r
276 // Unlink all the memory blocks from the pool, then free them.\r
48555339
FT
277 //\r
278 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
279 SdPeimFreeMemBlock (Pool, Block);\r
280 }\r
281\r
282 SdPeimFreeMemBlock (Pool, Pool->Head);\r
283\r
284 return EFI_SUCCESS;\r
285}\r
286\r
287/**\r
288 Allocate some memory from the host controller's memory pool\r
289 which can be used to communicate with host controller.\r
290\r
291 @param Pool The host controller's memory pool.\r
292 @param Size Size of the memory to allocate.\r
293\r
294 @return The allocated memory or NULL.\r
295\r
296**/\r
297VOID *\r
298SdPeimAllocateMem (\r
299 IN SD_PEIM_MEM_POOL *Pool,\r
300 IN UINTN Size\r
301 )\r
302{\r
303 SD_PEIM_MEM_BLOCK *Head;\r
304 SD_PEIM_MEM_BLOCK *Block;\r
305 SD_PEIM_MEM_BLOCK *NewBlock;\r
306 VOID *Mem;\r
307 UINTN AllocSize;\r
308 UINTN Pages;\r
309\r
310 Mem = NULL;\r
311 AllocSize = SD_PEIM_MEM_ROUND (Size);\r
312 Head = Pool->Head;\r
313 ASSERT (Head != NULL);\r
314\r
315 //\r
316 // First check whether current memory blocks can satisfy the allocation.\r
317 //\r
318 for (Block = Head; Block != NULL; Block = Block->Next) {\r
319 Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);\r
320\r
321 if (Mem != NULL) {\r
322 ZeroMem (Mem, Size);\r
323 break;\r
324 }\r
325 }\r
326\r
327 if (Mem != NULL) {\r
328 return Mem;\r
329 }\r
330\r
331 //\r
332 // Create a new memory block if there is not enough memory\r
333 // in the pool. If the allocation size is larger than the\r
334 // default page number, just allocate a large enough memory\r
335 // block. Otherwise allocate default pages.\r
336 //\r
337 if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {\r
338 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
339 } else {\r
340 Pages = SD_PEIM_MEM_DEFAULT_PAGES;\r
341 }\r
342\r
343 NewBlock = SdPeimAllocMemBlock (Pages);\r
344 if (NewBlock == NULL) {\r
345 return NULL;\r
346 }\r
347\r
348 //\r
349 // Add the new memory block to the pool, then allocate memory from it\r
350 //\r
351 SdPeimInsertMemBlockToPool (Head, NewBlock);\r
352 Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);\r
353\r
354 if (Mem != NULL) {\r
355 ZeroMem (Mem, Size);\r
356 }\r
357\r
358 return Mem;\r
359}\r
360\r
361/**\r
362 Free the allocated memory back to the memory pool.\r
363\r
364 @param Pool The memory pool of the host controller.\r
365 @param Mem The memory to free.\r
366 @param Size The size of the memory to free.\r
367\r
368**/\r
369VOID\r
370SdPeimFreeMem (\r
371 IN SD_PEIM_MEM_POOL *Pool,\r
372 IN VOID *Mem,\r
373 IN UINTN Size\r
374 )\r
375{\r
376 SD_PEIM_MEM_BLOCK *Head;\r
377 SD_PEIM_MEM_BLOCK *Block;\r
378 UINT8 *ToFree;\r
379 UINTN AllocSize;\r
380 UINTN Byte;\r
381 UINTN Bit;\r
382 UINTN Count;\r
383\r
384 Head = Pool->Head;\r
385 AllocSize = SD_PEIM_MEM_ROUND (Size);\r
386 ToFree = (UINT8 *) Mem;\r
387\r
388 for (Block = Head; Block != NULL; Block = Block->Next) {\r
389 //\r
390 // scan the memory block list for the memory block that\r
391 // completely contains the memory to free.\r
392 //\r
393 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
394 //\r
395 // compute the start byte and bit in the bit array\r
396 //\r
397 Byte = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;\r
398 Bit = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;\r
399\r
400 //\r
2048c585 401 // reset associated bits in bit array\r
48555339
FT
402 //\r
403 for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {\r
404 ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
405\r
406 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));\r
407 SD_PEIM_NEXT_BIT (Byte, Bit);\r
408 }\r
409\r
410 break;\r
411 }\r
412 }\r
413\r
414 //\r
415 // If Block == NULL, it means that the current memory isn't\r
416 // in the host controller's pool. This is critical because\r
417 // the caller has passed in a wrong memory point\r
418 //\r
419 ASSERT (Block != NULL);\r
420\r
421 //\r
422 // Release the current memory block if it is empty and not the head\r
423 //\r
424 if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {\r
425 SdPeimFreeMemBlock (Pool, Block);\r
426 }\r
427\r
428 return ;\r
429}\r