]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[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
0591696e 222\r
0591696e
FT
223\r
224/**\r
225 Initialize the memory management pool for the host controller.\r
d1102dba 226\r
0591696e
FT
227 @param Private The Ufs Peim driver private data.\r
228\r
229 @retval EFI_SUCCESS The memory pool is initialized.\r
230 @retval Others Fail to init the memory pool.\r
231\r
232**/\r
233EFI_STATUS\r
234UfsPeimInitMemPool (\r
235 IN UFS_PEIM_HC_PRIVATE_DATA *Private\r
236 )\r
237{\r
238 UFS_PEIM_MEM_POOL *Pool;\r
239 EFI_STATUS Status;\r
240 VOID *TempPtr;\r
241\r
242 TempPtr = NULL;\r
243 Pool = NULL;\r
d1102dba 244\r
0591696e
FT
245 Status = PeiServicesAllocatePool (sizeof (UFS_PEIM_MEM_POOL), &TempPtr);\r
246 if (EFI_ERROR (Status)) {\r
247 return EFI_OUT_OF_RESOURCES;\r
248 }\r
249\r
250 ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (UFS_PEIM_MEM_POOL));\r
251\r
252 Pool = (UFS_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
253\r
254 Pool->Head = UfsPeimAllocMemBlock (UFS_PEIM_MEM_DEFAULT_PAGES);\r
255\r
256 if (Pool->Head == NULL) {\r
257 return EFI_OUT_OF_RESOURCES;\r
258 }\r
259\r
260 Private->Pool = Pool;\r
261 return EFI_SUCCESS;\r
262}\r
263\r
264/**\r
265 Release the memory management pool.\r
d1102dba 266\r
0591696e
FT
267 @param Pool The memory pool to free.\r
268\r
269 @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
270 @retval EFI_SUCCESS The memory pool is freed.\r
271\r
272**/\r
273EFI_STATUS\r
274UfsPeimFreeMemPool (\r
275 IN UFS_PEIM_MEM_POOL *Pool\r
276 )\r
277{\r
278 UFS_PEIM_MEM_BLOCK *Block;\r
279\r
280 ASSERT (Pool->Head != NULL);\r
281\r
282 //\r
283 // Unlink all the memory blocks from the pool, then free them.\r
0591696e
FT
284 //\r
285 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
286 UfsPeimFreeMemBlock (Pool, Block);\r
287 }\r
288\r
289 UfsPeimFreeMemBlock (Pool, Pool->Head);\r
290\r
291 return EFI_SUCCESS;\r
292}\r
293\r
294/**\r
295 Allocate some memory from the host controller's memory pool\r
296 which can be used to communicate with host controller.\r
d1102dba 297\r
0591696e
FT
298 @param Pool The host controller's memory pool.\r
299 @param Size Size of the memory to allocate.\r
300\r
301 @return The allocated memory or NULL.\r
302\r
303**/\r
304VOID *\r
305UfsPeimAllocateMem (\r
306 IN UFS_PEIM_MEM_POOL *Pool,\r
307 IN UINTN Size\r
308 )\r
309{\r
310 UFS_PEIM_MEM_BLOCK *Head;\r
311 UFS_PEIM_MEM_BLOCK *Block;\r
312 UFS_PEIM_MEM_BLOCK *NewBlock;\r
313 VOID *Mem;\r
314 UINTN AllocSize;\r
315 UINTN Pages;\r
316\r
317 Mem = NULL;\r
318 AllocSize = UFS_PEIM_MEM_ROUND (Size);\r
319 Head = Pool->Head;\r
320 ASSERT (Head != NULL);\r
321\r
322 //\r
323 // First check whether current memory blocks can satisfy the allocation.\r
324 //\r
325 for (Block = Head; Block != NULL; Block = Block->Next) {\r
326 Mem = UfsPeimAllocMemFromBlock (Block, AllocSize / UFS_PEIM_MEM_UNIT);\r
327\r
328 if (Mem != NULL) {\r
329 ZeroMem (Mem, Size);\r
330 break;\r
331 }\r
332 }\r
333\r
334 if (Mem != NULL) {\r
335 return Mem;\r
336 }\r
337\r
338 //\r
339 // Create a new memory block if there is not enough memory\r
340 // in the pool. If the allocation size is larger than the\r
341 // default page number, just allocate a large enough memory\r
342 // block. Otherwise allocate default pages.\r
343 //\r
344 if (AllocSize > EFI_PAGES_TO_SIZE (UFS_PEIM_MEM_DEFAULT_PAGES)) {\r
345 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
346 } else {\r
347 Pages = UFS_PEIM_MEM_DEFAULT_PAGES;\r
348 }\r
349\r
350 NewBlock = UfsPeimAllocMemBlock (Pages);\r
351 if (NewBlock == NULL) {\r
352 return NULL;\r
353 }\r
d1102dba 354\r
0591696e
FT
355 //\r
356 // Add the new memory block to the pool, then allocate memory from it\r
357 //\r
358 UfsPeimInsertMemBlockToPool (Head, NewBlock);\r
359 Mem = UfsPeimAllocMemFromBlock (NewBlock, AllocSize / UFS_PEIM_MEM_UNIT);\r
360\r
361 if (Mem != NULL) {\r
362 ZeroMem (Mem, Size);\r
363 }\r
364\r
365 return Mem;\r
366}\r
367\r
368/**\r
369 Free the allocated memory back to the memory pool.\r
370\r
371 @param Pool The memory pool of the host controller.\r
372 @param Mem The memory to free.\r
373 @param Size The size of the memory to free.\r
374\r
375**/\r
376VOID\r
377UfsPeimFreeMem (\r
378 IN UFS_PEIM_MEM_POOL *Pool,\r
379 IN VOID *Mem,\r
380 IN UINTN Size\r
381 )\r
382{\r
383 UFS_PEIM_MEM_BLOCK *Head;\r
384 UFS_PEIM_MEM_BLOCK *Block;\r
385 UINT8 *ToFree;\r
386 UINTN AllocSize;\r
387 UINTN Byte;\r
388 UINTN Bit;\r
389 UINTN Count;\r
390\r
391 Head = Pool->Head;\r
392 AllocSize = UFS_PEIM_MEM_ROUND (Size);\r
393 ToFree = (UINT8 *) Mem;\r
394\r
395 for (Block = Head; Block != NULL; Block = Block->Next) {\r
396 //\r
397 // scan the memory block list for the memory block that\r
398 // completely contains the memory to free.\r
399 //\r
400 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
401 //\r
402 // compute the start byte and bit in the bit array\r
403 //\r
404 Byte = ((ToFree - Block->Buf) / UFS_PEIM_MEM_UNIT) / 8;\r
405 Bit = ((ToFree - Block->Buf) / UFS_PEIM_MEM_UNIT) % 8;\r
406\r
407 //\r
2048c585 408 // reset associated bits in bit array\r
0591696e
FT
409 //\r
410 for (Count = 0; Count < (AllocSize / UFS_PEIM_MEM_UNIT); Count++) {\r
411 ASSERT (UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
412\r
413 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ UFS_PEIM_MEM_BIT (Bit));\r
414 UFS_PEIM_NEXT_BIT (Byte, Bit);\r
415 }\r
416\r
417 break;\r
418 }\r
419 }\r
420\r
421 //\r
422 // If Block == NULL, it means that the current memory isn't\r
423 // in the host controller's pool. This is critical because\r
424 // the caller has passed in a wrong memory point\r
425 //\r
426 ASSERT (Block != NULL);\r
427\r
428 //\r
429 // Release the current memory block if it is empty and not the head\r
430 //\r
431 if ((Block != Head) && UfsPeimIsMemBlockEmpty (Block)) {\r
432 UfsPeimFreeMemBlock (Pool, Block);\r
433 }\r
434\r
435 return ;\r
436}\r