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