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 } 759