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