TianoCore EDK2 master
Loading...
Searching...
No Matches
UsbHcMem.c
Go to the documentation of this file.
1
10#include "Xhci.h"
11
23 IN USBHC_MEM_POOL *Pool,
24 IN UINTN Pages
25 )
26{
27 USBHC_MEM_BLOCK *Block;
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,
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,
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
94FREE_BUFFER:
95 PciIo->FreeBuffer (PciIo, Pages, BufHost);
96
97FREE_BITARRAY:
98 gBS->FreePool (Block->Bits);
99 gBS->FreePool (Block);
100 return NULL;
101}
102
110VOID
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
143VOID *
145 IN USBHC_MEM_BLOCK *Block,
146 IN UINTN Units,
147 IN BOOLEAN AllocationForRing
148 )
149{
150 UINTN Byte;
151 UINT8 Bit;
152 UINTN StartByte;
153 UINT8 StartBit;
154 UINTN Available;
155 UINTN Count;
156 UINTN MemUnitAddr;
157 UINTN AlignmentMask;
158
159 ASSERT ((Block != 0) && (Units != 0));
160
161 StartByte = 0;
162 StartBit = 0;
163 Available = 0;
164 AlignmentMask = ~((UINTN)USBHC_MEM_TRB_RINGS_BOUNDARY - 1);
165
166 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
167 //
168 // If current bit is zero, the corresponding memory unit is
169 // available, otherwise we need to restart our searching.
170 // Available counts the consective number of zero bit.
171 //
172 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
173 if (AllocationForRing && (Available != 0)) {
174 MemUnitAddr = (UINTN)Block->BufHost + (Byte * 8 + Bit) * USBHC_MEM_UNIT;
175 if ((MemUnitAddr & AlignmentMask) != ((MemUnitAddr - USBHC_MEM_UNIT) & AlignmentMask)) {
176 //
177 // If the TRB Ring memory cross 64K-byte boundary, then restart the
178 // search starting at current memory unit.
179 // Doing so is to meet the TRB Ring boundary requirement in XHCI spec.
180 //
181 Available = 0;
182 StartByte = Byte;
183 StartBit = Bit;
184 }
185 }
186
187 Available++;
188
189 if (Available >= Units) {
190 break;
191 }
192
193 NEXT_BIT (Byte, Bit);
194 } else {
195 NEXT_BIT (Byte, Bit);
196
197 Available = 0;
198 StartByte = Byte;
199 StartBit = Bit;
200 }
201 }
202
203 if (Available < Units) {
204 return NULL;
205 }
206
207 //
208 // Mark the memory as allocated
209 //
210 Byte = StartByte;
211 Bit = StartBit;
212
213 for (Count = 0; Count < Units; Count++) {
214 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
215
216 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | USB_HC_BIT (Bit));
217 NEXT_BIT (Byte, Bit);
218 }
219
220 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
221}
222
236 IN USBHC_MEM_POOL *Pool,
237 IN VOID *Mem,
238 IN UINTN Size,
239 IN BOOLEAN Alignment
240 )
241{
242 USBHC_MEM_BLOCK *Head;
243 USBHC_MEM_BLOCK *Block;
244 UINTN AllocSize;
245 EFI_PHYSICAL_ADDRESS PhyAddr;
246 UINTN Offset;
247
248 Head = Pool->Head;
249 if (Alignment) {
250 AllocSize = USBHC_MEM_ROUND (Size);
251 } else {
252 AllocSize = Size;
253 }
254
255 if (Mem == NULL) {
256 return 0;
257 }
258
259 for (Block = Head; Block != NULL; Block = Block->Next) {
260 //
261 // scan the memory block list for the memory block that
262 // completely contains the allocated memory.
263 //
264 if ((Block->BufHost <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
265 break;
266 }
267 }
268
269 ASSERT ((Block != NULL));
270 //
271 // calculate the pci memory address for host memory address.
272 //
273 Offset = (UINT8 *)Mem - Block->BufHost;
274 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->Buf + Offset);
275 return PhyAddr;
276}
277
291 IN USBHC_MEM_POOL *Pool,
292 IN VOID *Mem,
293 IN UINTN Size,
294 IN BOOLEAN Alignment
295 )
296{
297 USBHC_MEM_BLOCK *Head;
298 USBHC_MEM_BLOCK *Block;
299 UINTN AllocSize;
300 EFI_PHYSICAL_ADDRESS HostAddr;
301 UINTN Offset;
302
303 Head = Pool->Head;
304 if (Alignment) {
305 AllocSize = USBHC_MEM_ROUND (Size);
306 } else {
307 AllocSize = Size;
308 }
309
310 if (Mem == NULL) {
311 return 0;
312 }
313
314 for (Block = Head; Block != NULL; Block = Block->Next) {
315 //
316 // scan the memory block list for the memory block that
317 // completely contains the allocated memory.
318 //
319 if ((Block->Buf <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {
320 break;
321 }
322 }
323
324 ASSERT ((Block != NULL));
325 //
326 // calculate the pci memory address for host memory address.
327 //
328 Offset = (UINT8 *)Mem - Block->Buf;
329 HostAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->BufHost + Offset);
330 return HostAddr;
331}
332
340VOID
342 IN USBHC_MEM_BLOCK *Head,
343 IN USBHC_MEM_BLOCK *Block
344 )
345{
346 ASSERT ((Head != NULL) && (Block != NULL));
347 Block->Next = Head->Next;
348 Head->Next = Block;
349}
350
360BOOLEAN
362 IN USBHC_MEM_BLOCK *Block
363 )
364{
365 UINTN Index;
366
367 for (Index = 0; Index < Block->BitsLen; Index++) {
368 if (Block->Bits[Index] != 0) {
369 return FALSE;
370 }
371 }
372
373 return TRUE;
374}
375
383VOID
385 IN USBHC_MEM_BLOCK *Head,
386 IN USBHC_MEM_BLOCK *BlockToUnlink
387 )
388{
389 USBHC_MEM_BLOCK *Block;
390
391 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
392
393 for (Block = Head; Block != NULL; Block = Block->Next) {
394 if (Block->Next == BlockToUnlink) {
395 Block->Next = BlockToUnlink->Next;
396 BlockToUnlink->Next = NULL;
397 break;
398 }
399 }
400}
401
414 )
415{
416 USBHC_MEM_POOL *Pool;
417
418 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
419
420 if (Pool == NULL) {
421 return Pool;
422 }
423
424 Pool->PciIo = PciIo;
425 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
426
427 if (Pool->Head == NULL) {
428 gBS->FreePool (Pool);
429 Pool = NULL;
430 }
431
432 return Pool;
433}
434
446 IN USBHC_MEM_POOL *Pool
447 )
448{
449 USBHC_MEM_BLOCK *Block;
450
451 ASSERT (Pool->Head != NULL);
452
453 //
454 // Unlink all the memory blocks from the pool, then free them.
455 // UsbHcUnlinkMemBlock can't be used to unlink and free the
456 // first block.
457 //
458 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
459 UsbHcUnlinkMemBlock (Pool->Head, Block);
460 UsbHcFreeMemBlock (Pool, Block);
461 }
462
463 UsbHcFreeMemBlock (Pool, Pool->Head);
464 gBS->FreePool (Pool);
465 return EFI_SUCCESS;
466}
467
479VOID *
481 IN USBHC_MEM_POOL *Pool,
482 IN UINTN Size,
483 IN BOOLEAN AllocationForRing
484 )
485{
486 USBHC_MEM_BLOCK *Head;
487 USBHC_MEM_BLOCK *Block;
488 USBHC_MEM_BLOCK *NewBlock;
489 VOID *Mem;
490 UINTN AllocSize;
491 UINTN Pages;
492
493 Mem = NULL;
494 AllocSize = USBHC_MEM_ROUND (Size);
495 Head = Pool->Head;
496 ASSERT (Head != NULL);
497
498 //
499 // First check whether current memory blocks can satisfy the allocation.
500 //
501 for (Block = Head; Block != NULL; Block = Block->Next) {
502 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT, AllocationForRing);
503
504 if (Mem != NULL) {
505 ZeroMem (Mem, Size);
506 break;
507 }
508 }
509
510 if (Mem != NULL) {
511 return Mem;
512 }
513
514 //
515 // Create a new memory block if there is not enough memory
516 // in the pool. If the allocation size is larger than the
517 // default page number, just allocate a large enough memory
518 // block. Otherwise allocate default pages.
519 //
520 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
521 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
522 } else {
523 Pages = USBHC_MEM_DEFAULT_PAGES;
524 }
525
526 NewBlock = UsbHcAllocMemBlock (Pool, Pages);
527
528 if (NewBlock == NULL) {
529 DEBUG ((DEBUG_ERROR, "UsbHcAllocateMem: failed to allocate block\n"));
530 return NULL;
531 }
532
533 //
534 // Add the new memory block to the pool, then allocate memory from it
535 //
536 UsbHcInsertMemBlockToPool (Head, NewBlock);
537 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT, AllocationForRing);
538
539 if (Mem != NULL) {
540 ZeroMem (Mem, Size);
541 }
542
543 return Mem;
544}
545
554VOID
556 IN USBHC_MEM_POOL *Pool,
557 IN VOID *Mem,
558 IN UINTN Size
559 )
560{
561 USBHC_MEM_BLOCK *Head;
562 USBHC_MEM_BLOCK *Block;
563 UINT8 *ToFree;
564 UINTN AllocSize;
565 UINTN Byte;
566 UINTN Bit;
567 UINTN Count;
568
569 Head = Pool->Head;
570 AllocSize = USBHC_MEM_ROUND (Size);
571 ToFree = (UINT8 *)Mem;
572
573 for (Block = Head; Block != NULL; Block = Block->Next) {
574 //
575 // scan the memory block list for the memory block that
576 // completely contains the memory to free.
577 //
578 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
579 //
580 // compute the start byte and bit in the bit array
581 //
582 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
583 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
584
585 //
586 // reset associated bits in bit array
587 //
588 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
589 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
590
591 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ USB_HC_BIT (Bit));
592 NEXT_BIT (Byte, Bit);
593 }
594
595 break;
596 }
597 }
598
599 //
600 // If Block == NULL, it means that the current memory isn't
601 // in the host controller's pool. This is critical because
602 // the caller has passed in a wrong memory point
603 //
604 ASSERT (Block != NULL);
605
606 //
607 // Release the current memory block if it is empty and not the head
608 //
609 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
610 UsbHcUnlinkMemBlock (Head, Block);
611 UsbHcFreeMemBlock (Pool, Block);
612 }
613
614 return;
615}
616
638 IN EFI_PCI_IO_PROTOCOL *PciIo,
639 IN UINTN Pages,
640 IN UINTN Alignment,
641 OUT VOID **HostAddress,
642 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
643 OUT VOID **Mapping
644 )
645{
646 EFI_STATUS Status;
647 VOID *Memory;
648 UINTN AlignedMemory;
649 UINTN AlignmentMask;
650 UINTN UnalignedPages;
651 UINTN RealPages;
652 UINTN Bytes;
653
654 //
655 // Alignment must be a power of two or zero.
656 //
657 ASSERT ((Alignment & (Alignment - 1)) == 0);
658
659 if ((Alignment & (Alignment - 1)) != 0) {
660 return EFI_INVALID_PARAMETER;
661 }
662
663 if (Pages == 0) {
664 return EFI_INVALID_PARAMETER;
665 }
666
667 if (Alignment > EFI_PAGE_SIZE) {
668 //
669 // Calculate the total number of pages since alignment is larger than page size.
670 //
671 AlignmentMask = Alignment - 1;
672 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
673 //
674 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
675 //
676 ASSERT (RealPages > Pages);
677
678 Status = PciIo->AllocateBuffer (
679 PciIo,
682 RealPages,
683 &Memory,
684 0
685 );
686 if (EFI_ERROR (Status)) {
687 return EFI_OUT_OF_RESOURCES;
688 }
689
690 AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;
691 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
692 if (UnalignedPages > 0) {
693 //
694 // Free first unaligned page(s).
695 //
696 Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);
697 ASSERT_EFI_ERROR (Status);
698 }
699
700 Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
701 UnalignedPages = RealPages - Pages - UnalignedPages;
702 if (UnalignedPages > 0) {
703 //
704 // Free last unaligned page(s).
705 //
706 Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);
707 ASSERT_EFI_ERROR (Status);
708 }
709 } else {
710 //
711 // Do not over-allocate pages in this case.
712 //
713 Status = PciIo->AllocateBuffer (
714 PciIo,
717 Pages,
718 &Memory,
719 0
720 );
721 if (EFI_ERROR (Status)) {
722 return EFI_OUT_OF_RESOURCES;
723 }
724
725 AlignedMemory = (UINTN)Memory;
726 }
727
728 Bytes = EFI_PAGES_TO_SIZE (Pages);
729 Status = PciIo->Map (
730 PciIo,
732 (VOID *)AlignedMemory,
733 &Bytes,
734 DeviceAddress,
735 Mapping
736 );
737
738 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
739 Status = PciIo->FreeBuffer (PciIo, Pages, (VOID *)AlignedMemory);
740 return EFI_OUT_OF_RESOURCES;
741 }
742
743 *HostAddress = (VOID *)AlignedMemory;
744
745 return EFI_SUCCESS;
746}
747
757VOID
759 IN EFI_PCI_IO_PROTOCOL *PciIo,
760 IN VOID *HostAddress,
761 IN UINTN Pages,
762 VOID *Mapping
763 )
764{
765 EFI_STATUS Status;
766
767 ASSERT (Pages != 0);
768
769 Status = PciIo->Unmap (PciIo, Mapping);
770 ASSERT_EFI_ERROR (Status);
771
772 Status = PciIo->FreeBuffer (
773 PciIo,
774 Pages,
775 HostAddress
776 );
777 ASSERT_EFI_ERROR (Status);
778}
UINT64 UINTN
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID * UsbHcAllocMemFromBlock(IN USBHC_MEM_BLOCK *Block, IN UINTN Units)
Definition: UsbHcMem.c:152
EFI_STATUS UsbHcFreeMemPool(IN USBHC_MEM_POOL *Pool)
Definition: UsbHcMem.c:385
VOID UsbHcFreeMemBlock(IN USBHC_MEM_POOL *Pool, IN USBHC_MEM_BLOCK *Block)
Definition: UsbHcMem.c:120
BOOLEAN UsbHcIsMemBlockEmpty(IN USBHC_MEM_BLOCK *Block)
Definition: UsbHcMem.c:294
VOID UsbHcFreeMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:493
VOID * UsbHcAllocateMem(IN USBHC_MEM_POOL *Pool, IN UINTN Size)
Definition: UsbHcMem.c:419
USBHC_MEM_BLOCK * UsbHcAllocMemBlock(IN USBHC_MEM_POOL *Pool, IN UINTN Pages)
Definition: UsbHcMem.c:22
VOID UsbHcUnlinkMemBlock(IN USBHC_MEM_BLOCK *Head, IN USBHC_MEM_BLOCK *BlockToUnlink)
Definition: UsbHcMem.c:317
VOID UsbHcInsertMemBlockToPool(IN USBHC_MEM_BLOCK *Head, IN USBHC_MEM_BLOCK *Block)
Definition: UsbHcMem.c:274
USBHC_MEM_POOL * UsbHcInitMemPool(IN EFI_PCI_IO_PROTOCOL *PciIo, IN BOOLEAN Check4G, IN UINT32 Which4G)
Definition: UsbHcMem.c:348
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
@ EfiPciIoOperationBusMasterCommonBuffer
Definition: PciIo.h:90
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ EfiBootServicesData
@ AllocateAnyPages
Definition: UefiSpec.h:33
EFI_PHYSICAL_ADDRESS UsbHcGetPciAddrForHostAddr(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size, IN BOOLEAN Alignment)
Definition: UsbHcMem.c:235
EFI_STATUS UsbHcAllocateAlignedPages(IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINTN Pages, IN UINTN Alignment, OUT VOID **HostAddress, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: UsbHcMem.c:637
EFI_PHYSICAL_ADDRESS UsbHcGetHostAddrForPciAddr(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size, IN BOOLEAN Alignment)
Definition: UsbHcMem.c:290
VOID UsbHcFreeAlignedPages(IN EFI_PCI_IO_PROTOCOL *PciIo, IN VOID *HostAddress, IN UINTN Pages, VOID *Mapping)
Definition: UsbHcMem.c:758