]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
Update PeiCore to support load PEIM into memory on S3 boot path.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / UsbHcMem.c
CommitLineData
913cb9dc 1/** @file\r
2\r
ab6495ea 3 The routine procedure for uhci memory allocate/free.\r
4\r
cd5ebaa0
HT
5Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
913cb9dc 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full 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
913cb9dc 14**/\r
15\r
16#include "Uhci.h"\r
17\r
18\r
913cb9dc 19/**\r
ab6495ea 20 Allocate a block of memory to be used by the buffer pool.\r
913cb9dc 21\r
ab6495ea 22 @param Pool The buffer pool to allocate memory for.\r
23 @param Pages How many pages to allocate.\r
913cb9dc 24\r
ab6495ea 25 @return The allocated memory block or NULL if failed.\r
913cb9dc 26\r
27**/\r
913cb9dc 28USBHC_MEM_BLOCK *\r
29UsbHcAllocMemBlock (\r
30 IN USBHC_MEM_POOL *Pool,\r
31 IN UINTN Pages\r
32 )\r
33{\r
34 USBHC_MEM_BLOCK *Block;\r
35 EFI_PCI_IO_PROTOCOL *PciIo;\r
36 VOID *BufHost;\r
37 VOID *Mapping;\r
38 EFI_PHYSICAL_ADDRESS MappedAddr;\r
39 UINTN Bytes;\r
40 EFI_STATUS Status;\r
41\r
42 PciIo = Pool->PciIo;\r
43\r
44 Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
45 if (Block == NULL) {\r
46 return NULL;\r
47 }\r
48\r
49 //\r
50 // each bit in the bit array represents USBHC_MEM_UNIT\r
51 // bytes of memory in the memory block.\r
52 //\r
53 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
54\r
55 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
56 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
57 Block->Bits = AllocateZeroPool (Block->BitsLen);\r
58\r
59 if (Block->Bits == NULL) {\r
60 gBS->FreePool (Block);\r
61 return NULL;\r
62 }\r
63\r
64 //\r
65 // Allocate the number of Pages of memory, then map it for\r
66 // bus master read and write.\r
67 //\r
68 Status = PciIo->AllocateBuffer (\r
69 PciIo,\r
70 AllocateAnyPages,\r
71 EfiBootServicesData,\r
72 Pages,\r
73 &BufHost,\r
74 0\r
75 );\r
76\r
77 if (EFI_ERROR (Status)) {\r
78 goto FREE_BITARRAY;\r
79 }\r
80\r
81 Bytes = EFI_PAGES_TO_SIZE (Pages);\r
82 Status = PciIo->Map (\r
83 PciIo,\r
84 EfiPciIoOperationBusMasterCommonBuffer,\r
85 BufHost,\r
86 &Bytes,\r
87 &MappedAddr,\r
88 &Mapping\r
89 );\r
90\r
91 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
92 goto FREE_BUFFER;\r
93 }\r
94\r
95 //\r
96 // Check whether the data structure used by the host controller\r
97 // should be restricted into the same 4G\r
98 //\r
99 if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
100 PciIo->Unmap (PciIo, Mapping);\r
101 goto FREE_BUFFER;\r
102 }\r
103\r
104 Block->BufHost = BufHost;\r
105 Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
106 Block->Mapping = Mapping;\r
107\r
913cb9dc 108 return Block;\r
109\r
110FREE_BUFFER:\r
111 PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
112\r
113FREE_BITARRAY:\r
114 gBS->FreePool (Block->Bits);\r
115 gBS->FreePool (Block);\r
116 return NULL;\r
117}\r
118\r
119\r
120/**\r
ab6495ea 121 Free the memory block from the memory pool.\r
913cb9dc 122\r
ab6495ea 123 @param Pool The memory pool to free the block from.\r
124 @param Block The memory block to free.\r
913cb9dc 125\r
913cb9dc 126**/\r
913cb9dc 127VOID\r
128UsbHcFreeMemBlock (\r
129 IN USBHC_MEM_POOL *Pool,\r
130 IN USBHC_MEM_BLOCK *Block\r
131 )\r
132{\r
133 EFI_PCI_IO_PROTOCOL *PciIo;\r
134\r
135 ASSERT ((Pool != NULL) && (Block != NULL));\r
136\r
137 PciIo = Pool->PciIo;\r
138\r
139 //\r
140 // Unmap the common buffer then free the structures\r
141 //\r
142 PciIo->Unmap (PciIo, Block->Mapping);\r
143 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
144\r
145 gBS->FreePool (Block->Bits);\r
146 gBS->FreePool (Block);\r
147}\r
148\r
149\r
150/**\r
ab6495ea 151 Alloc some memory from the block.\r
913cb9dc 152\r
ab6495ea 153 @param Block The memory block to allocate memory from.\r
154 @param Units Number of memory units to allocate.\r
913cb9dc 155\r
ab6495ea 156 @return EFI_SUCCESS The needed memory is allocated.\r
157 @return EFI_NOT_FOUND Can't find the free memory.\r
913cb9dc 158\r
159**/\r
913cb9dc 160VOID *\r
161UsbHcAllocMemFromBlock (\r
162 IN USBHC_MEM_BLOCK *Block,\r
163 IN UINTN Units\r
164 )\r
165{\r
166 UINTN Byte;\r
167 UINT8 Bit;\r
168 UINTN StartByte;\r
169 UINT8 StartBit;\r
170 UINTN Available;\r
171 UINTN Count;\r
172\r
173 ASSERT ((Block != 0) && (Units != 0));\r
174\r
175 StartByte = 0;\r
176 StartBit = 0;\r
177 Available = 0;\r
178\r
179 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
180 //\r
181 // If current bit is zero, the corresponding memory unit is\r
182 // available, otherwise we need to restart our searching.\r
183 // Available counts the consective number of zero bit.\r
184 //\r
185 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
186 Available++;\r
187\r
188 if (Available >= Units) {\r
189 break;\r
190 }\r
191\r
192 NEXT_BIT (Byte, Bit);\r
193\r
194 } else {\r
195 NEXT_BIT (Byte, Bit);\r
196\r
197 Available = 0;\r
198 StartByte = Byte;\r
199 StartBit = Bit;\r
200 }\r
201 }\r
202\r
203 if (Available < Units) {\r
204 return NULL;\r
205 }\r
206\r
207 //\r
208 // Mark the memory as allocated\r
209 //\r
210 Byte = StartByte;\r
211 Bit = StartBit;\r
212\r
213 for (Count = 0; Count < Units; Count++) {\r
214 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
215\r
d074a8e1 216 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
913cb9dc 217 NEXT_BIT (Byte, Bit);\r
218 }\r
219\r
220 return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
221}\r
222\r
aa91de05 223/**\r
224 Calculate the corresponding pci bus address according to the Mem parameter.\r
225\r
226 @param Pool The memory pool of the host controller.\r
227 @param Mem The pointer to host memory.\r
228 @param Size The size of the memory region.\r
229\r
230 @return the pci memory address\r
231**/\r
232EFI_PHYSICAL_ADDRESS\r
233UsbHcGetPciAddressForHostMem (\r
234 IN USBHC_MEM_POOL *Pool,\r
235 IN VOID *Mem,\r
236 IN UINTN Size\r
237 )\r
238{\r
239 USBHC_MEM_BLOCK *Head;\r
240 USBHC_MEM_BLOCK *Block;\r
241 UINTN AllocSize;\r
242 EFI_PHYSICAL_ADDRESS PhyAddr;\r
243 UINTN Offset;\r
244\r
245 Head = Pool->Head;\r
246 AllocSize = USBHC_MEM_ROUND (Size);\r
247\r
248 if (Mem == NULL) {\r
249 return 0;\r
250 }\r
251\r
252 for (Block = Head; Block != NULL; Block = Block->Next) {\r
253 //\r
254 // scan the memory block list for the memory block that\r
255 // completely contains the allocated memory.\r
256 //\r
257 if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
258 break;\r
259 }\r
260 }\r
261\r
262 ASSERT ((Block != NULL));\r
263 //\r
264 // calculate the pci memory address for host memory address.\r
265 //\r
266 Offset = (UINT8 *)Mem - Block->BufHost;\r
267 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);\r
268 return PhyAddr;\r
269}\r
913cb9dc 270\r
271/**\r
ab6495ea 272 Insert the memory block to the pool's list of the blocks.\r
913cb9dc 273\r
ab6495ea 274 @param Head The head of the memory pool's block list.\r
275 @param Block The memory block to insert.\r
913cb9dc 276\r
913cb9dc 277**/\r
913cb9dc 278VOID\r
279UsbHcInsertMemBlockToPool (\r
280 IN USBHC_MEM_BLOCK *Head,\r
281 IN USBHC_MEM_BLOCK *Block\r
282 )\r
283{\r
284 ASSERT ((Head != NULL) && (Block != NULL));\r
285 Block->Next = Head->Next;\r
286 Head->Next = Block;\r
287}\r
288\r
289\r
290/**\r
291 Is the memory block empty?\r
292\r
ab6495ea 293 @param Block The memory block to check.\r
913cb9dc 294\r
ab6495ea 295 @return TRUE The memory block is empty.\r
296 @return FALSE The memory block isn't empty.\r
913cb9dc 297\r
298**/\r
913cb9dc 299BOOLEAN\r
300UsbHcIsMemBlockEmpty (\r
301 IN USBHC_MEM_BLOCK *Block\r
302 )\r
303{\r
304 UINTN Index;\r
305\r
306 for (Index = 0; Index < Block->BitsLen; Index++) {\r
307 if (Block->Bits[Index] != 0) {\r
308 return FALSE;\r
309 }\r
310 }\r
311\r
312 return TRUE;\r
313}\r
314\r
315\r
316/**\r
ab6495ea 317 Unlink the memory block from the pool's list.\r
913cb9dc 318\r
ab6495ea 319 @param Head The block list head of the memory's pool.\r
913cb9dc 320 @param BlockToUnlink The memory block to unlink.\r
321\r
913cb9dc 322**/\r
913cb9dc 323VOID\r
324UsbHcUnlinkMemBlock (\r
325 IN USBHC_MEM_BLOCK *Head,\r
326 IN USBHC_MEM_BLOCK *BlockToUnlink\r
327 )\r
328{\r
329 USBHC_MEM_BLOCK *Block;\r
330\r
331 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
332\r
333 for (Block = Head; Block != NULL; Block = Block->Next) {\r
334 if (Block->Next == BlockToUnlink) {\r
335 Block->Next = BlockToUnlink->Next;\r
336 BlockToUnlink->Next = NULL;\r
337 break;\r
338 }\r
339 }\r
340}\r
341\r
342\r
343/**\r
ab6495ea 344 Initialize the memory management pool for the host controller.\r
913cb9dc 345\r
ab6495ea 346 @param PciIo The PciIo that can be used to access the host controller.\r
347 @param Check4G Whether the host controller requires allocated memory\r
348 from one 4G address space.\r
349 @param Which4G The 4G memory area each memory allocated should be from.\r
913cb9dc 350\r
ab6495ea 351 @return EFI_SUCCESS The memory pool is initialized.\r
352 @return EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
913cb9dc 353\r
354**/\r
355USBHC_MEM_POOL *\r
356UsbHcInitMemPool (\r
357 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
358 IN BOOLEAN Check4G,\r
359 IN UINT32 Which4G\r
360 )\r
361{\r
362 USBHC_MEM_POOL *Pool;\r
363\r
364 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
365\r
366 if (Pool == NULL) {\r
367 return Pool;\r
368 }\r
369\r
370 Pool->PciIo = PciIo;\r
371 Pool->Check4G = Check4G;\r
372 Pool->Which4G = Which4G;\r
373 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
374\r
375 if (Pool->Head == NULL) {\r
376 gBS->FreePool (Pool);\r
377 Pool = NULL;\r
378 }\r
379\r
380 return Pool;\r
381}\r
382\r
383\r
384/**\r
ab6495ea 385 Release the memory management pool.\r
913cb9dc 386\r
ab6495ea 387 @param Pool The USB memory pool to free.\r
913cb9dc 388\r
ab6495ea 389 @return EFI_SUCCESS The memory pool is freed.\r
390 @return EFI_DEVICE_ERROR Failed to free the memory pool.\r
913cb9dc 391\r
392**/\r
393EFI_STATUS\r
394UsbHcFreeMemPool (\r
395 IN USBHC_MEM_POOL *Pool\r
396 )\r
397{\r
398 USBHC_MEM_BLOCK *Block;\r
399\r
400 ASSERT (Pool->Head != NULL);\r
401\r
402 //\r
403 // Unlink all the memory blocks from the pool, then free them.\r
404 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
405 // first block.\r
406 //\r
407 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
408 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
409 UsbHcFreeMemBlock (Pool, Block);\r
410 }\r
411\r
412 UsbHcFreeMemBlock (Pool, Pool->Head);\r
413 gBS->FreePool (Pool);\r
414 return EFI_SUCCESS;\r
415}\r
416\r
417\r
418/**\r
419 Allocate some memory from the host controller's memory pool\r
420 which can be used to communicate with host controller.\r
421\r
ab6495ea 422 @param Pool The host controller's memory pool.\r
423 @param Size Size of the memory to allocate.\r
913cb9dc 424\r
ab6495ea 425 @return The allocated memory or NULL.\r
913cb9dc 426\r
427**/\r
428VOID *\r
429UsbHcAllocateMem (\r
430 IN USBHC_MEM_POOL *Pool,\r
431 IN UINTN Size\r
432 )\r
433{\r
434 USBHC_MEM_BLOCK *Head;\r
435 USBHC_MEM_BLOCK *Block;\r
436 USBHC_MEM_BLOCK *NewBlock;\r
437 VOID *Mem;\r
438 UINTN AllocSize;\r
439 UINTN Pages;\r
440\r
441 Mem = NULL;\r
442 AllocSize = USBHC_MEM_ROUND (Size);\r
443 Head = Pool->Head;\r
444 ASSERT (Head != NULL);\r
445\r
446 //\r
447 // First check whether current memory blocks can satisfy the allocation.\r
448 //\r
449 for (Block = Head; Block != NULL; Block = Block->Next) {\r
450 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
451\r
452 if (Mem != NULL) {\r
453 ZeroMem (Mem, Size);\r
454 break;\r
455 }\r
456 }\r
457\r
458 if (Mem != NULL) {\r
459 return Mem;\r
460 }\r
461\r
462 //\r
463 // Create a new memory block if there is not enough memory\r
464 // in the pool. If the allocation size is larger than the\r
465 // default page number, just allocate a large enough memory\r
466 // block. Otherwise allocate default pages.\r
467 //\r
468 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
469 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
470 } else {\r
471 Pages = USBHC_MEM_DEFAULT_PAGES;\r
472 }\r
473\r
474 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
475\r
476 if (NewBlock == NULL) {\r
1c619535 477 DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
913cb9dc 478 return NULL;\r
479 }\r
480\r
481 //\r
482 // Add the new memory block to the pool, then allocate memory from it\r
483 //\r
484 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
485 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
486\r
487 if (Mem != NULL) {\r
488 ZeroMem (Mem, Size);\r
489 }\r
490\r
491 return Mem;\r
492}\r
493\r
494\r
495/**\r
ab6495ea 496 Free the allocated memory back to the memory pool.\r
913cb9dc 497\r
ab6495ea 498 @param Pool The memory pool of the host controller.\r
499 @param Mem The memory to free.\r
500 @param Size The size of the memory to free.\r
913cb9dc 501\r
913cb9dc 502**/\r
503VOID\r
504UsbHcFreeMem (\r
505 IN USBHC_MEM_POOL *Pool,\r
506 IN VOID *Mem,\r
507 IN UINTN Size\r
508 )\r
509{\r
510 USBHC_MEM_BLOCK *Head;\r
511 USBHC_MEM_BLOCK *Block;\r
512 UINT8 *ToFree;\r
513 UINTN AllocSize;\r
514 UINTN Byte;\r
515 UINTN Bit;\r
516 UINTN Count;\r
517\r
518 Head = Pool->Head;\r
519 AllocSize = USBHC_MEM_ROUND (Size);\r
520 ToFree = (UINT8 *) Mem;\r
521\r
522 for (Block = Head; Block != NULL; Block = Block->Next) {\r
523 //\r
524 // scan the memory block list for the memory block that\r
525 // completely contains the memory to free.\r
526 //\r
527 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
528 //\r
529 // compute the start byte and bit in the bit array\r
530 //\r
531 Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
532 Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
533\r
534 //\r
535 // reset associated bits in bit arry\r
536 //\r
537 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
538 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
539\r
c52fa98c 540 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
913cb9dc 541 NEXT_BIT (Byte, Bit);\r
542 }\r
543\r
544 break;\r
545 }\r
546 }\r
547\r
548 //\r
549 // If Block == NULL, it means that the current memory isn't\r
550 // in the host controller's pool. This is critical because\r
551 // the caller has passed in a wrong memory point\r
552 //\r
553 ASSERT (Block != NULL);\r
554\r
555 //\r
556 // Release the current memory block if it is empty and not the head\r
557 //\r
558 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
913cb9dc 559 UsbHcUnlinkMemBlock (Head, Block);\r
560 UsbHcFreeMemBlock (Pool, Block);\r
561 }\r
562\r
563 return ;\r
564}\r