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 - 2016, 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   Create a command transfer TRB to support XHCI command interfaces.
     22 
     23   @param  Xhc       The XHCI device.
     24   @param  CmdTrb    The cmd TRB to be executed.
     25 
     26   @return Created URB or NULL.
     27 
     28 **/
     29 URB*
     30 XhcPeiCreateCmdTrb (
     31   IN PEI_XHC_DEV    *Xhc,
     32   IN TRB_TEMPLATE   *CmdTrb
     33   )
     34 {
     35   URB   *Urb;
     36 
     37   Urb = AllocateZeroPool (sizeof (URB));
     38   if (Urb == NULL) {
     39     return NULL;
     40   }
     41 
     42   Urb->Signature  = XHC_URB_SIG;
     43 
     44   Urb->Ring       = &Xhc->CmdRing;
     45   XhcPeiSyncTrsRing (Xhc, Urb->Ring);
     46   Urb->TrbNum     = 1;
     47   Urb->TrbStart   = Urb->Ring->RingEnqueue;
     48   CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
     49   Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
     50   Urb->TrbEnd             = Urb->TrbStart;
     51 
     52   return Urb;
     53 }
     54 
     55 /**
     56   Execute a XHCI cmd TRB pointed by CmdTrb.
     57 
     58   @param  Xhc                   The XHCI device.
     59   @param  CmdTrb                The cmd TRB to be executed.
     60   @param  Timeout               Indicates the maximum time, in millisecond, which the
     61                                 transfer is allowed to complete.
     62   @param  EvtTrb                The event TRB corresponding to the cmd TRB.
     63 
     64   @retval EFI_SUCCESS           The transfer was completed successfully.
     65   @retval EFI_INVALID_PARAMETER Some parameters are invalid.
     66   @retval EFI_TIMEOUT           The transfer failed due to timeout.
     67   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
     68 
     69 **/
     70 EFI_STATUS
     71 XhcPeiCmdTransfer (
     72   IN PEI_XHC_DEV                *Xhc,
     73   IN TRB_TEMPLATE               *CmdTrb,
     74   IN UINTN                      Timeout,
     75   OUT TRB_TEMPLATE              **EvtTrb
     76   )
     77 {
     78   EFI_STATUS    Status;
     79   URB           *Urb;
     80 
     81   //
     82   // Validate the parameters
     83   //
     84   if ((Xhc == NULL) || (CmdTrb == NULL)) {
     85     return EFI_INVALID_PARAMETER;
     86   }
     87 
     88   Status = EFI_DEVICE_ERROR;
     89 
     90   if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
     91     DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
     92     goto ON_EXIT;
     93   }
     94 
     95   //
     96   // Create a new URB, then poll the execution status.
     97   //
     98   Urb = XhcPeiCreateCmdTrb (Xhc, CmdTrb);
     99   if (Urb == NULL) {
    100     DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));
    101     Status = EFI_OUT_OF_RESOURCES;
    102     goto ON_EXIT;
    103   }
    104 
    105   Status  = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);
    106   *EvtTrb = Urb->EvtTrb;
    107 
    108   if (Urb->Result == EFI_USB_NOERROR) {
    109     Status = EFI_SUCCESS;
    110   }
    111 
    112   XhcPeiFreeUrb (Xhc, Urb);
    113 
    114 ON_EXIT:
    115   return Status;
    116 }
    117 
    118 /**
    119   Create a new URB for a new transaction.
    120 
    121   @param  Xhc       The XHCI device
    122   @param  BusAddr   The logical device address assigned by UsbBus driver
    123   @param  EpAddr    Endpoint addrress
    124   @param  DevSpeed  The device speed
    125   @param  MaxPacket The max packet length of the endpoint
    126   @param  Type      The transaction type
    127   @param  Request   The standard USB request for control transfer
    128   @param  Data      The user data to transfer
    129   @param  DataLen   The length of data buffer
    130   @param  Callback  The function to call when data is transferred
    131   @param  Context   The context to the callback
    132 
    133   @return Created URB or NULL
    134 
    135 **/
    136 URB*
    137 XhcPeiCreateUrb (
    138   IN PEI_XHC_DEV                        *Xhc,
    139   IN UINT8                              BusAddr,
    140   IN UINT8                              EpAddr,
    141   IN UINT8                              DevSpeed,
    142   IN UINTN                              MaxPacket,
    143   IN UINTN                              Type,
    144   IN EFI_USB_DEVICE_REQUEST             *Request,
    145   IN VOID                               *Data,
    146   IN UINTN                              DataLen,
    147   IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
    148   IN VOID                               *Context
    149   )
    150 {
    151   USB_ENDPOINT      *Ep;
    152   EFI_STATUS        Status;
    153   URB               *Urb;
    154 
    155   Urb = AllocateZeroPool (sizeof (URB));
    156   if (Urb == NULL) {
    157     return NULL;
    158   }
    159 
    160   Urb->Signature = XHC_URB_SIG;
    161 
    162   Ep            = &Urb->Ep;
    163   Ep->BusAddr   = BusAddr;
    164   Ep->EpAddr    = (UINT8) (EpAddr & 0x0F);
    165   Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
    166   Ep->DevSpeed  = DevSpeed;
    167   Ep->MaxPacket = MaxPacket;
    168   Ep->Type      = Type;
    169 
    170   Urb->Request  = Request;
    171   Urb->Data     = Data;
    172   Urb->DataLen  = DataLen;
    173   Urb->Callback = Callback;
    174   Urb->Context  = Context;
    175 
    176   Status = XhcPeiCreateTransferTrb (Xhc, Urb);
    177   if (EFI_ERROR (Status)) {
    178     DEBUG ((EFI_D_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));
    179     FreePool (Urb);
    180     Urb = NULL;
    181   }
    182 
    183   return Urb;
    184 }
    185 
    186 /**
    187   Free an allocated URB.
    188 
    189   @param  Xhc       The XHCI device.
    190   @param  Urb       The URB to free.
    191 
    192 **/
    193 VOID
    194 XhcPeiFreeUrb (
    195   IN PEI_XHC_DEV    *Xhc,
    196   IN URB            *Urb
    197   )
    198 {
    199   if ((Xhc == NULL) || (Urb == NULL)) {
    200     return;
    201   }
    202 
    203   FreePool (Urb);
    204 }
    205 
    206 /**
    207   Create a transfer TRB.
    208 
    209   @param  Xhc       The XHCI device
    210   @param  Urb       The urb used to construct the transfer TRB.
    211 
    212   @return Created TRB or NULL
    213 
    214 **/
    215 EFI_STATUS
    216 XhcPeiCreateTransferTrb (
    217   IN PEI_XHC_DEV    *Xhc,
    218   IN URB            *Urb
    219   )
    220 {
    221   VOID                          *OutputContext;
    222   TRANSFER_RING                 *EPRing;
    223   UINT8                         EPType;
    224   UINT8                         SlotId;
    225   UINT8                         Dci;
    226   TRB                           *TrbStart;
    227   UINTN                         TotalLen;
    228   UINTN                         Len;
    229   UINTN                         TrbNum;
    230 
    231   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
    232   if (SlotId == 0) {
    233     return EFI_DEVICE_ERROR;
    234   }
    235 
    236   Urb->Finished  = FALSE;
    237   Urb->StartDone = FALSE;
    238   Urb->EndDone   = FALSE;
    239   Urb->Completed = 0;
    240   Urb->Result    = EFI_USB_NOERROR;
    241 
    242   Dci       = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
    243   EPRing    = (TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
    244   Urb->Ring = EPRing;
    245   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
    246   if (Xhc->HcCParams.Data.Csz == 0) {
    247     EPType  = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
    248   } else {
    249     EPType  = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
    250   }
    251 
    252   Urb->DataPhy = Urb->Data;
    253 
    254   //
    255   // Construct the TRB
    256   //
    257   XhcPeiSyncTrsRing (Xhc, EPRing);
    258   Urb->TrbStart = EPRing->RingEnqueue;
    259   switch (EPType) {
    260     case ED_CONTROL_BIDIR:
    261       //
    262       // For control transfer, create SETUP_STAGE_TRB first.
    263       //
    264       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
    265       TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
    266       TrbStart->TrbCtrSetup.bRequest      = Urb->Request->Request;
    267       TrbStart->TrbCtrSetup.wValue        = Urb->Request->Value;
    268       TrbStart->TrbCtrSetup.wIndex        = Urb->Request->Index;
    269       TrbStart->TrbCtrSetup.wLength       = Urb->Request->Length;
    270       TrbStart->TrbCtrSetup.Length        = 8;
    271       TrbStart->TrbCtrSetup.IntTarget     = 0;
    272       TrbStart->TrbCtrSetup.IOC           = 1;
    273       TrbStart->TrbCtrSetup.IDT           = 1;
    274       TrbStart->TrbCtrSetup.Type          = TRB_TYPE_SETUP_STAGE;
    275       if (Urb->Ep.Direction == EfiUsbDataIn) {
    276         TrbStart->TrbCtrSetup.TRT = 3;
    277       } else if (Urb->Ep.Direction == EfiUsbDataOut) {
    278         TrbStart->TrbCtrSetup.TRT = 2;
    279       } else {
    280         TrbStart->TrbCtrSetup.TRT = 0;
    281       }
    282       //
    283       // Update the cycle bit
    284       //
    285       TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
    286       Urb->TrbNum++;
    287 
    288       //
    289       // For control transfer, create DATA_STAGE_TRB.
    290       //
    291       if (Urb->DataLen > 0) {
    292         XhcPeiSyncTrsRing (Xhc, EPRing);
    293         TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
    294         TrbStart->TrbCtrData.TRBPtrLo  = XHC_LOW_32BIT (Urb->DataPhy);
    295         TrbStart->TrbCtrData.TRBPtrHi  = XHC_HIGH_32BIT (Urb->DataPhy);
    296         TrbStart->TrbCtrData.Length    = (UINT32) Urb->DataLen;
    297         TrbStart->TrbCtrData.TDSize    = 0;
    298         TrbStart->TrbCtrData.IntTarget = 0;
    299         TrbStart->TrbCtrData.ISP       = 1;
    300         TrbStart->TrbCtrData.IOC       = 1;
    301         TrbStart->TrbCtrData.IDT       = 0;
    302         TrbStart->TrbCtrData.CH        = 0;
    303         TrbStart->TrbCtrData.Type      = TRB_TYPE_DATA_STAGE;
    304         if (Urb->Ep.Direction == EfiUsbDataIn) {
    305           TrbStart->TrbCtrData.DIR = 1;
    306         } else if (Urb->Ep.Direction == EfiUsbDataOut) {
    307           TrbStart->TrbCtrData.DIR = 0;
    308         } else {
    309           TrbStart->TrbCtrData.DIR = 0;
    310         }
    311         //
    312         // Update the cycle bit
    313         //
    314         TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
    315         Urb->TrbNum++;
    316       }
    317       //
    318       // For control transfer, create STATUS_STAGE_TRB.
    319       // Get the pointer to next TRB for status stage use
    320       //
    321       XhcPeiSyncTrsRing (Xhc, EPRing);
    322       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
    323       TrbStart->TrbCtrStatus.IntTarget = 0;
    324       TrbStart->TrbCtrStatus.IOC       = 1;
    325       TrbStart->TrbCtrStatus.CH        = 0;
    326       TrbStart->TrbCtrStatus.Type      = TRB_TYPE_STATUS_STAGE;
    327       if (Urb->Ep.Direction == EfiUsbDataIn) {
    328         TrbStart->TrbCtrStatus.DIR = 0;
    329       } else if (Urb->Ep.Direction == EfiUsbDataOut) {
    330         TrbStart->TrbCtrStatus.DIR = 1;
    331       } else {
    332         TrbStart->TrbCtrStatus.DIR = 0;
    333       }
    334       //
    335       // Update the cycle bit
    336       //
    337       TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
    338       //
    339       // Update the enqueue pointer
    340       //
    341       XhcPeiSyncTrsRing (Xhc, EPRing);
    342       Urb->TrbNum++;
    343       Urb->TrbEnd = (TRB_TEMPLATE *) (UINTN) TrbStart;
    344 
    345       break;
    346 
    347     case ED_BULK_OUT:
    348     case ED_BULK_IN:
    349       TotalLen = 0;
    350       Len      = 0;
    351       TrbNum   = 0;
    352       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
    353       while (TotalLen < Urb->DataLen) {
    354         if ((TotalLen + 0x10000) >= Urb->DataLen) {
    355           Len = Urb->DataLen - TotalLen;
    356         } else {
    357           Len = 0x10000;
    358         }
    359         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
    360         TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
    361         TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
    362         TrbStart->TrbNormal.Length    = (UINT32) Len;
    363         TrbStart->TrbNormal.TDSize    = 0;
    364         TrbStart->TrbNormal.IntTarget = 0;
    365         TrbStart->TrbNormal.ISP       = 1;
    366         TrbStart->TrbNormal.IOC       = 1;
    367         TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;
    368         //
    369         // Update the cycle bit
    370         //
    371         TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
    372 
    373         XhcPeiSyncTrsRing (Xhc, EPRing);
    374         TrbNum++;
    375         TotalLen += Len;
    376       }
    377 
    378       Urb->TrbNum = TrbNum;
    379       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
    380       break;
    381 
    382     case ED_INTERRUPT_OUT:
    383     case ED_INTERRUPT_IN:
    384       TotalLen = 0;
    385       Len      = 0;
    386       TrbNum   = 0;
    387       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
    388       while (TotalLen < Urb->DataLen) {
    389         if ((TotalLen + 0x10000) >= Urb->DataLen) {
    390           Len = Urb->DataLen - TotalLen;
    391         } else {
    392           Len = 0x10000;
    393         }
    394         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
    395         TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
    396         TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
    397         TrbStart->TrbNormal.Length    = (UINT32) Len;
    398         TrbStart->TrbNormal.TDSize    = 0;
    399         TrbStart->TrbNormal.IntTarget = 0;
    400         TrbStart->TrbNormal.ISP       = 1;
    401         TrbStart->TrbNormal.IOC       = 1;
    402         TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;
    403         //
    404         // Update the cycle bit
    405         //
    406         TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
    407 
    408         XhcPeiSyncTrsRing (Xhc, EPRing);
    409         TrbNum++;
    410         TotalLen += Len;
    411       }
    412 
    413       Urb->TrbNum = TrbNum;
    414       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
    415       break;
    416 
    417     default:
    418       DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
    419       ASSERT (FALSE);
    420       break;
    421   }
    422 
    423   return EFI_SUCCESS;
    424 }
    425 
    426 /**
    427   System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
    428   condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
    429   Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
    430   reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
    431   Stopped to the Running state.
    432 
    433   @param  Xhc           The XHCI device.
    434   @param  Urb           The urb which makes the endpoint halted.
    435 
    436   @retval EFI_SUCCESS   The recovery is successful.
    437   @retval Others        Failed to recovery halted endpoint.
    438 
    439 **/
    440 EFI_STATUS
    441 XhcPeiRecoverHaltedEndpoint (
    442   IN PEI_XHC_DEV        *Xhc,
    443   IN URB                *Urb
    444   )
    445 {
    446   EFI_STATUS                  Status;
    447   UINT8                       Dci;
    448   UINT8                       SlotId;
    449 
    450   Status = EFI_SUCCESS;
    451   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
    452   if (SlotId == 0) {
    453     return EFI_DEVICE_ERROR;
    454   }
    455   Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));
    456 
    457   DEBUG ((EFI_D_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));
    458 
    459   //
    460   // 1) Send Reset endpoint command to transit from halt to stop state
    461   //
    462   Status = XhcPeiResetEndpoint (Xhc, SlotId, Dci);
    463   if (EFI_ERROR(Status)) {
    464     DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
    465     goto Done;
    466   }
    467 
    468   //
    469   // 2) Set dequeue pointer
    470   //
    471   Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
    472   if (EFI_ERROR(Status)) {
    473     DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
    474     goto Done;
    475   }
    476 
    477   //
    478   // 3) Ring the doorbell to transit from stop to active
    479   //
    480   XhcPeiRingDoorBell (Xhc, SlotId, Dci);
    481 
    482 Done:
    483   return Status;
    484 }
    485 
    486 /**
    487   System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
    488   Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
    489   the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
    490   state.
    491 
    492   @param  Xhc                   The XHCI device.
    493   @param  Urb                   The urb which doesn't get completed in a specified timeout range.
    494 
    495   @retval EFI_SUCCESS           The dequeuing of the TDs is successful.
    496   @retval Others                Failed to stop the endpoint and dequeue the TDs.
    497 
    498 **/
    499 EFI_STATUS
    500 XhcPeiDequeueTrbFromEndpoint (
    501   IN PEI_XHC_DEV        *Xhc,
    502   IN URB                *Urb
    503   )
    504 {
    505   EFI_STATUS                  Status;
    506   UINT8                       Dci;
    507   UINT8                       SlotId;
    508 
    509   Status = EFI_SUCCESS;
    510   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
    511   if (SlotId == 0) {
    512     return EFI_DEVICE_ERROR;
    513   }
    514   Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));
    515 
    516   DEBUG ((EFI_D_INFO, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId, Dci));
    517 
    518   //
    519   // 1) Send Stop endpoint command to stop endpoint.
    520   //
    521   Status = XhcPeiStopEndpoint (Xhc, SlotId, Dci);
    522   if (EFI_ERROR(Status)) {
    523     DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
    524     goto Done;
    525   }
    526 
    527   //
    528   // 2) Set dequeue pointer
    529   //
    530   Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
    531   if (EFI_ERROR(Status)) {
    532     DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
    533     goto Done;
    534   }
    535 
    536   //
    537   // 3) Ring the doorbell to transit from stop to active
    538   //
    539   XhcPeiRingDoorBell (Xhc, SlotId, Dci);
    540 
    541 Done:
    542   return Status;
    543 }
    544 
    545 /**
    546   Check if the Trb is a transaction of the URB.
    547 
    548   @param Trb        The TRB to be checked
    549   @param Urb        The transfer ring to be checked.
    550 
    551   @retval TRUE      It is a transaction of the URB.
    552   @retval FALSE     It is not any transaction of the URB.
    553 
    554 **/
    555 BOOLEAN
    556 XhcPeiIsTransferRingTrb (
    557   IN TRB_TEMPLATE   *Trb,
    558   IN URB            *Urb
    559   )
    560 {
    561   TRB_TEMPLATE  *CheckedTrb;
    562   UINTN         Index;
    563 
    564   CheckedTrb = Urb->Ring->RingSeg0;
    565 
    566   ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
    567 
    568   for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
    569     if (Trb == CheckedTrb) {
    570       return TRUE;
    571     }
    572     CheckedTrb++;
    573   }
    574 
    575   return FALSE;
    576 }
    577 
    578 /**
    579   Check the URB's execution result and update the URB's
    580   result accordingly.
    581 
    582   @param  Xhc               The XHCI device.
    583   @param  Urb               The URB to check result.
    584 
    585   @return Whether the result of URB transfer is finialized.
    586 
    587 **/
    588 BOOLEAN
    589 XhcPeiCheckUrbResult (
    590   IN PEI_XHC_DEV            *Xhc,
    591   IN URB                    *Urb
    592   )
    593 {
    594   EVT_TRB_TRANSFER          *EvtTrb;
    595   TRB_TEMPLATE              *TRBPtr;
    596   UINTN                     Index;
    597   UINT8                     TRBType;
    598   EFI_STATUS                Status;
    599   URB                       *CheckedUrb;
    600   UINT64                    XhcDequeue;
    601   UINT32                    High;
    602   UINT32                    Low;
    603   EFI_PHYSICAL_ADDRESS      PhyAddr;
    604 
    605   ASSERT ((Xhc != NULL) && (Urb != NULL));
    606 
    607   Status = EFI_SUCCESS;
    608 
    609   if (Urb->Finished) {
    610     goto EXIT;
    611   }
    612 
    613   EvtTrb = NULL;
    614 
    615   if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
    616     Urb->Result |= EFI_USB_ERR_SYSTEM;
    617     goto EXIT;
    618   }
    619 
    620   //
    621   // Traverse the event ring to find out all new events from the previous check.
    622   //
    623   XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);
    624   for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
    625     Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **) &EvtTrb));
    626     if (Status == EFI_NOT_READY) {
    627       //
    628       // All new events are handled, return directly.
    629       //
    630       goto EXIT;
    631     }
    632 
    633     //
    634     // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
    635     //
    636     if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
    637       continue;
    638     }
    639 
    640     //
    641     // Need convert pci device address to host address
    642     //
    643     PhyAddr = (EFI_PHYSICAL_ADDRESS) (EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
    644     TRBPtr = (TRB_TEMPLATE *) (UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *) (UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
    645 
    646     //
    647     // Update the status of Urb according to the finished event regardless of whether
    648     // the urb is current checked one or in the XHCI's async transfer list.
    649     // This way is used to avoid that those completed async transfer events don't get
    650     // handled in time and are flushed by newer coming events.
    651     //
    652     if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {
    653       CheckedUrb = Urb;
    654     } else {
    655       continue;
    656     }
    657 
    658     switch (EvtTrb->Completecode) {
    659       case TRB_COMPLETION_STALL_ERROR:
    660         CheckedUrb->Result  |= EFI_USB_ERR_STALL;
    661         CheckedUrb->Finished = TRUE;
    662         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));
    663         goto EXIT;
    664 
    665       case TRB_COMPLETION_BABBLE_ERROR:
    666         CheckedUrb->Result  |= EFI_USB_ERR_BABBLE;
    667         CheckedUrb->Finished = TRUE;
    668         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));
    669         goto EXIT;
    670 
    671       case TRB_COMPLETION_DATA_BUFFER_ERROR:
    672         CheckedUrb->Result  |= EFI_USB_ERR_BUFFER;
    673         CheckedUrb->Finished = TRUE;
    674         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));
    675         goto EXIT;
    676 
    677       case TRB_COMPLETION_USB_TRANSACTION_ERROR:
    678         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
    679         CheckedUrb->Finished = TRUE;
    680         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));
    681         goto EXIT;
    682 
    683       case TRB_COMPLETION_SHORT_PACKET:
    684       case TRB_COMPLETION_SUCCESS:
    685         if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
    686           DEBUG ((EFI_D_VERBOSE, "XhcPeiCheckUrbResult: short packet happens!\n"));
    687         }
    688 
    689         TRBType = (UINT8) (TRBPtr->Type);
    690         if ((TRBType == TRB_TYPE_DATA_STAGE) ||
    691             (TRBType == TRB_TYPE_NORMAL) ||
    692             (TRBType == TRB_TYPE_ISOCH)) {
    693           CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
    694         }
    695 
    696         break;
    697 
    698       default:
    699         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));
    700         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
    701         CheckedUrb->Finished = TRUE;
    702         goto EXIT;
    703     }
    704 
    705     //
    706     // Only check first and end Trb event address
    707     //
    708     if (TRBPtr == CheckedUrb->TrbStart) {
    709       CheckedUrb->StartDone = TRUE;
    710     }
    711 
    712     if (TRBPtr == CheckedUrb->TrbEnd) {
    713       CheckedUrb->EndDone = TRUE;
    714     }
    715 
    716     if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
    717       CheckedUrb->Finished = TRUE;
    718       CheckedUrb->EvtTrb   = (TRB_TEMPLATE *) EvtTrb;
    719     }
    720   }
    721 
    722 EXIT:
    723 
    724   //
    725   // Advance event ring to last available entry
    726   //
    727   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
    728   // So divide it to two 32-bytes width register access.
    729   //
    730   Low  = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
    731   High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
    732   XhcDequeue = (UINT64) (LShiftU64((UINT64) High, 32) | Low);
    733 
    734   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
    735 
    736   if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
    737     //
    738     // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
    739     // So divide it to two 32-bytes width register access.
    740     //
    741     XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
    742     XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
    743   }
    744 
    745   return Urb->Finished;
    746 }
    747 
    748 /**
    749   Execute the transfer by polling the URB. This is a synchronous operation.
    750 
    751   @param  Xhc               The XHCI device.
    752   @param  CmdTransfer       The executed URB is for cmd transfer or not.
    753   @param  Urb               The URB to execute.
    754   @param  Timeout           The time to wait before abort, in millisecond.
    755 
    756   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
    757   @return EFI_TIMEOUT       The transfer failed due to time out.
    758   @return EFI_SUCCESS       The transfer finished OK.
    759 
    760 **/
    761 EFI_STATUS
    762 XhcPeiExecTransfer (
    763   IN PEI_XHC_DEV            *Xhc,
    764   IN BOOLEAN                CmdTransfer,
    765   IN URB                    *Urb,
    766   IN UINTN                  Timeout
    767   )
    768 {
    769   EFI_STATUS    Status;
    770   UINTN         Index;
    771   UINT64        Loop;
    772   UINT8         SlotId;
    773   UINT8         Dci;
    774   BOOLEAN       Finished;
    775 
    776   if (CmdTransfer) {
    777     SlotId = 0;
    778     Dci    = 0;
    779   } else {
    780     SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
    781     if (SlotId == 0) {
    782       return EFI_DEVICE_ERROR;
    783     }
    784     Dci  = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
    785   }
    786 
    787   Status = EFI_SUCCESS;
    788   Loop   = Timeout * XHC_1_MILLISECOND;
    789   if (Timeout == 0) {
    790     Loop = 0xFFFFFFFF;
    791   }
    792 
    793   XhcPeiRingDoorBell (Xhc, SlotId, Dci);
    794 
    795   for (Index = 0; Index < Loop; Index++) {
    796     Finished = XhcPeiCheckUrbResult (Xhc, Urb);
    797     if (Finished) {
    798       break;
    799     }
    800     MicroSecondDelay (XHC_1_MICROSECOND);
    801   }
    802 
    803   if (Index == Loop) {
    804     Urb->Result = EFI_USB_ERR_TIMEOUT;
    805     Status      = EFI_TIMEOUT;
    806   } else if (Urb->Result != EFI_USB_NOERROR) {
    807     Status      = EFI_DEVICE_ERROR;
    808   }
    809 
    810   return Status;
    811 }
    812 
    813 /**
    814   Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
    815 
    816   @param  Xhc               The XHCI device.
    817   @param  ParentRouteChart  The route string pointed to the parent device if it exists.
    818   @param  Port              The port to be polled.
    819   @param  PortState         The port state.
    820 
    821   @retval EFI_SUCCESS       Successfully enable/disable device slot according to port state.
    822   @retval Others            Should not appear.
    823 
    824 **/
    825 EFI_STATUS
    826 XhcPeiPollPortStatusChange (
    827   IN PEI_XHC_DEV            *Xhc,
    828   IN USB_DEV_ROUTE          ParentRouteChart,
    829   IN UINT8                  Port,
    830   IN EFI_USB_PORT_STATUS    *PortState
    831   )
    832 {
    833   EFI_STATUS        Status;
    834   UINT8             Speed;
    835   UINT8             SlotId;
    836   USB_DEV_ROUTE     RouteChart;
    837 
    838   DEBUG ((EFI_D_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));
    839 
    840   Status = EFI_SUCCESS;
    841 
    842   if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
    843     return EFI_SUCCESS;
    844   }
    845 
    846   if (ParentRouteChart.Dword == 0) {
    847     RouteChart.Route.RouteString = 0;
    848     RouteChart.Route.RootPortNum = Port + 1;
    849     RouteChart.Route.TierNum     = 1;
    850   } else {
    851     if(Port < 14) {
    852       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
    853     } else {
    854       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
    855     }
    856     RouteChart.Route.RootPortNum   = ParentRouteChart.Route.RootPortNum;
    857     RouteChart.Route.TierNum       = ParentRouteChart.Route.TierNum + 1;
    858   }
    859 
    860   SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
    861   if (SlotId != 0) {
    862     if (Xhc->HcCParams.Data.Csz == 0) {
    863       Status = XhcPeiDisableSlotCmd (Xhc, SlotId);
    864     } else {
    865       Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);
    866     }
    867   }
    868 
    869   if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
    870       ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
    871     //
    872     // Has a device attached, Identify device speed after port is enabled.
    873     //
    874     Speed = EFI_USB_SPEED_FULL;
    875     if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
    876       Speed = EFI_USB_SPEED_LOW;
    877     } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
    878       Speed = EFI_USB_SPEED_HIGH;
    879     } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
    880       Speed = EFI_USB_SPEED_SUPER;
    881     }
    882     //
    883     // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
    884     //
    885     SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
    886     if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
    887       if (Xhc->HcCParams.Data.Csz == 0) {
    888         Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
    889       } else {
    890         Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
    891       }
    892     }
    893   }
    894 
    895   return Status;
    896 }
    897 
    898 /**
    899   Calculate the device context index by endpoint address and direction.
    900 
    901   @param  EpAddr        The target endpoint number.
    902   @param  Direction     The direction of the target endpoint.
    903 
    904   @return The device context index of endpoint.
    905 
    906 **/
    907 UINT8
    908 XhcPeiEndpointToDci (
    909   IN UINT8                      EpAddr,
    910   IN EFI_USB_DATA_DIRECTION     Direction
    911   )
    912 {
    913   UINT8 Index;
    914 
    915   ASSERT (EpAddr <= 15);
    916 
    917   if (EpAddr == 0) {
    918     return 1;
    919   } else {
    920     Index = (UINT8) (2 * EpAddr);
    921     if (Direction == EfiUsbDataIn) {
    922       Index += 1;
    923     }
    924     return Index;
    925   }
    926 }
    927 
    928 /**
    929   Find out the actual device address according to the requested device address from UsbBus.
    930 
    931   @param  Xhc           The XHCI device.
    932   @param  BusDevAddr    The requested device address by UsbBus upper driver.
    933 
    934   @return The actual device address assigned to the device.
    935 
    936 **/
    937 UINT8
    938 XhcPeiBusDevAddrToSlotId (
    939   IN PEI_XHC_DEV        *Xhc,
    940   IN UINT8              BusDevAddr
    941   )
    942 {
    943   UINT8   Index;
    944 
    945   for (Index = 0; Index < 255; Index++) {
    946     if (Xhc->UsbDevContext[Index + 1].Enabled &&
    947         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
    948         (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
    949       break;
    950     }
    951   }
    952 
    953   if (Index == 255) {
    954     return 0;
    955   }
    956 
    957   return Xhc->UsbDevContext[Index + 1].SlotId;
    958 }
    959 
    960 /**
    961   Find out the slot id according to the device's route string.
    962 
    963   @param  Xhc           The XHCI device.
    964   @param  RouteString   The route string described the device location.
    965 
    966   @return The slot id used by the device.
    967 
    968 **/
    969 UINT8
    970 XhcPeiRouteStringToSlotId (
    971   IN PEI_XHC_DEV        *Xhc,
    972   IN USB_DEV_ROUTE      RouteString
    973   )
    974 {
    975   UINT8   Index;
    976 
    977   for (Index = 0; Index < 255; Index++) {
    978     if (Xhc->UsbDevContext[Index + 1].Enabled &&
    979         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
    980         (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
    981       break;
    982     }
    983   }
    984 
    985   if (Index == 255) {
    986     return 0;
    987   }
    988 
    989   return Xhc->UsbDevContext[Index + 1].SlotId;
    990 }
    991 
    992 /**
    993   Ring the door bell to notify XHCI there is a transaction to be executed.
    994 
    995   @param  Xhc           The XHCI device.
    996   @param  SlotId        The slot id of the target device.
    997   @param  Dci           The device context index of the target slot or endpoint.
    998 
    999 **/
   1000 VOID
   1001 XhcPeiRingDoorBell (
   1002   IN PEI_XHC_DEV        *Xhc,
   1003   IN UINT8              SlotId,
   1004   IN UINT8              Dci
   1005   )
   1006 {
   1007   if (SlotId == 0) {
   1008     XhcPeiWriteDoorBellReg (Xhc, 0, 0);
   1009   } else {
   1010     XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
   1011   }
   1012 }
   1013 
   1014 /**
   1015   Assign and initialize the device slot for a new device.
   1016 
   1017   @param  Xhc                   The XHCI device.
   1018   @param  ParentRouteChart      The route string pointed to the parent device.
   1019   @param  ParentPort            The port at which the device is located.
   1020   @param  RouteChart            The route string pointed to the device.
   1021   @param  DeviceSpeed           The device speed.
   1022 
   1023   @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.
   1024   @retval Others                Fail to initialize device slot.
   1025 
   1026 **/
   1027 EFI_STATUS
   1028 XhcPeiInitializeDeviceSlot (
   1029   IN PEI_XHC_DEV                *Xhc,
   1030   IN USB_DEV_ROUTE              ParentRouteChart,
   1031   IN UINT16                     ParentPort,
   1032   IN USB_DEV_ROUTE              RouteChart,
   1033   IN UINT8                      DeviceSpeed
   1034   )
   1035 {
   1036   EFI_STATUS                    Status;
   1037   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   1038   INPUT_CONTEXT                 *InputContext;
   1039   DEVICE_CONTEXT                *OutputContext;
   1040   TRANSFER_RING                 *EndpointTransferRing;
   1041   CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;
   1042   UINT8                         DeviceAddress;
   1043   CMD_TRB_ENABLE_SLOT           CmdTrb;
   1044   UINT8                         SlotId;
   1045   UINT8                         ParentSlotId;
   1046   DEVICE_CONTEXT                *ParentDeviceContext;
   1047   EFI_PHYSICAL_ADDRESS          PhyAddr;
   1048 
   1049   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
   1050   CmdTrb.CycleBit = 1;
   1051   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
   1052 
   1053   Status = XhcPeiCmdTransfer (
   1054              Xhc,
   1055              (TRB_TEMPLATE *) (UINTN) &CmdTrb,
   1056              XHC_GENERIC_TIMEOUT,
   1057              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1058              );
   1059   if (EFI_ERROR (Status)) {
   1060     DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
   1061     return Status;
   1062   }
   1063   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
   1064   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
   1065   SlotId = (UINT8) EvtTrb->SlotId;
   1066   ASSERT (SlotId != 0);
   1067 
   1068   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
   1069   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
   1070   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
   1071   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
   1072   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
   1073 
   1074   //
   1075   // 4.3.3 Device Slot Initialization
   1076   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
   1077   //
   1078   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
   1079   ASSERT (InputContext != NULL);
   1080   ASSERT (((UINTN) InputContext & 0x3F) == 0);
   1081   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
   1082 
   1083   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
   1084 
   1085   //
   1086   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
   1087   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
   1088   //    Context are affected by the command.
   1089   //
   1090   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
   1091 
   1092   //
   1093   // 3) Initialize the Input Slot Context data structure
   1094   //
   1095   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
   1096   InputContext->Slot.Speed          = DeviceSpeed + 1;
   1097   InputContext->Slot.ContextEntries = 1;
   1098   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
   1099 
   1100   if (RouteChart.Route.RouteString != 0) {
   1101     //
   1102     // The device is behind of hub device.
   1103     //
   1104     ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
   1105     ASSERT (ParentSlotId != 0);
   1106     //
   1107     // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
   1108     //
   1109     ParentDeviceContext = (DEVICE_CONTEXT *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
   1110     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
   1111         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
   1112       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
   1113         //
   1114         // Full/Low device attached to High speed hub port that isolates the high speed signaling
   1115         // environment from Full/Low speed signaling environment for a device
   1116         //
   1117         InputContext->Slot.TTPortNum   = ParentPort;
   1118         InputContext->Slot.TTHubSlotId = ParentSlotId;
   1119       }
   1120     } else {
   1121       //
   1122       // Inherit the TT parameters from parent device.
   1123       //
   1124       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
   1125       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
   1126       //
   1127       // If the device is a High speed device then down the speed to be the same as its parent Hub
   1128       //
   1129       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
   1130         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
   1131       }
   1132     }
   1133   }
   1134 
   1135   //
   1136   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
   1137   //
   1138   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
   1139   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
   1140   XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
   1141   //
   1142   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
   1143   //
   1144   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
   1145 
   1146   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
   1147     InputContext->EP[0].MaxPacketSize = 512;
   1148   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
   1149     InputContext->EP[0].MaxPacketSize = 64;
   1150   } else {
   1151     InputContext->EP[0].MaxPacketSize = 8;
   1152   }
   1153   //
   1154   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
   1155   // 1KB, and Bulk and Isoch endpoints 3KB.
   1156   //
   1157   InputContext->EP[0].AverageTRBLength = 8;
   1158   InputContext->EP[0].MaxBurstSize     = 0;
   1159   InputContext->EP[0].Interval         = 0;
   1160   InputContext->EP[0].MaxPStreams      = 0;
   1161   InputContext->EP[0].Mult             = 0;
   1162   InputContext->EP[0].CErr             = 3;
   1163 
   1164   //
   1165   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
   1166   //
   1167   PhyAddr = UsbHcGetPciAddrForHostAddr (
   1168               Xhc->MemPool,
   1169               ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
   1170               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
   1171               );
   1172   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
   1173   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
   1174 
   1175   //
   1176   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
   1177   //
   1178   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
   1179   ASSERT (OutputContext != NULL);
   1180   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
   1181   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
   1182 
   1183   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
   1184   //
   1185   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
   1186   //    a pointer to the Output Device Context data structure (6.2.1).
   1187   //
   1188   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
   1189   //
   1190   // Fill DCBAA with PCI device address
   1191   //
   1192   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
   1193 
   1194   //
   1195   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
   1196   //    Context data structure described above.
   1197   //
   1198   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
   1199   // to device.
   1200   //
   1201   MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
   1202   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
   1203   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
   1204   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   1205   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   1206   CmdTrbAddr.CycleBit = 1;
   1207   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
   1208   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   1209   Status = XhcPeiCmdTransfer (
   1210              Xhc,
   1211              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
   1212              XHC_GENERIC_TIMEOUT,
   1213              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1214              );
   1215   if (!EFI_ERROR (Status)) {
   1216     DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
   1217     DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));
   1218     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
   1219   }
   1220 
   1221   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));
   1222   return Status;
   1223 }
   1224 
   1225 /**
   1226   Assign and initialize the device slot for a new device.
   1227 
   1228   @param  Xhc                   The XHCI device.
   1229   @param  ParentRouteChart      The route string pointed to the parent device.
   1230   @param  ParentPort            The port at which the device is located.
   1231   @param  RouteChart            The route string pointed to the device.
   1232   @param  DeviceSpeed           The device speed.
   1233 
   1234   @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.
   1235   @retval Others                Fail to initialize device slot.
   1236 
   1237 **/
   1238 EFI_STATUS
   1239 XhcPeiInitializeDeviceSlot64 (
   1240   IN PEI_XHC_DEV                *Xhc,
   1241   IN USB_DEV_ROUTE              ParentRouteChart,
   1242   IN UINT16                     ParentPort,
   1243   IN USB_DEV_ROUTE              RouteChart,
   1244   IN UINT8                      DeviceSpeed
   1245   )
   1246 {
   1247   EFI_STATUS                    Status;
   1248   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   1249   INPUT_CONTEXT_64              *InputContext;
   1250   DEVICE_CONTEXT_64             *OutputContext;
   1251   TRANSFER_RING                 *EndpointTransferRing;
   1252   CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;
   1253   UINT8                         DeviceAddress;
   1254   CMD_TRB_ENABLE_SLOT           CmdTrb;
   1255   UINT8                         SlotId;
   1256   UINT8                         ParentSlotId;
   1257   DEVICE_CONTEXT_64             *ParentDeviceContext;
   1258   EFI_PHYSICAL_ADDRESS          PhyAddr;
   1259 
   1260   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
   1261   CmdTrb.CycleBit = 1;
   1262   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
   1263 
   1264   Status = XhcPeiCmdTransfer (
   1265              Xhc,
   1266              (TRB_TEMPLATE *) (UINTN) &CmdTrb,
   1267              XHC_GENERIC_TIMEOUT,
   1268              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1269              );
   1270   if (EFI_ERROR (Status)) {
   1271     DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
   1272     return Status;
   1273   }
   1274   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
   1275   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
   1276   SlotId = (UINT8)EvtTrb->SlotId;
   1277   ASSERT (SlotId != 0);
   1278 
   1279   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
   1280   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
   1281   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
   1282   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
   1283   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
   1284 
   1285   //
   1286   // 4.3.3 Device Slot Initialization
   1287   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
   1288   //
   1289   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
   1290   ASSERT (InputContext != NULL);
   1291   ASSERT (((UINTN) InputContext & 0x3F) == 0);
   1292   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
   1293 
   1294   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
   1295 
   1296   //
   1297   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
   1298   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
   1299   //    Context are affected by the command.
   1300   //
   1301   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
   1302 
   1303   //
   1304   // 3) Initialize the Input Slot Context data structure
   1305   //
   1306   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
   1307   InputContext->Slot.Speed          = DeviceSpeed + 1;
   1308   InputContext->Slot.ContextEntries = 1;
   1309   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
   1310 
   1311   if (RouteChart.Route.RouteString != 0) {
   1312     //
   1313     // The device is behind of hub device.
   1314     //
   1315     ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
   1316     ASSERT (ParentSlotId != 0);
   1317     //
   1318     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
   1319     //
   1320     ParentDeviceContext = (DEVICE_CONTEXT_64 *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
   1321     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
   1322         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
   1323       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
   1324         //
   1325         // Full/Low device attached to High speed hub port that isolates the high speed signaling
   1326         // environment from Full/Low speed signaling environment for a device
   1327         //
   1328         InputContext->Slot.TTPortNum   = ParentPort;
   1329         InputContext->Slot.TTHubSlotId = ParentSlotId;
   1330       }
   1331     } else {
   1332       //
   1333       // Inherit the TT parameters from parent device.
   1334       //
   1335       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
   1336       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
   1337       //
   1338       // If the device is a High speed device then down the speed to be the same as its parent Hub
   1339       //
   1340       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
   1341         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
   1342       }
   1343     }
   1344   }
   1345 
   1346   //
   1347   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
   1348   //
   1349   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
   1350   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
   1351   XhcPeiCreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
   1352   //
   1353   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
   1354   //
   1355   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
   1356 
   1357   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
   1358     InputContext->EP[0].MaxPacketSize = 512;
   1359   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
   1360     InputContext->EP[0].MaxPacketSize = 64;
   1361   } else {
   1362     InputContext->EP[0].MaxPacketSize = 8;
   1363   }
   1364   //
   1365   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
   1366   // 1KB, and Bulk and Isoch endpoints 3KB.
   1367   //
   1368   InputContext->EP[0].AverageTRBLength = 8;
   1369   InputContext->EP[0].MaxBurstSize     = 0;
   1370   InputContext->EP[0].Interval         = 0;
   1371   InputContext->EP[0].MaxPStreams      = 0;
   1372   InputContext->EP[0].Mult             = 0;
   1373   InputContext->EP[0].CErr             = 3;
   1374 
   1375   //
   1376   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
   1377   //
   1378   PhyAddr = UsbHcGetPciAddrForHostAddr (
   1379               Xhc->MemPool,
   1380               ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
   1381               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
   1382               );
   1383   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
   1384   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
   1385 
   1386   //
   1387   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
   1388   //
   1389   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
   1390   ASSERT (OutputContext != NULL);
   1391   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
   1392   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
   1393 
   1394   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
   1395   //
   1396   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
   1397   //    a pointer to the Output Device Context data structure (6.2.1).
   1398   //
   1399   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
   1400   //
   1401   // Fill DCBAA with PCI device address
   1402   //
   1403   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
   1404 
   1405   //
   1406   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
   1407   //    Context data structure described above.
   1408   //
   1409   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
   1410   // to device.
   1411   //
   1412   MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
   1413   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
   1414   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
   1415   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   1416   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   1417   CmdTrbAddr.CycleBit = 1;
   1418   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
   1419   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   1420   Status = XhcPeiCmdTransfer (
   1421              Xhc,
   1422              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
   1423              XHC_GENERIC_TIMEOUT,
   1424              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1425              );
   1426   if (!EFI_ERROR (Status)) {
   1427     DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
   1428     DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));
   1429     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
   1430   }
   1431 
   1432   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));
   1433   return Status;
   1434 }
   1435 
   1436 
   1437 /**
   1438   Disable the specified device slot.
   1439 
   1440   @param  Xhc           The XHCI device.
   1441   @param  SlotId        The slot id to be disabled.
   1442 
   1443   @retval EFI_SUCCESS   Successfully disable the device slot.
   1444 
   1445 **/
   1446 EFI_STATUS
   1447 XhcPeiDisableSlotCmd (
   1448   IN PEI_XHC_DEV               *Xhc,
   1449   IN UINT8                     SlotId
   1450   )
   1451 {
   1452   EFI_STATUS            Status;
   1453   TRB_TEMPLATE          *EvtTrb;
   1454   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
   1455   UINT8                 Index;
   1456   VOID                  *RingSeg;
   1457 
   1458   //
   1459   // Disable the device slots occupied by these devices on its downstream ports.
   1460   // Entry 0 is reserved.
   1461   //
   1462   for (Index = 0; Index < 255; Index++) {
   1463     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
   1464         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
   1465         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
   1466       continue;
   1467     }
   1468 
   1469     Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
   1470 
   1471     if (EFI_ERROR (Status)) {
   1472       DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
   1473       Xhc->UsbDevContext[Index + 1].SlotId = 0;
   1474     }
   1475   }
   1476 
   1477   //
   1478   // Construct the disable slot command
   1479   //
   1480   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));
   1481 
   1482   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
   1483   CmdTrbDisSlot.CycleBit = 1;
   1484   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
   1485   CmdTrbDisSlot.SlotId   = SlotId;
   1486   Status = XhcPeiCmdTransfer (
   1487              Xhc,
   1488              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
   1489              XHC_GENERIC_TIMEOUT,
   1490              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1491              );
   1492   if (EFI_ERROR (Status)) {
   1493     DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
   1494     return Status;
   1495   }
   1496   //
   1497   // Free the slot's device context entry
   1498   //
   1499   Xhc->DCBAA[SlotId] = 0;
   1500 
   1501   //
   1502   // Free the slot related data structure
   1503   //
   1504   for (Index = 0; Index < 31; Index++) {
   1505     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
   1506       RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
   1507       if (RingSeg != NULL) {
   1508         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
   1509       }
   1510       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
   1511       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
   1512     }
   1513   }
   1514 
   1515   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
   1516     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
   1517       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
   1518     }
   1519   }
   1520 
   1521   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
   1522     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
   1523   }
   1524 
   1525   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
   1526     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
   1527   }
   1528   //
   1529   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
   1530   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
   1531   // remove urb from XHCI's asynchronous transfer list.
   1532   //
   1533   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
   1534   Xhc->UsbDevContext[SlotId].SlotId  = 0;
   1535 
   1536   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));
   1537   return Status;
   1538 }
   1539 
   1540 /**
   1541   Disable the specified device slot.
   1542 
   1543   @param  Xhc           The XHCI device.
   1544   @param  SlotId        The slot id to be disabled.
   1545 
   1546   @retval EFI_SUCCESS   Successfully disable the device slot.
   1547 
   1548 **/
   1549 EFI_STATUS
   1550 XhcPeiDisableSlotCmd64 (
   1551   IN PEI_XHC_DEV               *Xhc,
   1552   IN UINT8                     SlotId
   1553   )
   1554 {
   1555   EFI_STATUS            Status;
   1556   TRB_TEMPLATE          *EvtTrb;
   1557   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
   1558   UINT8                 Index;
   1559   VOID                  *RingSeg;
   1560 
   1561   //
   1562   // Disable the device slots occupied by these devices on its downstream ports.
   1563   // Entry 0 is reserved.
   1564   //
   1565   for (Index = 0; Index < 255; Index++) {
   1566     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
   1567         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
   1568         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
   1569       continue;
   1570     }
   1571 
   1572     Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
   1573 
   1574     if (EFI_ERROR (Status)) {
   1575       DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
   1576       Xhc->UsbDevContext[Index + 1].SlotId = 0;
   1577     }
   1578   }
   1579 
   1580   //
   1581   // Construct the disable slot command
   1582   //
   1583   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));
   1584 
   1585   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
   1586   CmdTrbDisSlot.CycleBit = 1;
   1587   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
   1588   CmdTrbDisSlot.SlotId   = SlotId;
   1589   Status = XhcPeiCmdTransfer (
   1590              Xhc,
   1591              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
   1592              XHC_GENERIC_TIMEOUT,
   1593              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1594              );
   1595   if (EFI_ERROR (Status)) {
   1596     DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));
   1597     return Status;
   1598   }
   1599   //
   1600   // Free the slot's device context entry
   1601   //
   1602   Xhc->DCBAA[SlotId] = 0;
   1603 
   1604   //
   1605   // Free the slot related data structure
   1606   //
   1607   for (Index = 0; Index < 31; Index++) {
   1608     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
   1609       RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
   1610       if (RingSeg != NULL) {
   1611         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
   1612       }
   1613       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
   1614       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
   1615     }
   1616   }
   1617 
   1618   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
   1619     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
   1620       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
   1621     }
   1622   }
   1623 
   1624   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
   1625     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
   1626   }
   1627 
   1628   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
   1629      UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
   1630   }
   1631   //
   1632   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
   1633   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
   1634   // remove urb from XHCI's asynchronous transfer list.
   1635   //
   1636   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
   1637   Xhc->UsbDevContext[SlotId].SlotId  = 0;
   1638 
   1639   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));
   1640   return Status;
   1641 }
   1642 
   1643 /**
   1644   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
   1645 
   1646   @param  Xhc           The XHCI device.
   1647   @param  SlotId        The slot id to be configured.
   1648   @param  DeviceSpeed   The device's speed.
   1649   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
   1650 
   1651   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
   1652 
   1653 **/
   1654 EFI_STATUS
   1655 XhcPeiSetConfigCmd (
   1656   IN PEI_XHC_DEV                *Xhc,
   1657   IN UINT8                      SlotId,
   1658   IN UINT8                      DeviceSpeed,
   1659   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc
   1660   )
   1661 {
   1662   EFI_STATUS                    Status;
   1663   USB_INTERFACE_DESCRIPTOR      *IfDesc;
   1664   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
   1665   UINT8                         Index;
   1666   UINTN                         NumEp;
   1667   UINTN                         EpIndex;
   1668   UINT8                         EpAddr;
   1669   EFI_USB_DATA_DIRECTION        Direction;
   1670   UINT8                         Dci;
   1671   UINT8                         MaxDci;
   1672   EFI_PHYSICAL_ADDRESS          PhyAddr;
   1673   UINT8                         Interval;
   1674 
   1675   TRANSFER_RING                 *EndpointTransferRing;
   1676   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
   1677   INPUT_CONTEXT                 *InputContext;
   1678   DEVICE_CONTEXT                *OutputContext;
   1679   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   1680   //
   1681   // 4.6.6 Configure Endpoint
   1682   //
   1683   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
   1684   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
   1685   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
   1686   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
   1687 
   1688   ASSERT (ConfigDesc != NULL);
   1689 
   1690   MaxDci = 0;
   1691 
   1692   IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
   1693   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
   1694     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
   1695       IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
   1696     }
   1697 
   1698     NumEp = IfDesc->NumEndpoints;
   1699 
   1700     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
   1701     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
   1702       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
   1703         EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
   1704       }
   1705 
   1706       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
   1707       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
   1708 
   1709       Dci = XhcPeiEndpointToDci (EpAddr, Direction);
   1710       if (Dci > MaxDci) {
   1711         MaxDci = Dci;
   1712       }
   1713 
   1714       InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
   1715       InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
   1716 
   1717       if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
   1718         //
   1719         // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
   1720         //
   1721         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
   1722       } else {
   1723         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
   1724       }
   1725 
   1726       switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
   1727         case USB_ENDPOINT_BULK:
   1728           if (Direction == EfiUsbDataIn) {
   1729             InputContext->EP[Dci-1].CErr   = 3;
   1730             InputContext->EP[Dci-1].EPType = ED_BULK_IN;
   1731           } else {
   1732             InputContext->EP[Dci-1].CErr   = 3;
   1733             InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
   1734           }
   1735 
   1736           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
   1737           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
   1738             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
   1739             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
   1740             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
   1741           }
   1742 
   1743           break;
   1744         case USB_ENDPOINT_ISO:
   1745           if (Direction == EfiUsbDataIn) {
   1746             InputContext->EP[Dci-1].CErr   = 0;
   1747             InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
   1748           } else {
   1749             InputContext->EP[Dci-1].CErr   = 0;
   1750             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
   1751           }
   1752           //
   1753           // Do not support isochronous transfer now.
   1754           //
   1755           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
   1756           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
   1757           continue;
   1758         case USB_ENDPOINT_INTERRUPT:
   1759           if (Direction == EfiUsbDataIn) {
   1760             InputContext->EP[Dci-1].CErr   = 3;
   1761             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
   1762           } else {
   1763             InputContext->EP[Dci-1].CErr   = 3;
   1764             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
   1765           }
   1766           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
   1767           InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
   1768           //
   1769           // Get the bInterval from descriptor and init the interval field of endpoint context
   1770           //
   1771           if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
   1772             Interval = EpDesc->Interval;
   1773             //
   1774             // Calculate through the bInterval field of Endpoint descriptor.
   1775             //
   1776             ASSERT (Interval != 0);
   1777             InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32 ((UINT32) Interval) + 3;
   1778           } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
   1779             Interval = EpDesc->Interval;
   1780             ASSERT (Interval >= 1 && Interval <= 16);
   1781             //
   1782             // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
   1783             //
   1784             InputContext->EP[Dci-1].Interval = Interval - 1;
   1785           }
   1786 
   1787           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
   1788             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
   1789             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
   1790             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
   1791           }
   1792           break;
   1793 
   1794         case USB_ENDPOINT_CONTROL:
   1795           //
   1796           // Do not support control transfer now.
   1797           //
   1798           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
   1799         default:
   1800           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
   1801           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
   1802           continue;
   1803       }
   1804 
   1805       PhyAddr = UsbHcGetPciAddrForHostAddr (
   1806                   Xhc->MemPool,
   1807                   ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
   1808                   sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
   1809                   );
   1810       PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
   1811       PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
   1812       InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
   1813       InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
   1814 
   1815       EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
   1816     }
   1817     IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
   1818   }
   1819 
   1820   InputContext->InputControlContext.Dword2 |= BIT0;
   1821   InputContext->Slot.ContextEntries         = MaxDci;
   1822   //
   1823   // configure endpoint
   1824   //
   1825   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
   1826   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
   1827   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   1828   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   1829   CmdTrbCfgEP.CycleBit = 1;
   1830   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
   1831   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   1832   DEBUG ((EFI_D_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));
   1833   Status = XhcPeiCmdTransfer (
   1834              Xhc,
   1835              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
   1836              XHC_GENERIC_TIMEOUT,
   1837              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   1838              );
   1839   if (EFI_ERROR (Status)) {
   1840     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
   1841   }
   1842   return Status;
   1843 }
   1844 
   1845 /**
   1846   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
   1847 
   1848   @param  Xhc           The XHCI device.
   1849   @param  SlotId        The slot id to be configured.
   1850   @param  DeviceSpeed   The device's speed.
   1851   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
   1852 
   1853   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
   1854 
   1855 **/
   1856 EFI_STATUS
   1857 XhcPeiSetConfigCmd64 (
   1858   IN PEI_XHC_DEV                *Xhc,
   1859   IN UINT8                      SlotId,
   1860   IN UINT8                      DeviceSpeed,
   1861   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc
   1862   )
   1863 {
   1864   EFI_STATUS                    Status;
   1865   USB_INTERFACE_DESCRIPTOR      *IfDesc;
   1866   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
   1867   UINT8                         Index;
   1868   UINTN                         NumEp;
   1869   UINTN                         EpIndex;
   1870   UINT8                         EpAddr;
   1871   EFI_USB_DATA_DIRECTION        Direction;
   1872   UINT8                         Dci;
   1873   UINT8                         MaxDci;
   1874   EFI_PHYSICAL_ADDRESS          PhyAddr;
   1875   UINT8                         Interval;
   1876 
   1877   TRANSFER_RING                 *EndpointTransferRing;
   1878   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
   1879   INPUT_CONTEXT_64              *InputContext;
   1880   DEVICE_CONTEXT_64             *OutputContext;
   1881   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   1882   //
   1883   // 4.6.6 Configure Endpoint
   1884   //
   1885   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
   1886   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
   1887   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
   1888   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
   1889 
   1890   ASSERT (ConfigDesc != NULL);
   1891 
   1892   MaxDci = 0;
   1893 
   1894   IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
   1895   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
   1896     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
   1897       IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
   1898     }
   1899 
   1900     NumEp = IfDesc->NumEndpoints;
   1901 
   1902     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
   1903     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
   1904       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
   1905         EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
   1906       }
   1907 
   1908       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
   1909       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
   1910 
   1911       Dci = XhcPeiEndpointToDci (EpAddr, Direction);
   1912       ASSERT (Dci < 32);
   1913       if (Dci > MaxDci) {
   1914         MaxDci = Dci;
   1915       }
   1916 
   1917       InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
   1918       InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
   1919 
   1920       if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
   1921         //
   1922         // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
   1923         //
   1924         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
   1925       } else {
   1926         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
   1927       }
   1928 
   1929       switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
   1930         case USB_ENDPOINT_BULK:
   1931           if (Direction == EfiUsbDataIn) {
   1932             InputContext->EP[Dci-1].CErr   = 3;
   1933             InputContext->EP[Dci-1].EPType = ED_BULK_IN;
   1934           } else {
   1935             InputContext->EP[Dci-1].CErr   = 3;
   1936             InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
   1937           }
   1938 
   1939           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
   1940           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
   1941             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
   1942             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
   1943             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
   1944           }
   1945 
   1946           break;
   1947         case USB_ENDPOINT_ISO:
   1948           if (Direction == EfiUsbDataIn) {
   1949             InputContext->EP[Dci-1].CErr   = 0;
   1950             InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
   1951           } else {
   1952             InputContext->EP[Dci-1].CErr   = 0;
   1953             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
   1954           }
   1955           //
   1956           // Do not support isochronous transfer now.
   1957           //
   1958           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
   1959           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
   1960           continue;
   1961         case USB_ENDPOINT_INTERRUPT:
   1962           if (Direction == EfiUsbDataIn) {
   1963             InputContext->EP[Dci-1].CErr   = 3;
   1964             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
   1965           } else {
   1966             InputContext->EP[Dci-1].CErr   = 3;
   1967             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
   1968           }
   1969           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
   1970           InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
   1971           //
   1972           // Get the bInterval from descriptor and init the the interval field of endpoint context
   1973           //
   1974           if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
   1975             Interval = EpDesc->Interval;
   1976             //
   1977             // Calculate through the bInterval field of Endpoint descriptor.
   1978             //
   1979             ASSERT (Interval != 0);
   1980             InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32( (UINT32) Interval) + 3;
   1981           } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
   1982             Interval = EpDesc->Interval;
   1983             ASSERT (Interval >= 1 && Interval <= 16);
   1984             //
   1985             // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
   1986             //
   1987             InputContext->EP[Dci-1].Interval = Interval - 1;
   1988           }
   1989 
   1990           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
   1991             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
   1992             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
   1993             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
   1994           }
   1995           break;
   1996 
   1997         case USB_ENDPOINT_CONTROL:
   1998           //
   1999           // Do not support control transfer now.
   2000           //
   2001           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
   2002         default:
   2003           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
   2004           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
   2005           continue;
   2006       }
   2007 
   2008       PhyAddr = UsbHcGetPciAddrForHostAddr (
   2009                   Xhc->MemPool,
   2010                   ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
   2011                   sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
   2012                   );
   2013 
   2014       PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
   2015       PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
   2016 
   2017       InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
   2018       InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
   2019 
   2020       EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN)EpDesc + EpDesc->Length);
   2021     }
   2022     IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN)IfDesc + IfDesc->Length);
   2023   }
   2024 
   2025   InputContext->InputControlContext.Dword2 |= BIT0;
   2026   InputContext->Slot.ContextEntries         = MaxDci;
   2027   //
   2028   // configure endpoint
   2029   //
   2030   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
   2031   PhyAddr  = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
   2032   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   2033   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   2034   CmdTrbCfgEP.CycleBit = 1;
   2035   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
   2036   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   2037   DEBUG ((EFI_D_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));
   2038   Status = XhcPeiCmdTransfer (
   2039              Xhc,
   2040              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
   2041              XHC_GENERIC_TIMEOUT,
   2042              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2043              );
   2044   if (EFI_ERROR (Status)) {
   2045     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
   2046   }
   2047 
   2048   return Status;
   2049 }
   2050 
   2051 
   2052 /**
   2053   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
   2054 
   2055   @param  Xhc           The XHCI device.
   2056   @param  SlotId        The slot id to be evaluated.
   2057   @param  MaxPacketSize The max packet size supported by the device control transfer.
   2058 
   2059   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
   2060 
   2061 **/
   2062 EFI_STATUS
   2063 XhcPeiEvaluateContext (
   2064   IN PEI_XHC_DEV                *Xhc,
   2065   IN UINT8                      SlotId,
   2066   IN UINT32                     MaxPacketSize
   2067   )
   2068 {
   2069   EFI_STATUS                    Status;
   2070   CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;
   2071   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   2072   INPUT_CONTEXT                 *InputContext;
   2073   EFI_PHYSICAL_ADDRESS          PhyAddr;
   2074 
   2075   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
   2076 
   2077   //
   2078   // 4.6.7 Evaluate Context
   2079   //
   2080   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
   2081   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
   2082 
   2083   InputContext->InputControlContext.Dword2 |= BIT1;
   2084   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
   2085 
   2086   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
   2087   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
   2088   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   2089   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   2090   CmdTrbEvalu.CycleBit = 1;
   2091   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
   2092   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   2093   DEBUG ((EFI_D_INFO, "XhcEvaluateContext: Evaluate context\n"));
   2094   Status = XhcPeiCmdTransfer (
   2095              Xhc,
   2096              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
   2097              XHC_GENERIC_TIMEOUT,
   2098              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2099              );
   2100   if (EFI_ERROR (Status)) {
   2101     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
   2102   }
   2103   return Status;
   2104 }
   2105 
   2106 /**
   2107   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
   2108 
   2109   @param  Xhc           The XHCI device.
   2110   @param  SlotId        The slot id to be evaluated.
   2111   @param  MaxPacketSize The max packet size supported by the device control transfer.
   2112 
   2113   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
   2114 
   2115 **/
   2116 EFI_STATUS
   2117 XhcPeiEvaluateContext64 (
   2118   IN PEI_XHC_DEV                *Xhc,
   2119   IN UINT8                      SlotId,
   2120   IN UINT32                     MaxPacketSize
   2121   )
   2122 {
   2123   EFI_STATUS                    Status;
   2124   CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;
   2125   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   2126   INPUT_CONTEXT_64              *InputContext;
   2127   EFI_PHYSICAL_ADDRESS          PhyAddr;
   2128 
   2129   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
   2130 
   2131   //
   2132   // 4.6.7 Evaluate Context
   2133   //
   2134   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
   2135   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
   2136 
   2137   InputContext->InputControlContext.Dword2 |= BIT1;
   2138   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
   2139 
   2140   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
   2141   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
   2142   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   2143   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   2144   CmdTrbEvalu.CycleBit = 1;
   2145   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
   2146   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   2147   DEBUG ((EFI_D_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));
   2148   Status = XhcPeiCmdTransfer (
   2149              Xhc,
   2150              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
   2151              XHC_GENERIC_TIMEOUT,
   2152              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2153              );
   2154   if (EFI_ERROR (Status)) {
   2155     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
   2156   }
   2157   return Status;
   2158 }
   2159 
   2160 /**
   2161   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
   2162 
   2163   @param  Xhc           The XHCI device.
   2164   @param  SlotId        The slot id to be configured.
   2165   @param  PortNum       The total number of downstream port supported by the hub.
   2166   @param  TTT           The TT think time of the hub device.
   2167   @param  MTT           The multi-TT of the hub device.
   2168 
   2169   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
   2170 
   2171 **/
   2172 EFI_STATUS
   2173 XhcPeiConfigHubContext (
   2174   IN PEI_XHC_DEV                *Xhc,
   2175   IN UINT8                      SlotId,
   2176   IN UINT8                      PortNum,
   2177   IN UINT8                      TTT,
   2178   IN UINT8                      MTT
   2179   )
   2180 {
   2181   EFI_STATUS                    Status;
   2182   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   2183   INPUT_CONTEXT                 *InputContext;
   2184   DEVICE_CONTEXT                *OutputContext;
   2185   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
   2186   EFI_PHYSICAL_ADDRESS          PhyAddr;
   2187 
   2188   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
   2189   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
   2190   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
   2191 
   2192   //
   2193   // 4.6.7 Evaluate Context
   2194   //
   2195   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
   2196 
   2197   InputContext->InputControlContext.Dword2 |= BIT0;
   2198 
   2199   //
   2200   // Copy the slot context from OutputContext to Input context
   2201   //
   2202   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
   2203   InputContext->Slot.Hub     = 1;
   2204   InputContext->Slot.PortNum = PortNum;
   2205   InputContext->Slot.TTT     = TTT;
   2206   InputContext->Slot.MTT     = MTT;
   2207 
   2208   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
   2209   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
   2210   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   2211   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   2212   CmdTrbCfgEP.CycleBit = 1;
   2213   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
   2214   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   2215   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
   2216   Status = XhcPeiCmdTransfer (
   2217              Xhc,
   2218              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
   2219              XHC_GENERIC_TIMEOUT,
   2220              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2221              );
   2222   if (EFI_ERROR (Status)) {
   2223     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
   2224   }
   2225   return Status;
   2226 }
   2227 
   2228 /**
   2229   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
   2230 
   2231   @param  Xhc           The XHCI device.
   2232   @param  SlotId        The slot id to be configured.
   2233   @param  PortNum       The total number of downstream port supported by the hub.
   2234   @param  TTT           The TT think time of the hub device.
   2235   @param  MTT           The multi-TT of the hub device.
   2236 
   2237   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
   2238 
   2239 **/
   2240 EFI_STATUS
   2241 XhcPeiConfigHubContext64 (
   2242   IN PEI_XHC_DEV                *Xhc,
   2243   IN UINT8                      SlotId,
   2244   IN UINT8                      PortNum,
   2245   IN UINT8                      TTT,
   2246   IN UINT8                      MTT
   2247   )
   2248 {
   2249   EFI_STATUS                    Status;
   2250   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   2251   INPUT_CONTEXT_64              *InputContext;
   2252   DEVICE_CONTEXT_64             *OutputContext;
   2253   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
   2254   EFI_PHYSICAL_ADDRESS          PhyAddr;
   2255 
   2256   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
   2257   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
   2258   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
   2259 
   2260   //
   2261   // 4.6.7 Evaluate Context
   2262   //
   2263   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
   2264 
   2265   InputContext->InputControlContext.Dword2 |= BIT0;
   2266 
   2267   //
   2268   // Copy the slot context from OutputContext to Input context
   2269   //
   2270   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
   2271   InputContext->Slot.Hub     = 1;
   2272   InputContext->Slot.PortNum = PortNum;
   2273   InputContext->Slot.TTT     = TTT;
   2274   InputContext->Slot.MTT     = MTT;
   2275 
   2276   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
   2277   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
   2278   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
   2279   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   2280   CmdTrbCfgEP.CycleBit = 1;
   2281   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
   2282   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
   2283   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context 64\n"));
   2284   Status = XhcPeiCmdTransfer (
   2285              Xhc,
   2286              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
   2287              XHC_GENERIC_TIMEOUT,
   2288              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2289              );
   2290   if (EFI_ERROR (Status)) {
   2291     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
   2292   }
   2293   return Status;
   2294 }
   2295 
   2296 /**
   2297   Stop endpoint through XHCI's Stop_Endpoint cmd.
   2298 
   2299   @param  Xhc           The XHCI device.
   2300   @param  SlotId        The slot id of the target device.
   2301   @param  Dci           The device context index of the target slot or endpoint.
   2302 
   2303   @retval EFI_SUCCESS   Stop endpoint successfully.
   2304   @retval Others        Failed to stop endpoint.
   2305 
   2306 **/
   2307 EFI_STATUS
   2308 EFIAPI
   2309 XhcPeiStopEndpoint (
   2310   IN PEI_XHC_DEV        *Xhc,
   2311   IN UINT8              SlotId,
   2312   IN UINT8              Dci
   2313   )
   2314 {
   2315   EFI_STATUS                    Status;
   2316   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
   2317   CMD_TRB_STOP_ENDPOINT         CmdTrbStopED;
   2318 
   2319   DEBUG ((EFI_D_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
   2320 
   2321   //
   2322   // Send stop endpoint command to transit Endpoint from running to stop state
   2323   //
   2324   ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
   2325   CmdTrbStopED.CycleBit = 1;
   2326   CmdTrbStopED.Type     = TRB_TYPE_STOP_ENDPOINT;
   2327   CmdTrbStopED.EDID     = Dci;
   2328   CmdTrbStopED.SlotId   = SlotId;
   2329   Status = XhcPeiCmdTransfer (
   2330              Xhc,
   2331              (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
   2332              XHC_GENERIC_TIMEOUT,
   2333              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2334              );
   2335   if (EFI_ERROR(Status)) {
   2336     DEBUG ((EFI_D_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
   2337   }
   2338 
   2339   return Status;
   2340 }
   2341 
   2342 /**
   2343   Reset endpoint through XHCI's Reset_Endpoint cmd.
   2344 
   2345   @param  Xhc           The XHCI device.
   2346   @param  SlotId        The slot id of the target device.
   2347   @param  Dci           The device context index of the target slot or endpoint.
   2348 
   2349   @retval EFI_SUCCESS   Reset endpoint successfully.
   2350   @retval Others        Failed to reset endpoint.
   2351 
   2352 **/
   2353 EFI_STATUS
   2354 EFIAPI
   2355 XhcPeiResetEndpoint (
   2356   IN PEI_XHC_DEV        *Xhc,
   2357   IN UINT8              SlotId,
   2358   IN UINT8              Dci
   2359   )
   2360 {
   2361   EFI_STATUS                  Status;
   2362   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
   2363   CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;
   2364 
   2365   DEBUG ((EFI_D_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
   2366 
   2367   //
   2368   // Send stop endpoint command to transit Endpoint from running to stop state
   2369   //
   2370   ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
   2371   CmdTrbResetED.CycleBit = 1;
   2372   CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;
   2373   CmdTrbResetED.EDID     = Dci;
   2374   CmdTrbResetED.SlotId   = SlotId;
   2375   Status = XhcPeiCmdTransfer (
   2376              Xhc,
   2377              (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
   2378              XHC_GENERIC_TIMEOUT,
   2379              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2380              );
   2381   if (EFI_ERROR(Status)) {
   2382     DEBUG ((EFI_D_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
   2383   }
   2384 
   2385   return Status;
   2386 }
   2387 
   2388 /**
   2389   Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
   2390 
   2391   @param  Xhc           The XHCI device.
   2392   @param  SlotId        The slot id of the target device.
   2393   @param  Dci           The device context index of the target slot or endpoint.
   2394   @param  Urb           The dequeue pointer of the transfer ring specified
   2395                         by the urb to be updated.
   2396 
   2397   @retval EFI_SUCCESS   Set transfer ring dequeue pointer succeeds.
   2398   @retval Others        Failed to set transfer ring dequeue pointer.
   2399 
   2400 **/
   2401 EFI_STATUS
   2402 EFIAPI
   2403 XhcPeiSetTrDequeuePointer (
   2404   IN PEI_XHC_DEV        *Xhc,
   2405   IN UINT8              SlotId,
   2406   IN UINT8              Dci,
   2407   IN URB                *Urb
   2408   )
   2409 {
   2410   EFI_STATUS                  Status;
   2411   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
   2412   CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;
   2413   EFI_PHYSICAL_ADDRESS        PhyAddr;
   2414 
   2415   DEBUG ((EFI_D_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
   2416 
   2417   //
   2418   // Send stop endpoint command to transit Endpoint from running to stop state
   2419   //
   2420   ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
   2421   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
   2422   CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
   2423   CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
   2424   CmdSetTRDeq.CycleBit = 1;
   2425   CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;
   2426   CmdSetTRDeq.Endpoint = Dci;
   2427   CmdSetTRDeq.SlotId   = SlotId;
   2428   Status = XhcPeiCmdTransfer (
   2429              Xhc,
   2430              (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
   2431              XHC_GENERIC_TIMEOUT,
   2432              (TRB_TEMPLATE **) (UINTN) &EvtTrb
   2433              );
   2434   if (EFI_ERROR(Status)) {
   2435     DEBUG ((EFI_D_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
   2436   }
   2437 
   2438   return Status;
   2439 }
   2440 
   2441 /**
   2442   Check if there is a new generated event.
   2443 
   2444   @param  Xhc           The XHCI device.
   2445   @param  EvtRing       The event ring to check.
   2446   @param  NewEvtTrb     The new event TRB found.
   2447 
   2448   @retval EFI_SUCCESS   Found a new event TRB at the event ring.
   2449   @retval EFI_NOT_READY The event ring has no new event.
   2450 
   2451 **/
   2452 EFI_STATUS
   2453 XhcPeiCheckNewEvent (
   2454   IN PEI_XHC_DEV        *Xhc,
   2455   IN EVENT_RING         *EvtRing,
   2456   OUT TRB_TEMPLATE      **NewEvtTrb
   2457   )
   2458 {
   2459   ASSERT (EvtRing != NULL);
   2460 
   2461   *NewEvtTrb = EvtRing->EventRingDequeue;
   2462 
   2463   if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
   2464     return EFI_NOT_READY;
   2465   }
   2466 
   2467   EvtRing->EventRingDequeue++;
   2468   //
   2469   // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
   2470   //
   2471   if ((UINTN) EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
   2472     EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
   2473   }
   2474 
   2475   return EFI_SUCCESS;
   2476 }
   2477 
   2478 /**
   2479   Synchronize the specified event ring to update the enqueue and dequeue pointer.
   2480 
   2481   @param  Xhc       The XHCI device.
   2482   @param  EvtRing   The event ring to sync.
   2483 
   2484   @retval EFI_SUCCESS The event ring is synchronized successfully.
   2485 
   2486 **/
   2487 EFI_STATUS
   2488 XhcPeiSyncEventRing (
   2489   IN PEI_XHC_DEV    *Xhc,
   2490   IN EVENT_RING     *EvtRing
   2491   )
   2492 {
   2493   UINTN             Index;
   2494   TRB_TEMPLATE      *EvtTrb;
   2495 
   2496   ASSERT (EvtRing != NULL);
   2497 
   2498   //
   2499   // Calculate the EventRingEnqueue and EventRingCCS.
   2500   // Note: only support single Segment
   2501   //
   2502   EvtTrb = EvtRing->EventRingDequeue;
   2503 
   2504   for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
   2505     if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {
   2506       break;
   2507     }
   2508 
   2509     EvtTrb++;
   2510 
   2511     if ((UINTN) EvtTrb >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
   2512       EvtTrb = EvtRing->EventRingSeg0;
   2513       EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
   2514     }
   2515   }
   2516 
   2517   if (Index < EvtRing->TrbNumber) {
   2518     EvtRing->EventRingEnqueue = EvtTrb;
   2519   } else {
   2520     ASSERT (FALSE);
   2521   }
   2522 
   2523   return EFI_SUCCESS;
   2524 }
   2525 
   2526 /**
   2527   Free XHCI event ring.
   2528 
   2529   @param  Xhc           The XHCI device.
   2530   @param  EventRing     The event ring to be freed.
   2531 
   2532 **/
   2533 VOID
   2534 XhcPeiFreeEventRing (
   2535   IN PEI_XHC_DEV        *Xhc,
   2536   IN EVENT_RING         *EventRing
   2537   )
   2538 {
   2539   if(EventRing->EventRingSeg0 == NULL) {
   2540     return;
   2541   }
   2542 
   2543   //
   2544   // Free EventRing Segment 0
   2545   //
   2546   UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
   2547 
   2548   //
   2549   // Free ERST table
   2550   //
   2551   UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
   2552 }
   2553 
   2554 /**
   2555   Create XHCI event ring.
   2556 
   2557   @param  Xhc           The XHCI device.
   2558   @param  EventRing     The created event ring.
   2559 
   2560 **/
   2561 VOID
   2562 XhcPeiCreateEventRing (
   2563   IN PEI_XHC_DEV        *Xhc,
   2564   OUT EVENT_RING        *EventRing
   2565   )
   2566 {
   2567   VOID                          *Buf;
   2568   EVENT_RING_SEG_TABLE_ENTRY    *ERSTBase;
   2569   UINTN                         Size;
   2570   EFI_PHYSICAL_ADDRESS          ERSTPhy;
   2571   EFI_PHYSICAL_ADDRESS          DequeuePhy;
   2572 
   2573   ASSERT (EventRing != NULL);
   2574 
   2575   Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
   2576   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
   2577   ASSERT (Buf != NULL);
   2578   ASSERT (((UINTN) Buf & 0x3F) == 0);
   2579   ZeroMem (Buf, Size);
   2580 
   2581   DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
   2582 
   2583   EventRing->EventRingSeg0      = Buf;
   2584   EventRing->TrbNumber          = EVENT_RING_TRB_NUMBER;
   2585   EventRing->EventRingDequeue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
   2586   EventRing->EventRingEnqueue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
   2587 
   2588   //
   2589   // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
   2590   // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
   2591   //
   2592   EventRing->EventRingCCS = 1;
   2593 
   2594   Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
   2595   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
   2596   ASSERT (Buf != NULL);
   2597   ASSERT (((UINTN) Buf & 0x3F) == 0);
   2598   ZeroMem (Buf, Size);
   2599 
   2600   ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
   2601   EventRing->ERSTBase   = ERSTBase;
   2602   ERSTBase->PtrLo       = XHC_LOW_32BIT (DequeuePhy);
   2603   ERSTBase->PtrHi       = XHC_HIGH_32BIT (DequeuePhy);
   2604   ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
   2605 
   2606   ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
   2607 
   2608   //
   2609   // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
   2610   //
   2611   XhcPeiWriteRuntimeReg (
   2612     Xhc,
   2613     XHC_ERSTSZ_OFFSET,
   2614     ERST_NUMBER
   2615     );
   2616   //
   2617   // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
   2618   //
   2619   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
   2620   // So divide it to two 32-bytes width register access.
   2621   //
   2622   XhcPeiWriteRuntimeReg (
   2623     Xhc,
   2624     XHC_ERDP_OFFSET,
   2625     XHC_LOW_32BIT ((UINT64) (UINTN) DequeuePhy)
   2626     );
   2627   XhcPeiWriteRuntimeReg (
   2628     Xhc,
   2629     XHC_ERDP_OFFSET + 4,
   2630     XHC_HIGH_32BIT ((UINT64) (UINTN) DequeuePhy)
   2631     );
   2632   //
   2633   // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
   2634   //
   2635   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
   2636   // So divide it to two 32-bytes width register access.
   2637   //
   2638   XhcPeiWriteRuntimeReg (
   2639     Xhc,
   2640     XHC_ERSTBA_OFFSET,
   2641     XHC_LOW_32BIT ((UINT64) (UINTN) ERSTPhy)
   2642     );
   2643   XhcPeiWriteRuntimeReg (
   2644     Xhc,
   2645     XHC_ERSTBA_OFFSET + 4,
   2646     XHC_HIGH_32BIT ((UINT64) (UINTN) ERSTPhy)
   2647     );
   2648   //
   2649   // Need set IMAN IE bit to enable the ring interrupt
   2650   //
   2651   XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
   2652 }
   2653 
   2654 /**
   2655   Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
   2656 
   2657   @param  Xhc       The XHCI device.
   2658   @param  TrsRing   The transfer ring to sync.
   2659 
   2660   @retval EFI_SUCCESS The transfer ring is synchronized successfully.
   2661 
   2662 **/
   2663 EFI_STATUS
   2664 XhcPeiSyncTrsRing (
   2665   IN PEI_XHC_DEV    *Xhc,
   2666   IN TRANSFER_RING  *TrsRing
   2667   )
   2668 {
   2669   UINTN             Index;
   2670   TRB_TEMPLATE      *TrsTrb;
   2671 
   2672   ASSERT (TrsRing != NULL);
   2673   //
   2674   // Calculate the latest RingEnqueue and RingPCS
   2675   //
   2676   TrsTrb = TrsRing->RingEnqueue;
   2677   ASSERT (TrsTrb != NULL);
   2678 
   2679   for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
   2680     if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
   2681       break;
   2682     }
   2683     TrsTrb++;
   2684     if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
   2685       ASSERT (((LINK_TRB *) TrsTrb)->TC != 0);
   2686       //
   2687       // set cycle bit in Link TRB as normal
   2688       //
   2689       ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
   2690       //
   2691       // Toggle PCS maintained by software
   2692       //
   2693       TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
   2694       TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0;  // Use host address
   2695     }
   2696   }
   2697 
   2698   ASSERT (Index != TrsRing->TrbNumber);
   2699 
   2700   if (TrsTrb != TrsRing->RingEnqueue) {
   2701     TrsRing->RingEnqueue = TrsTrb;
   2702   }
   2703 
   2704   //
   2705   // Clear the Trb context for enqueue, but reserve the PCS bit
   2706   //
   2707   TrsTrb->Parameter1 = 0;
   2708   TrsTrb->Parameter2 = 0;
   2709   TrsTrb->Status     = 0;
   2710   TrsTrb->RsvdZ1     = 0;
   2711   TrsTrb->Type       = 0;
   2712   TrsTrb->Control    = 0;
   2713 
   2714   return EFI_SUCCESS;
   2715 }
   2716 
   2717 /**
   2718   Create XHCI transfer ring.
   2719 
   2720   @param  Xhc               The XHCI Device.
   2721   @param  TrbNum            The number of TRB in the ring.
   2722   @param  TransferRing      The created transfer ring.
   2723 
   2724 **/
   2725 VOID
   2726 XhcPeiCreateTransferRing (
   2727   IN PEI_XHC_DEV            *Xhc,
   2728   IN UINTN                  TrbNum,
   2729   OUT TRANSFER_RING         *TransferRing
   2730   )
   2731 {
   2732   VOID                  *Buf;
   2733   LINK_TRB              *EndTrb;
   2734   EFI_PHYSICAL_ADDRESS  PhyAddr;
   2735 
   2736   Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
   2737   ASSERT (Buf != NULL);
   2738   ASSERT (((UINTN) Buf & 0x3F) == 0);
   2739   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
   2740 
   2741   TransferRing->RingSeg0     = Buf;
   2742   TransferRing->TrbNumber    = TrbNum;
   2743   TransferRing->RingEnqueue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
   2744   TransferRing->RingDequeue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
   2745   TransferRing->RingPCS      = 1;
   2746   //
   2747   // 4.9.2 Transfer Ring Management
   2748   // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
   2749   // point to the first TRB in the ring.
   2750   //
   2751   EndTrb        = (LINK_TRB *) ((UINTN) Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
   2752   EndTrb->Type  = TRB_TYPE_LINK;
   2753   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
   2754   EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
   2755   EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
   2756   //
   2757   // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
   2758   //
   2759   EndTrb->TC    = 1;
   2760   //
   2761   // Set Cycle bit as other TRB PCS init value
   2762   //
   2763   EndTrb->CycleBit = 0;
   2764 }
   2765 
   2766 /**
   2767   Initialize the XHCI host controller for schedule.
   2768 
   2769   @param  Xhc       The XHCI device to be initialized.
   2770 
   2771 **/
   2772 VOID
   2773 XhcPeiInitSched (
   2774   IN PEI_XHC_DEV        *Xhc
   2775   )
   2776 {
   2777   VOID                  *Dcbaa;
   2778   EFI_PHYSICAL_ADDRESS  DcbaaPhy;
   2779   UINTN                 Size;
   2780   EFI_PHYSICAL_ADDRESS  CmdRingPhy;
   2781   UINT32                MaxScratchpadBufs;
   2782   UINT64                *ScratchBuf;
   2783   EFI_PHYSICAL_ADDRESS  ScratchPhy;
   2784   UINT64                *ScratchEntry;
   2785   EFI_PHYSICAL_ADDRESS  ScratchEntryPhy;
   2786   UINT32                Index;
   2787   EFI_STATUS            Status;
   2788 
   2789   //
   2790   // Initialize memory management.
   2791   //
   2792   Xhc->MemPool = UsbHcInitMemPool ();
   2793   ASSERT (Xhc->MemPool != NULL);
   2794 
   2795   //
   2796   // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
   2797   // to enable the device slots that system software is going to use.
   2798   //
   2799   Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
   2800   ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
   2801   XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);
   2802 
   2803   //
   2804   // The Device Context Base Address Array entry associated with each allocated Device Slot
   2805   // shall contain a 64-bit pointer to the base of the associated Device Context.
   2806   // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
   2807   // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
   2808   //
   2809   Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);
   2810   Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);
   2811   ASSERT (Dcbaa != NULL);
   2812 
   2813   //
   2814   // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
   2815   // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
   2816   // mode (Run/Stop(R/S) ='1').
   2817   //
   2818   MaxScratchpadBufs      = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
   2819   Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
   2820   ASSERT (MaxScratchpadBufs <= 1023);
   2821   if (MaxScratchpadBufs != 0) {
   2822     //
   2823     // Allocate the buffer to record the host address for each entry
   2824     //
   2825     ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
   2826     ASSERT (ScratchEntry != NULL);
   2827     Xhc->ScratchEntry = ScratchEntry;
   2828 
   2829     ScratchPhy = 0;
   2830     Status = UsbHcAllocateAlignedPages (
   2831                EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
   2832                Xhc->PageSize,
   2833                (VOID **) &ScratchBuf,
   2834                &ScratchPhy
   2835                );
   2836     ASSERT_EFI_ERROR (Status);
   2837 
   2838     ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
   2839     Xhc->ScratchBuf = ScratchBuf;
   2840 
   2841     //
   2842     // Allocate each scratch buffer
   2843     //
   2844     for (Index = 0; Index < MaxScratchpadBufs; Index++) {
   2845       ScratchEntryPhy = 0;
   2846       Status = UsbHcAllocateAlignedPages (
   2847                  EFI_SIZE_TO_PAGES (Xhc->PageSize),
   2848                  Xhc->PageSize,
   2849                  (VOID **) &ScratchEntry[Index],
   2850                  &ScratchEntryPhy
   2851                  );
   2852       ASSERT_EFI_ERROR (Status);
   2853       ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);
   2854       //
   2855       // Fill with the PCI device address
   2856       //
   2857       *ScratchBuf++ = ScratchEntryPhy;
   2858     }
   2859     //
   2860     // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
   2861     // Device Context Base Address Array points to the Scratchpad Buffer Array.
   2862     //
   2863     *(UINT64 *) Dcbaa = (UINT64) (UINTN) ScratchPhy;
   2864   }
   2865 
   2866   //
   2867   // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
   2868   // a 64-bit address pointing to where the Device Context Base Address Array is located.
   2869   //
   2870   Xhc->DCBAA = (UINT64 *) (UINTN) Dcbaa;
   2871   //
   2872   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
   2873   // So divide it to two 32-bytes width register access.
   2874   //
   2875   DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);
   2876   XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));
   2877   XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
   2878 
   2879   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));
   2880 
   2881   //
   2882   // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
   2883   // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
   2884   // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
   2885   // always be '0'.
   2886   //
   2887   XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
   2888   //
   2889   // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
   2890   // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
   2891   // So we set RCS as inverted PCS init value to let Command Ring empty
   2892   //
   2893   CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
   2894   ASSERT ((CmdRingPhy & 0x3F) == 0);
   2895   CmdRingPhy |= XHC_CRCR_RCS;
   2896   //
   2897   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
   2898   // So divide it to two 32-bytes width register access.
   2899   //
   2900   XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));
   2901   XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
   2902 
   2903   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
   2904 
   2905   //
   2906   // Disable the 'interrupter enable' bit in USB_CMD
   2907   // and clear IE & IP bit in all Interrupter X Management Registers.
   2908   //
   2909   XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
   2910   for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
   2911     XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
   2912     XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
   2913   }
   2914 
   2915   //
   2916   // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
   2917   //
   2918   XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);
   2919   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
   2920 }
   2921 
   2922 /**
   2923   Free the resouce allocated at initializing schedule.
   2924 
   2925   @param  Xhc       The XHCI device.
   2926 
   2927 **/
   2928 VOID
   2929 XhcPeiFreeSched (
   2930   IN PEI_XHC_DEV    *Xhc
   2931   )
   2932 {
   2933   UINT32                  Index;
   2934   UINT64                  *ScratchEntry;
   2935 
   2936   if (Xhc->ScratchBuf != NULL) {
   2937     ScratchEntry = Xhc->ScratchEntry;
   2938     for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
   2939       //
   2940       // Free Scratchpad Buffers
   2941       //
   2942       UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));
   2943     }
   2944     //
   2945     // Free Scratchpad Buffer Array
   2946     //
   2947     UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));
   2948     FreePool (Xhc->ScratchEntry);
   2949   }
   2950 
   2951   if (Xhc->CmdRing.RingSeg0 != NULL) {
   2952     UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
   2953     Xhc->CmdRing.RingSeg0 = NULL;
   2954   }
   2955 
   2956   XhcPeiFreeEventRing (Xhc,&Xhc->EventRing);
   2957 
   2958   if (Xhc->DCBAA != NULL) {
   2959     UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));
   2960     Xhc->DCBAA = NULL;
   2961   }
   2962 
   2963   //
   2964   // Free memory pool at last
   2965   //
   2966   if (Xhc->MemPool != NULL) {
   2967     UsbHcFreeMemPool (Xhc->MemPool);
   2968     Xhc->MemPool = NULL;
   2969   }
   2970 }
   2971 
   2972