]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.c
99fb3521d56be80bd0ae827061042ee8560c734c
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / UsbHcMem.c
1 /** @file
2
3 Routine procedures for memory allocate/free.
4
5 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "Xhci.h"
11
12 /**
13 Allocate a block of memory to be used by the buffer pool.
14
15 @param Pool The buffer pool to allocate memory for.
16 @param Pages How many pages to allocate.
17
18 @return The allocated memory block or NULL if failed.
19
20 **/
21 USBHC_MEM_BLOCK *
22 UsbHcAllocMemBlock (
23 IN USBHC_MEM_POOL *Pool,
24 IN UINTN Pages
25 )
26 {
27 USBHC_MEM_BLOCK *Block;
28 EFI_PCI_IO_PROTOCOL *PciIo;
29 VOID *BufHost;
30 VOID *Mapping;
31 EFI_PHYSICAL_ADDRESS MappedAddr;
32 UINTN Bytes;
33 EFI_STATUS Status;
34
35 PciIo = Pool->PciIo;
36
37 Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
38 if (Block == NULL) {
39 return NULL;
40 }
41
42 //
43 // each bit in the bit array represents USBHC_MEM_UNIT
44 // bytes of memory in the memory block.
45 //
46 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
47
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
49 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
50 Block->Bits = AllocateZeroPool (Block->BitsLen);
51
52 if (Block->Bits == NULL) {
53 gBS->FreePool (Block);
54 return NULL;
55 }
56
57 //
58 // Allocate the number of Pages of memory, then map it for
59 // bus master read and write.
60 //
61 Status = PciIo->AllocateBuffer (
62 PciIo,
63 AllocateAnyPages,
64 EfiBootServicesData,
65 Pages,
66 &BufHost,
67 0
68 );
69
70 if (EFI_ERROR (Status)) {
71 goto FREE_BITARRAY;
72 }
73
74 Bytes = EFI_PAGES_TO_SIZE (Pages);
75 Status = PciIo->Map (
76 PciIo,
77 EfiPciIoOperationBusMasterCommonBuffer,
78 BufHost,
79 &Bytes,
80 &MappedAddr,
81 &Mapping
82 );
83
84 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
85 goto FREE_BUFFER;
86 }
87
88 Block->BufHost = BufHost;
89 Block->Buf = (UINT8 *)((UINTN)MappedAddr);
90 Block->Mapping = Mapping;
91
92 return Block;
93
94 FREE_BUFFER:
95 PciIo->FreeBuffer (PciIo, Pages, BufHost);
96
97 FREE_BITARRAY:
98 gBS->FreePool (Block->Bits);
99 gBS->FreePool (Block);
100 return NULL;
101 }
102
103 /**
104 Free the memory block from the memory pool.
105
106 @param Pool The memory pool to free the block from.
107 @param Block The memory block to free.
108
109 **/
110 VOID
111 UsbHcFreeMemBlock (
112 IN USBHC_MEM_POOL *Pool,
113 IN USBHC_MEM_BLOCK *Block
114 )
115 {
116 EFI_PCI_IO_PROTOCOL *PciIo;
117
118 ASSERT ((Pool != NULL) && (Block != NULL));
119
120 PciIo = Pool->PciIo;
121
122 //
123 // Unmap the common buffer then free the structures
124 //
125 PciIo->Unmap (PciIo, Block->Mapping);
126 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
127
128 gBS->FreePool (Block->Bits);
129 gBS->FreePool (Block);
130 }
131
132 /**
133 Alloc some memory from the block.
134
135 @param Block The memory block to allocate memory from.
136 @param Units Number of memory units to allocate.
137
138 @return The pointer to the allocated memory. If couldn't allocate the needed memory,
139 the return value is NULL.
140
141 **/
142 VOID *
143 UsbHcAllocMemFromBlock (
144 IN USBHC_MEM_BLOCK *Block,
145 IN UINTN Units
146 )
147 {
148 UINTN Byte;
149 UINT8 Bit;
150 UINTN StartByte;
151 UINT8 StartBit;
152 UINTN Available;
153 UINTN Count;
154
155 ASSERT ((Block != 0) && (Units != 0));
156
157 StartByte = 0;
158 StartBit = 0;
159 Available = 0;
160
161 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
162 //
163 // If current bit is zero, the corresponding memory unit is
164 // available, otherwise we need to restart our searching.
165 // Available counts the consective number of zero bit.
166 //
167 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
168 Available++;
169
170 if (Available >= Units) {
171 break;
172 }
173
174 NEXT_BIT (Byte, Bit);
175 } else {
176 NEXT_BIT (Byte, Bit);
177
178 Available = 0;
179 StartByte = Byte;
180 StartBit = Bit;
181 }
182 }
183
184 if (Available < Units) {
185 return NULL;
186 }
187
188 //
189 // Mark the memory as allocated
190 //
191 Byte = StartByte;
192 Bit = StartBit;
193
194 for (Count = 0; Count < Units; Count++) {
195 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
196
197 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | USB_HC_BIT (Bit));
198 NEXT_BIT (Byte, Bit);
199 }
200
201 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
202 }
203
204 /**
205 Calculate the corresponding pci bus address according to the Mem parameter.
206
207 @param Pool The memory pool of the host controller.
208 @param Mem The pointer to host memory.
209 @param Size The size of the memory region.
210
211 @return The pci memory address
212
213 **/
214 EFI_PHYSICAL_ADDRESS
215 UsbHcGetPciAddrForHostAddr (
216 IN USBHC_MEM_POOL *Pool,
217 IN VOID *Mem,
218 IN UINTN Size
219 )
220 {
221 USBHC_MEM_BLOCK *Head;
222 USBHC_MEM_BLOCK *Block;
223 UINTN AllocSize;
224 EFI_PHYSICAL_ADDRESS PhyAddr;
225 UINTN Offset;
226
227 Head = Pool->Head;
228 AllocSize = USBHC_MEM_ROUND (Size);
229
230 if (Mem == NULL) {
231 return 0;
232 }
233
234 for (Block = Head; Block != NULL; Block = Block->Next) {
235 //
236 // scan the memory block list for the memory block that
237 // completely contains the allocated memory.
238 //
239 if ((Block->BufHost <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
240 break;
241 }
242 }
243
244 ASSERT ((Block != NULL));
245 //
246 // calculate the pci memory address for host memory address.
247 //
248 Offset = (UINT8 *)Mem - Block->BufHost;
249 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->Buf + Offset);
250 return PhyAddr;
251 }
252
253 /**
254 Calculate the corresponding host address according to the pci address.
255
256 @param Pool The memory pool of the host controller.
257 @param Mem The pointer to pci memory.
258 @param Size The size of the memory region.
259
260 @return The host memory address
261
262 **/
263 EFI_PHYSICAL_ADDRESS
264 UsbHcGetHostAddrForPciAddr (
265 IN USBHC_MEM_POOL *Pool,
266 IN VOID *Mem,
267 IN UINTN Size
268 )
269 {
270 USBHC_MEM_BLOCK *Head;
271 USBHC_MEM_BLOCK *Block;
272 UINTN AllocSize;
273 EFI_PHYSICAL_ADDRESS HostAddr;
274 UINTN Offset;
275
276 Head = Pool->Head;
277 AllocSize = USBHC_MEM_ROUND (Size);
278
279 if (Mem == NULL) {
280 return 0;
281 }
282
283 for (Block = Head; Block != NULL; Block = Block->Next) {
284 //
285 // scan the memory block list for the memory block that
286 // completely contains the allocated memory.
287 //
288 if ((Block->Buf <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {
289 break;
290 }
291 }
292
293 ASSERT ((Block != NULL));
294 //
295 // calculate the pci memory address for host memory address.
296 //
297 Offset = (UINT8 *)Mem - Block->Buf;
298 HostAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->BufHost + Offset);
299 return HostAddr;
300 }
301
302 /**
303 Insert the memory block to the pool's list of the blocks.
304
305 @param Head The head of the memory pool's block list.
306 @param Block The memory block to insert.
307
308 **/
309 VOID
310 UsbHcInsertMemBlockToPool (
311 IN USBHC_MEM_BLOCK *Head,
312 IN USBHC_MEM_BLOCK *Block
313 )
314 {
315 ASSERT ((Head != NULL) && (Block != NULL));
316 Block->Next = Head->Next;
317 Head->Next = Block;
318 }
319
320 /**
321 Is the memory block empty?
322
323 @param Block The memory block to check.
324
325 @retval TRUE The memory block is empty.
326 @retval FALSE The memory block isn't empty.
327
328 **/
329 BOOLEAN
330 UsbHcIsMemBlockEmpty (
331 IN USBHC_MEM_BLOCK *Block
332 )
333 {
334 UINTN Index;
335
336 for (Index = 0; Index < Block->BitsLen; Index++) {
337 if (Block->Bits[Index] != 0) {
338 return FALSE;
339 }
340 }
341
342 return TRUE;
343 }
344
345 /**
346 Unlink the memory block from the pool's list.
347
348 @param Head The block list head of the memory's pool.
349 @param BlockToUnlink The memory block to unlink.
350
351 **/
352 VOID
353 UsbHcUnlinkMemBlock (
354 IN USBHC_MEM_BLOCK *Head,
355 IN USBHC_MEM_BLOCK *BlockToUnlink
356 )
357 {
358 USBHC_MEM_BLOCK *Block;
359
360 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
361
362 for (Block = Head; Block != NULL; Block = Block->Next) {
363 if (Block->Next == BlockToUnlink) {
364 Block->Next = BlockToUnlink->Next;
365 BlockToUnlink->Next = NULL;
366 break;
367 }
368 }
369 }
370
371 /**
372 Initialize the memory management pool for the host controller.
373
374 @param PciIo The PciIo that can be used to access the host controller.
375
376 @retval EFI_SUCCESS The memory pool is initialized.
377 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
378
379 **/
380 USBHC_MEM_POOL *
381 UsbHcInitMemPool (
382 IN EFI_PCI_IO_PROTOCOL *PciIo
383 )
384 {
385 USBHC_MEM_POOL *Pool;
386
387 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
388
389 if (Pool == NULL) {
390 return Pool;
391 }
392
393 Pool->PciIo = PciIo;
394 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
395
396 if (Pool->Head == NULL) {
397 gBS->FreePool (Pool);
398 Pool = NULL;
399 }
400
401 return Pool;
402 }
403
404 /**
405 Release the memory management pool.
406
407 @param Pool The USB memory pool to free.
408
409 @retval EFI_SUCCESS The memory pool is freed.
410 @retval EFI_DEVICE_ERROR Failed to free the memory pool.
411
412 **/
413 EFI_STATUS
414 UsbHcFreeMemPool (
415 IN USBHC_MEM_POOL *Pool
416 )
417 {
418 USBHC_MEM_BLOCK *Block;
419
420 ASSERT (Pool->Head != NULL);
421
422 //
423 // Unlink all the memory blocks from the pool, then free them.
424 // UsbHcUnlinkMemBlock can't be used to unlink and free the
425 // first block.
426 //
427 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
428 UsbHcUnlinkMemBlock (Pool->Head, Block);
429 UsbHcFreeMemBlock (Pool, Block);
430 }
431
432 UsbHcFreeMemBlock (Pool, Pool->Head);
433 gBS->FreePool (Pool);
434 return EFI_SUCCESS;
435 }
436
437 /**
438 Allocate some memory from the host controller's memory pool
439 which can be used to communicate with host controller.
440
441 @param Pool The host controller's memory pool.
442 @param Size Size of the memory to allocate.
443
444 @return The allocated memory or NULL.
445
446 **/
447 VOID *
448 UsbHcAllocateMem (
449 IN USBHC_MEM_POOL *Pool,
450 IN UINTN Size
451 )
452 {
453 USBHC_MEM_BLOCK *Head;
454 USBHC_MEM_BLOCK *Block;
455 USBHC_MEM_BLOCK *NewBlock;
456 VOID *Mem;
457 UINTN AllocSize;
458 UINTN Pages;
459
460 Mem = NULL;
461 AllocSize = USBHC_MEM_ROUND (Size);
462 Head = Pool->Head;
463 ASSERT (Head != NULL);
464
465 //
466 // First check whether current memory blocks can satisfy the allocation.
467 //
468 for (Block = Head; Block != NULL; Block = Block->Next) {
469 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
470
471 if (Mem != NULL) {
472 ZeroMem (Mem, Size);
473 break;
474 }
475 }
476
477 if (Mem != NULL) {
478 return Mem;
479 }
480
481 //
482 // Create a new memory block if there is not enough memory
483 // in the pool. If the allocation size is larger than the
484 // default page number, just allocate a large enough memory
485 // block. Otherwise allocate default pages.
486 //
487 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
488 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
489 } else {
490 Pages = USBHC_MEM_DEFAULT_PAGES;
491 }
492
493 NewBlock = UsbHcAllocMemBlock (Pool, Pages);
494
495 if (NewBlock == NULL) {
496 DEBUG ((DEBUG_ERROR, "UsbHcAllocateMem: failed to allocate block\n"));
497 return NULL;
498 }
499
500 //
501 // Add the new memory block to the pool, then allocate memory from it
502 //
503 UsbHcInsertMemBlockToPool (Head, NewBlock);
504 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
505
506 if (Mem != NULL) {
507 ZeroMem (Mem, Size);
508 }
509
510 return Mem;
511 }
512
513 /**
514 Free the allocated memory back to the memory pool.
515
516 @param Pool The memory pool of the host controller.
517 @param Mem The memory to free.
518 @param Size The size of the memory to free.
519
520 **/
521 VOID
522 UsbHcFreeMem (
523 IN USBHC_MEM_POOL *Pool,
524 IN VOID *Mem,
525 IN UINTN Size
526 )
527 {
528 USBHC_MEM_BLOCK *Head;
529 USBHC_MEM_BLOCK *Block;
530 UINT8 *ToFree;
531 UINTN AllocSize;
532 UINTN Byte;
533 UINTN Bit;
534 UINTN Count;
535
536 Head = Pool->Head;
537 AllocSize = USBHC_MEM_ROUND (Size);
538 ToFree = (UINT8 *)Mem;
539
540 for (Block = Head; Block != NULL; Block = Block->Next) {
541 //
542 // scan the memory block list for the memory block that
543 // completely contains the memory to free.
544 //
545 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
546 //
547 // compute the start byte and bit in the bit array
548 //
549 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
550 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
551
552 //
553 // reset associated bits in bit array
554 //
555 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
556 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
557
558 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ USB_HC_BIT (Bit));
559 NEXT_BIT (Byte, Bit);
560 }
561
562 break;
563 }
564 }
565
566 //
567 // If Block == NULL, it means that the current memory isn't
568 // in the host controller's pool. This is critical because
569 // the caller has passed in a wrong memory point
570 //
571 ASSERT (Block != NULL);
572
573 //
574 // Release the current memory block if it is empty and not the head
575 //
576 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
577 UsbHcUnlinkMemBlock (Head, Block);
578 UsbHcFreeMemBlock (Pool, Block);
579 }
580
581 return;
582 }
583
584 /**
585 Allocates pages at a specified alignment that are suitable for an EfiPciIoOperationBusMasterCommonBuffer mapping.
586
587 If Alignment is not a power of two and Alignment is not zero, then ASSERT().
588
589 @param PciIo The PciIo that can be used to access the host controller.
590 @param Pages The number of pages to allocate.
591 @param Alignment The requested alignment of the allocation. Must be a power of two.
592 @param HostAddress The system memory address to map to the PCI controller.
593 @param DeviceAddress The resulting map address for the bus master PCI controller to
594 use to access the hosts HostAddress.
595 @param Mapping A resulting value to pass to Unmap().
596
597 @retval EFI_SUCCESS Success to allocate aligned pages.
598 @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
599 @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
600
601
602 **/
603 EFI_STATUS
604 UsbHcAllocateAlignedPages (
605 IN EFI_PCI_IO_PROTOCOL *PciIo,
606 IN UINTN Pages,
607 IN UINTN Alignment,
608 OUT VOID **HostAddress,
609 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
610 OUT VOID **Mapping
611 )
612 {
613 EFI_STATUS Status;
614 VOID *Memory;
615 UINTN AlignedMemory;
616 UINTN AlignmentMask;
617 UINTN UnalignedPages;
618 UINTN RealPages;
619 UINTN Bytes;
620
621 //
622 // Alignment must be a power of two or zero.
623 //
624 ASSERT ((Alignment & (Alignment - 1)) == 0);
625
626 if ((Alignment & (Alignment - 1)) != 0) {
627 return EFI_INVALID_PARAMETER;
628 }
629
630 if (Pages == 0) {
631 return EFI_INVALID_PARAMETER;
632 }
633
634 if (Alignment > EFI_PAGE_SIZE) {
635 //
636 // Calculate the total number of pages since alignment is larger than page size.
637 //
638 AlignmentMask = Alignment - 1;
639 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
640 //
641 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
642 //
643 ASSERT (RealPages > Pages);
644
645 Status = PciIo->AllocateBuffer (
646 PciIo,
647 AllocateAnyPages,
648 EfiBootServicesData,
649 RealPages,
650 &Memory,
651 0
652 );
653 if (EFI_ERROR (Status)) {
654 return EFI_OUT_OF_RESOURCES;
655 }
656
657 AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;
658 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
659 if (UnalignedPages > 0) {
660 //
661 // Free first unaligned page(s).
662 //
663 Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);
664 ASSERT_EFI_ERROR (Status);
665 }
666
667 Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
668 UnalignedPages = RealPages - Pages - UnalignedPages;
669 if (UnalignedPages > 0) {
670 //
671 // Free last unaligned page(s).
672 //
673 Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);
674 ASSERT_EFI_ERROR (Status);
675 }
676 } else {
677 //
678 // Do not over-allocate pages in this case.
679 //
680 Status = PciIo->AllocateBuffer (
681 PciIo,
682 AllocateAnyPages,
683 EfiBootServicesData,
684 Pages,
685 &Memory,
686 0
687 );
688 if (EFI_ERROR (Status)) {
689 return EFI_OUT_OF_RESOURCES;
690 }
691
692 AlignedMemory = (UINTN)Memory;
693 }
694
695 Bytes = EFI_PAGES_TO_SIZE (Pages);
696 Status = PciIo->Map (
697 PciIo,
698 EfiPciIoOperationBusMasterCommonBuffer,
699 (VOID *)AlignedMemory,
700 &Bytes,
701 DeviceAddress,
702 Mapping
703 );
704
705 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
706 Status = PciIo->FreeBuffer (PciIo, Pages, (VOID *)AlignedMemory);
707 return EFI_OUT_OF_RESOURCES;
708 }
709
710 *HostAddress = (VOID *)AlignedMemory;
711
712 return EFI_SUCCESS;
713 }
714
715 /**
716 Frees memory that was allocated with UsbHcAllocateAlignedPages().
717
718 @param PciIo The PciIo that can be used to access the host controller.
719 @param HostAddress The system memory address to map to the PCI controller.
720 @param Pages The number of 4 KB pages to free.
721 @param Mapping The mapping value returned from Map().
722
723 **/
724 VOID
725 UsbHcFreeAlignedPages (
726 IN EFI_PCI_IO_PROTOCOL *PciIo,
727 IN VOID *HostAddress,
728 IN UINTN Pages,
729 VOID *Mapping
730 )
731 {
732 EFI_STATUS Status;
733
734 ASSERT (Pages != 0);
735
736 Status = PciIo->Unmap (PciIo, Mapping);
737 ASSERT_EFI_ERROR (Status);
738
739 Status = PciIo->FreeBuffer (
740 PciIo,
741 Pages,
742 HostAddress
743 );
744 ASSERT_EFI_ERROR (Status);
745 }