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 // Two arrays used to translate the XHCI port state (change)
     22 // to the UEFI protocol's port state (change).
     23 //
     24 USB_PORT_STATE_MAP  mUsbPortStateMap[] = {
     25   {XHC_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},
     26   {XHC_PORTSC_PED,   USB_PORT_STAT_ENABLE},
     27   {XHC_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},
     28   {XHC_PORTSC_PP,    USB_PORT_STAT_POWER},
     29   {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
     30 };
     31 
     32 USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
     33   {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
     34   {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
     35   {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
     36   {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
     37 };
     38 
     39 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
     40   {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
     41   {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
     42   {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
     43   {XHC_PORTSC_PRC, EfiUsbPortResetChange}
     44 };
     45 
     46 USB_PORT_STATE_MAP  mUsbHubPortStateMap[] = {
     47   {XHC_HUB_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},
     48   {XHC_HUB_PORTSC_PED,   USB_PORT_STAT_ENABLE},
     49   {XHC_HUB_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},
     50   {XHC_HUB_PORTSC_PP,    USB_PORT_STAT_POWER},
     51   {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
     52 };
     53 
     54 USB_PORT_STATE_MAP  mUsbHubPortChangeMap[] = {
     55   {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
     56   {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
     57   {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
     58   {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
     59 };
     60 
     61 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
     62   {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
     63   {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
     64   {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
     65   {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
     66   {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
     67 };
     68 
     69 /**
     70   Read XHCI Operation register.
     71 
     72   @param Xhc            The XHCI device.
     73   @param Offset         The operation register offset.
     74 
     75   @retval the register content read.
     76 
     77 **/
     78 UINT32
     79 XhcPeiReadOpReg (
     80   IN PEI_XHC_DEV        *Xhc,
     81   IN UINT32             Offset
     82   )
     83 {
     84   UINT32                Data;
     85 
     86   ASSERT (Xhc->CapLength != 0);
     87 
     88   Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);
     89   return Data;
     90 }
     91 
     92 /**
     93   Write the data to the XHCI operation register.
     94 
     95   @param Xhc            The XHCI device.
     96   @param Offset         The operation register offset.
     97   @param Data           The data to write.
     98 
     99 **/
    100 VOID
    101 XhcPeiWriteOpReg (
    102   IN PEI_XHC_DEV        *Xhc,
    103   IN UINT32             Offset,
    104   IN UINT32             Data
    105   )
    106 {
    107   ASSERT (Xhc->CapLength != 0);
    108 
    109   MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);
    110 }
    111 
    112 /**
    113   Set one bit of the operational register while keeping other bits.
    114 
    115   @param  Xhc           The XHCI device.
    116   @param  Offset        The offset of the operational register.
    117   @param  Bit           The bit mask of the register to set.
    118 
    119 **/
    120 VOID
    121 XhcPeiSetOpRegBit (
    122   IN PEI_XHC_DEV        *Xhc,
    123   IN UINT32             Offset,
    124   IN UINT32             Bit
    125   )
    126 {
    127   UINT32                Data;
    128 
    129   Data  = XhcPeiReadOpReg (Xhc, Offset);
    130   Data |= Bit;
    131   XhcPeiWriteOpReg (Xhc, Offset, Data);
    132 }
    133 
    134 /**
    135   Clear one bit of the operational register while keeping other bits.
    136 
    137   @param  Xhc           The XHCI device.
    138   @param  Offset        The offset of the operational register.
    139   @param  Bit           The bit mask of the register to clear.
    140 
    141 **/
    142 VOID
    143 XhcPeiClearOpRegBit (
    144   IN PEI_XHC_DEV        *Xhc,
    145   IN UINT32             Offset,
    146   IN UINT32             Bit
    147   )
    148 {
    149   UINT32                Data;
    150 
    151   Data  = XhcPeiReadOpReg (Xhc, Offset);
    152   Data &= ~Bit;
    153   XhcPeiWriteOpReg (Xhc, Offset, Data);
    154 }
    155 
    156 /**
    157   Wait the operation register's bit as specified by Bit
    158   to become set (or clear).
    159 
    160   @param  Xhc           The XHCI device.
    161   @param  Offset        The offset of the operational register.
    162   @param  Bit           The bit mask of the register to wait for.
    163   @param  WaitToSet     Wait the bit to set or clear.
    164   @param  Timeout       The time to wait before abort (in millisecond, ms).
    165 
    166   @retval EFI_SUCCESS   The bit successfully changed by host controller.
    167   @retval EFI_TIMEOUT   The time out occurred.
    168 
    169 **/
    170 EFI_STATUS
    171 XhcPeiWaitOpRegBit (
    172   IN PEI_XHC_DEV        *Xhc,
    173   IN UINT32             Offset,
    174   IN UINT32             Bit,
    175   IN BOOLEAN            WaitToSet,
    176   IN UINT32             Timeout
    177   )
    178 {
    179   UINT64                Index;
    180 
    181   for (Index = 0; Index < Timeout * XHC_1_MILLISECOND; Index++) {
    182     if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
    183       return EFI_SUCCESS;
    184     }
    185 
    186     MicroSecondDelay (XHC_1_MICROSECOND);
    187   }
    188 
    189   return EFI_TIMEOUT;
    190 }
    191 
    192 /**
    193   Read XHCI capability register.
    194 
    195   @param Xhc        The XHCI device.
    196   @param Offset     Capability register address.
    197 
    198   @retval the register content read.
    199 
    200 **/
    201 UINT32
    202 XhcPeiReadCapRegister (
    203   IN PEI_XHC_DEV        *Xhc,
    204   IN UINT32             Offset
    205   )
    206 {
    207   UINT32                Data;
    208 
    209   Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);
    210 
    211   return Data;
    212 }
    213 
    214 /**
    215   Read XHCI door bell register.
    216 
    217   @param  Xhc       The XHCI device.
    218   @param  Offset    The offset of the door bell register.
    219 
    220   @return The register content read
    221 
    222 **/
    223 UINT32
    224 XhcPeiReadDoorBellReg (
    225   IN  PEI_XHC_DEV       *Xhc,
    226   IN  UINT32            Offset
    227   )
    228 {
    229   UINT32                  Data;
    230 
    231   ASSERT (Xhc->DBOff != 0);
    232 
    233   Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset);
    234 
    235   return Data;
    236 }
    237 
    238 /**
    239   Write the data to the XHCI door bell register.
    240 
    241   @param  Xhc           The XHCI device.
    242   @param  Offset        The offset of the door bell register.
    243   @param  Data          The data to write.
    244 
    245 **/
    246 VOID
    247 XhcPeiWriteDoorBellReg (
    248   IN PEI_XHC_DEV        *Xhc,
    249   IN UINT32             Offset,
    250   IN UINT32             Data
    251   )
    252 {
    253   ASSERT (Xhc->DBOff != 0);
    254 
    255   MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);
    256 }
    257 
    258 /**
    259   Read XHCI runtime register.
    260 
    261   @param  Xhc           The XHCI device.
    262   @param  Offset        The offset of the runtime register.
    263 
    264   @return The register content read
    265 
    266 **/
    267 UINT32
    268 XhcPeiReadRuntimeReg (
    269   IN  PEI_XHC_DEV       *Xhc,
    270   IN  UINT32            Offset
    271   )
    272 {
    273   UINT32                Data;
    274 
    275   ASSERT (Xhc->RTSOff != 0);
    276 
    277   Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);
    278 
    279   return Data;
    280 }
    281 
    282 /**
    283   Write the data to the XHCI runtime register.
    284 
    285   @param  Xhc       The XHCI device.
    286   @param  Offset    The offset of the runtime register.
    287   @param  Data      The data to write.
    288 
    289 **/
    290 VOID
    291 XhcPeiWriteRuntimeReg (
    292   IN PEI_XHC_DEV          *Xhc,
    293   IN UINT32               Offset,
    294   IN UINT32               Data
    295   )
    296 {
    297   ASSERT (Xhc->RTSOff != 0);
    298 
    299   MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);
    300 }
    301 
    302 /**
    303   Set one bit of the runtime register while keeping other bits.
    304 
    305   @param  Xhc          The XHCI device.
    306   @param  Offset       The offset of the runtime register.
    307   @param  Bit          The bit mask of the register to set.
    308 
    309 **/
    310 VOID
    311 XhcPeiSetRuntimeRegBit (
    312   IN PEI_XHC_DEV        *Xhc,
    313   IN UINT32             Offset,
    314   IN UINT32             Bit
    315   )
    316 {
    317   UINT32                Data;
    318 
    319   Data  = XhcPeiReadRuntimeReg (Xhc, Offset);
    320   Data |= Bit;
    321   XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
    322 }
    323 
    324 /**
    325   Clear one bit of the runtime register while keeping other bits.
    326 
    327   @param  Xhc          The XHCI device.
    328   @param  Offset       The offset of the runtime register.
    329   @param  Bit          The bit mask of the register to set.
    330 
    331 **/
    332 VOID
    333 XhcPeiClearRuntimeRegBit (
    334   IN PEI_XHC_DEV        *Xhc,
    335   IN UINT32             Offset,
    336   IN UINT32             Bit
    337   )
    338 {
    339   UINT32                Data;
    340 
    341   Data  = XhcPeiReadRuntimeReg (Xhc, Offset);
    342   Data &= ~Bit;
    343   XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
    344 }
    345 
    346 /**
    347   Check whether Xhc is halted.
    348 
    349   @param  Xhc           The XHCI device.
    350 
    351   @retval TRUE          The controller is halted.
    352   @retval FALSE         The controller isn't halted.
    353 
    354 **/
    355 BOOLEAN
    356 XhcPeiIsHalt (
    357   IN PEI_XHC_DEV        *Xhc
    358   )
    359 {
    360   return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
    361 }
    362 
    363 /**
    364   Check whether system error occurred.
    365 
    366   @param  Xhc           The XHCI device.
    367 
    368   @retval TRUE          System error happened.
    369   @retval FALSE         No system error.
    370 
    371 **/
    372 BOOLEAN
    373 XhcPeiIsSysError (
    374   IN PEI_XHC_DEV        *Xhc
    375   )
    376 {
    377   return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
    378 }
    379 
    380 /**
    381   Reset the host controller.
    382 
    383   @param  Xhc           The XHCI device.
    384   @param  Timeout       Time to wait before abort (in millisecond, ms).
    385 
    386   @retval EFI_TIMEOUT   The transfer failed due to time out.
    387   @retval Others        Failed to reset the host.
    388 
    389 **/
    390 EFI_STATUS
    391 XhcPeiResetHC (
    392   IN PEI_XHC_DEV        *Xhc,
    393   IN UINT32             Timeout
    394   )
    395 {
    396   EFI_STATUS            Status;
    397 
    398   //
    399   // Host can only be reset when it is halt. If not so, halt it
    400   //
    401   if (!XhcPeiIsHalt (Xhc)) {
    402     Status = XhcPeiHaltHC (Xhc, Timeout);
    403 
    404     if (EFI_ERROR (Status)) {
    405       goto ON_EXIT;
    406     }
    407   }
    408 
    409   XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
    410   //
    411   // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
    412   // Otherwise there may have the timeout case happened.
    413   // The below is a workaround to solve such problem.
    414   //
    415   MicroSecondDelay (1000);
    416   Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
    417 ON_EXIT:
    418   DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));
    419   return Status;
    420 }
    421 
    422 /**
    423   Halt the host controller.
    424 
    425   @param  Xhc           The XHCI device.
    426   @param  Timeout       Time to wait before abort.
    427 
    428   @retval EFI_TIMEOUT   Failed to halt the controller before Timeout.
    429   @retval EFI_SUCCESS   The XHCI is halt.
    430 
    431 **/
    432 EFI_STATUS
    433 XhcPeiHaltHC (
    434   IN PEI_XHC_DEV        *Xhc,
    435   IN UINT32             Timeout
    436   )
    437 {
    438   EFI_STATUS            Status;
    439 
    440   XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
    441   Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
    442   DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));
    443   return Status;
    444 }
    445 
    446 /**
    447   Set the XHCI to run.
    448 
    449   @param  Xhc           The XHCI device.
    450   @param  Timeout       Time to wait before abort.
    451 
    452   @retval EFI_SUCCESS   The XHCI is running.
    453   @retval Others        Failed to set the XHCI to run.
    454 
    455 **/
    456 EFI_STATUS
    457 XhcPeiRunHC (
    458   IN PEI_XHC_DEV        *Xhc,
    459   IN UINT32             Timeout
    460   )
    461 {
    462   EFI_STATUS            Status;
    463 
    464   XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
    465   Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
    466   DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));
    467   return Status;
    468 }
    469 
    470 /**
    471   Submits control transfer to a target USB device.
    472 
    473   @param  PeiServices               The pointer of EFI_PEI_SERVICES.
    474   @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
    475   @param  DeviceAddress             The target device address.
    476   @param  DeviceSpeed               Target device speed.
    477   @param  MaximumPacketLength       Maximum packet size the default control transfer
    478                                     endpoint is capable of sending or receiving.
    479   @param  Request                   USB device request to send.
    480   @param  TransferDirection         Specifies the data direction for the data stage.
    481   @param  Data                      Data buffer to be transmitted or received from USB device.
    482   @param  DataLength                The size (in bytes) of the data buffer.
    483   @param  TimeOut                   Indicates the maximum timeout, in millisecond.
    484                                     If Timeout is 0, then the caller must wait for the function
    485                                     to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
    486   @param  Translator                Transaction translator to be used by this device.
    487   @param  TransferResult            Return the result of this control transfer.
    488 
    489   @retval EFI_SUCCESS               Transfer was completed successfully.
    490   @retval EFI_OUT_OF_RESOURCES      The transfer failed due to lack of resources.
    491   @retval EFI_INVALID_PARAMETER     Some parameters are invalid.
    492   @retval EFI_TIMEOUT               Transfer failed due to timeout.
    493   @retval EFI_DEVICE_ERROR          Transfer failed due to host controller or device error.
    494 
    495 **/
    496 EFI_STATUS
    497 EFIAPI
    498 XhcPeiControlTransfer (
    499   IN EFI_PEI_SERVICES                       **PeiServices,
    500   IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
    501   IN UINT8                                  DeviceAddress,
    502   IN UINT8                                  DeviceSpeed,
    503   IN UINTN                                  MaximumPacketLength,
    504   IN EFI_USB_DEVICE_REQUEST                 *Request,
    505   IN EFI_USB_DATA_DIRECTION                 TransferDirection,
    506   IN OUT VOID                               *Data,
    507   IN OUT UINTN                              *DataLength,
    508   IN UINTN                                  TimeOut,
    509   IN EFI_USB2_HC_TRANSACTION_TRANSLATOR     *Translator,
    510   OUT UINT32                                *TransferResult
    511   )
    512 {
    513   PEI_XHC_DEV                   *Xhc;
    514   URB                           *Urb;
    515   UINT8                         Endpoint;
    516   UINT8                         Index;
    517   UINT8                         DescriptorType;
    518   UINT8                         SlotId;
    519   UINT8                         TTT;
    520   UINT8                         MTT;
    521   UINT32                        MaxPacket0;
    522   EFI_USB_HUB_DESCRIPTOR        *HubDesc;
    523   EFI_STATUS                    Status;
    524   EFI_STATUS                    RecoveryStatus;
    525   UINTN                         MapSize;
    526   EFI_USB_PORT_STATUS           PortStatus;
    527   UINT32                        State;
    528   EFI_USB_DEVICE_REQUEST        ClearPortRequest;
    529   UINTN                         Len;
    530 
    531   //
    532   // Validate parameters
    533   //
    534   if ((Request == NULL) || (TransferResult == NULL)) {
    535     return EFI_INVALID_PARAMETER;
    536   }
    537 
    538   if ((TransferDirection != EfiUsbDataIn) &&
    539       (TransferDirection != EfiUsbDataOut) &&
    540       (TransferDirection != EfiUsbNoData)) {
    541     return EFI_INVALID_PARAMETER;
    542   }
    543 
    544   if ((TransferDirection == EfiUsbNoData) &&
    545       ((Data != NULL) || (*DataLength != 0))) {
    546     return EFI_INVALID_PARAMETER;
    547   }
    548 
    549   if ((TransferDirection != EfiUsbNoData) &&
    550      ((Data == NULL) || (*DataLength == 0))) {
    551     return EFI_INVALID_PARAMETER;
    552   }
    553 
    554   if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&
    555       (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
    556       (MaximumPacketLength != 512)
    557       ) {
    558     return EFI_INVALID_PARAMETER;
    559   }
    560 
    561   if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
    562     return EFI_INVALID_PARAMETER;
    563   }
    564 
    565   if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
    566     return EFI_INVALID_PARAMETER;
    567   }
    568 
    569   Xhc             = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
    570 
    571   Status          = EFI_DEVICE_ERROR;
    572   *TransferResult = EFI_USB_ERR_SYSTEM;
    573   Len             = 0;
    574 
    575   if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
    576     DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));
    577     goto ON_EXIT;
    578   }
    579 
    580   //
    581   // Check if the device is still enabled before every transaction.
    582   //
    583   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
    584   if (SlotId == 0) {
    585     goto ON_EXIT;
    586   }
    587 
    588   //
    589   // Hook the Set_Address request from UsbBus.
    590   // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
    591   //
    592   if ((Request->Request     == USB_REQ_SET_ADDRESS) &&
    593       (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
    594     //
    595     // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
    596     // This way is used to clean the history to avoid using wrong device address afterwards.
    597     //
    598     for (Index = 0; Index < 255; Index++) {
    599       if (!Xhc->UsbDevContext[Index + 1].Enabled &&
    600           (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
    601           (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {
    602         Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
    603       }
    604     }
    605 
    606     if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
    607       goto ON_EXIT;
    608     }
    609     //
    610     // The actual device address has been assigned by XHCI during initializing the device slot.
    611     // So we just need establish the mapping relationship between the device address requested from UsbBus
    612     // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface
    613     // can find out the actual device address by it.
    614     //
    615     Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;
    616     Status = EFI_SUCCESS;
    617     goto ON_EXIT;
    618   }
    619 
    620   //
    621   // Create a new URB, insert it into the asynchronous
    622   // schedule list, then poll the execution status.
    623   // Note that we encode the direction in address although default control
    624   // endpoint is bidirectional. XhcPeiCreateUrb expects this
    625   // combination of Ep addr and its direction.
    626   //
    627   Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
    628   Urb = XhcPeiCreateUrb (
    629           Xhc,
    630           DeviceAddress,
    631           Endpoint,
    632           DeviceSpeed,
    633           MaximumPacketLength,
    634           XHC_CTRL_TRANSFER,
    635           Request,
    636           Data,
    637           *DataLength,
    638           NULL,
    639           NULL
    640           );
    641 
    642   if (Urb == NULL) {
    643     DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));
    644     Status = EFI_OUT_OF_RESOURCES;
    645     goto ON_EXIT;
    646   }
    647 
    648   Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
    649 
    650   //
    651   // Get the status from URB. The result is updated in XhcPeiCheckUrbResult
    652   // which is called by XhcPeiExecTransfer
    653   //
    654   *TransferResult = Urb->Result;
    655   *DataLength     = Urb->Completed;
    656 
    657   if (Status == EFI_TIMEOUT) {
    658     //
    659     // The transfer timed out. Abort the transfer by dequeueing of the TD.
    660     //
    661     RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
    662     if (EFI_ERROR(RecoveryStatus)) {
    663       DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
    664     }
    665     goto FREE_URB;
    666   } else {
    667     if (*TransferResult == EFI_USB_NOERROR) {
    668       Status = EFI_SUCCESS;
    669     } else if (*TransferResult == EFI_USB_ERR_STALL) {
    670       RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
    671       if (EFI_ERROR (RecoveryStatus)) {
    672         DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
    673       }
    674       Status = EFI_DEVICE_ERROR;
    675       goto FREE_URB;
    676     } else {
    677       goto FREE_URB;
    678     }
    679   }
    680 
    681   //
    682   // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
    683   // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
    684   // Hook Set_Config request from UsbBus as we need configure device endpoint.
    685   //
    686   if ((Request->Request     == USB_REQ_GET_DESCRIPTOR) &&
    687       ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
    688       ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
    689     DescriptorType = (UINT8) (Request->Value >> 8);
    690     if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
    691       ASSERT (Data != NULL);
    692       //
    693       // Store a copy of device scriptor as hub device need this info to configure endpoint.
    694       //
    695       CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
    696       if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
    697         //
    698         // If it's a usb3.0 device, then its max packet size is a 2^n.
    699         //
    700         MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
    701       } else {
    702         MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
    703       }
    704       Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
    705       if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
    706         Status = EFI_OUT_OF_RESOURCES;
    707         goto FREE_URB;
    708       }
    709       if (Xhc->HcCParams.Data.Csz == 0) {
    710         Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
    711       } else {
    712         Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);
    713       }
    714     } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
    715       ASSERT (Data != NULL);
    716       if (*DataLength == ((UINT16 *) Data)[1]) {
    717         //
    718         // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
    719         //
    720         Index = (UINT8) Request->Value;
    721         ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
    722         Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
    723         if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
    724           Status = EFI_OUT_OF_RESOURCES;
    725           goto FREE_URB;
    726         }
    727         CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
    728       }
    729     } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
    730                (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
    731       ASSERT (Data != NULL);
    732       HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;
    733       ASSERT (HubDesc->NumPorts <= 15);
    734       //
    735       // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
    736       //
    737       TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
    738       if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
    739         //
    740         // Don't support multi-TT feature for super speed hub now.
    741         //
    742         MTT = 0;
    743         DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
    744       } else {
    745         MTT = 0;
    746       }
    747 
    748       if (Xhc->HcCParams.Data.Csz == 0) {
    749         Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
    750       } else {
    751         Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
    752       }
    753     }
    754   } else if ((Request->Request     == USB_REQ_SET_CONFIG) &&
    755              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
    756     //
    757     // Hook Set_Config request from UsbBus as we need configure device endpoint.
    758     //
    759     for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
    760       if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
    761         if (Xhc->HcCParams.Data.Csz == 0) {
    762           Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
    763         } else {
    764           Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
    765         }
    766         break;
    767       }
    768     }
    769   } else if ((Request->Request     == USB_REQ_GET_STATUS) &&
    770              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
    771     ASSERT (Data != NULL);
    772     //
    773     // Hook Get_Status request from UsbBus to keep track of the port status change.
    774     //
    775     State                       = *(UINT32 *) Data;
    776     PortStatus.PortStatus       = 0;
    777     PortStatus.PortChangeStatus = 0;
    778 
    779     if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
    780       //
    781       // For super speed hub, its bit10~12 presents the attached device speed.
    782       //
    783       if ((State & XHC_PORTSC_PS) >> 10 == 0) {
    784         PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
    785       }
    786     } else {
    787       //
    788       // For high or full/low speed hub, its bit9~10 presents the attached device speed.
    789       //
    790       if (XHC_BIT_IS_SET (State, BIT9)) {
    791         PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
    792       } else if (XHC_BIT_IS_SET (State, BIT10)) {
    793         PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
    794       }
    795     }
    796 
    797     //
    798     // Convert the XHCI port/port change state to UEFI status
    799     //
    800     MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
    801     for (Index = 0; Index < MapSize; Index++) {
    802       if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
    803         PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
    804       }
    805     }
    806 
    807     MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
    808     for (Index = 0; Index < MapSize; Index++) {
    809       if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
    810         PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
    811       }
    812     }
    813 
    814     MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
    815 
    816     for (Index = 0; Index < MapSize; Index++) {
    817       if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
    818         ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
    819         ClearPortRequest.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
    820         ClearPortRequest.Request      = (UINT8) USB_REQ_CLEAR_FEATURE;
    821         ClearPortRequest.Value        = mUsbHubClearPortChangeMap[Index].Selector;
    822         ClearPortRequest.Index        = Request->Index;
    823         ClearPortRequest.Length       = 0;
    824 
    825         XhcPeiControlTransfer (
    826           PeiServices,
    827           This,
    828           DeviceAddress,
    829           DeviceSpeed,
    830           MaximumPacketLength,
    831           &ClearPortRequest,
    832           EfiUsbNoData,
    833           NULL,
    834           &Len,
    835           TimeOut,
    836           Translator,
    837           TransferResult
    838           );
    839       }
    840     }
    841 
    842     XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
    843 
    844     *(UINT32 *) Data = *(UINT32 *) &PortStatus;
    845   }
    846 
    847 FREE_URB:
    848   XhcPeiFreeUrb (Xhc, Urb);
    849 
    850 ON_EXIT:
    851 
    852   if (EFI_ERROR (Status)) {
    853     DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
    854   }
    855 
    856   return Status;
    857 }
    858 
    859 /**
    860   Submits bulk transfer to a bulk endpoint of a USB device.
    861 
    862   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
    863   @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
    864   @param  DeviceAddress         Target device address.
    865   @param  EndPointAddress       Endpoint number and its direction in bit 7.
    866   @param  DeviceSpeed           Device speed, Low speed device doesn't support
    867                                 bulk transfer.
    868   @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
    869                                 sending or receiving.
    870   @param  Data                  Array of pointers to the buffers of data to transmit
    871                                 from or receive into.
    872   @param  DataLength            The lenght of the data buffer.
    873   @param  DataToggle            On input, the initial data toggle for the transfer;
    874                                 On output, it is updated to to next data toggle to use of
    875                                 the subsequent bulk transfer.
    876   @param  TimeOut               Indicates the maximum time, in millisecond, which the
    877                                 transfer is allowed to complete.
    878                                 If Timeout is 0, then the caller must wait for the function
    879                                 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
    880   @param  Translator            A pointr to the transaction translator data.
    881   @param  TransferResult        A pointer to the detailed result information of the
    882                                 bulk transfer.
    883 
    884   @retval EFI_SUCCESS           The transfer was completed successfully.
    885   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
    886   @retval EFI_INVALID_PARAMETER Parameters are invalid.
    887   @retval EFI_TIMEOUT           The transfer failed due to timeout.
    888   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
    889 
    890 **/
    891 EFI_STATUS
    892 EFIAPI
    893 XhcPeiBulkTransfer (
    894   IN EFI_PEI_SERVICES                       **PeiServices,
    895   IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
    896   IN UINT8                                  DeviceAddress,
    897   IN UINT8                                  EndPointAddress,
    898   IN UINT8                                  DeviceSpeed,
    899   IN UINTN                                  MaximumPacketLength,
    900   IN OUT VOID                               *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
    901   IN OUT UINTN                              *DataLength,
    902   IN OUT UINT8                              *DataToggle,
    903   IN UINTN                                  TimeOut,
    904   IN EFI_USB2_HC_TRANSACTION_TRANSLATOR     *Translator,
    905   OUT UINT32                                *TransferResult
    906   )
    907 {
    908   PEI_XHC_DEV                   *Xhc;
    909   URB                           *Urb;
    910   UINT8                         SlotId;
    911   EFI_STATUS                    Status;
    912   EFI_STATUS                    RecoveryStatus;
    913 
    914   //
    915   // Validate the parameters
    916   //
    917   if ((DataLength == NULL) || (*DataLength == 0) ||
    918       (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
    919     return EFI_INVALID_PARAMETER;
    920   }
    921 
    922   if ((*DataToggle != 0) && (*DataToggle != 1)) {
    923     return EFI_INVALID_PARAMETER;
    924   }
    925 
    926   if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
    927       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
    928       ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||
    929       ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {
    930     return EFI_INVALID_PARAMETER;
    931   }
    932 
    933   Xhc             = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
    934 
    935   *TransferResult = EFI_USB_ERR_SYSTEM;
    936   Status          = EFI_DEVICE_ERROR;
    937 
    938   if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
    939     DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
    940     goto ON_EXIT;
    941   }
    942 
    943   //
    944   // Check if the device is still enabled before every transaction.
    945   //
    946   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
    947   if (SlotId == 0) {
    948     goto ON_EXIT;
    949   }
    950 
    951   //
    952   // Create a new URB, insert it into the asynchronous
    953   // schedule list, then poll the execution status.
    954   //
    955   Urb = XhcPeiCreateUrb (
    956           Xhc,
    957           DeviceAddress,
    958           EndPointAddress,
    959           DeviceSpeed,
    960           MaximumPacketLength,
    961           XHC_BULK_TRANSFER,
    962           NULL,
    963           Data[0],
    964           *DataLength,
    965           NULL,
    966           NULL
    967           );
    968 
    969   if (Urb == NULL) {
    970     DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));
    971     Status = EFI_OUT_OF_RESOURCES;
    972     goto ON_EXIT;
    973   }
    974 
    975   Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
    976 
    977   *TransferResult = Urb->Result;
    978   *DataLength     = Urb->Completed;
    979 
    980   if (Status == EFI_TIMEOUT) {
    981     //
    982     // The transfer timed out. Abort the transfer by dequeueing of the TD.
    983     //
    984     RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
    985     if (EFI_ERROR(RecoveryStatus)) {
    986       DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
    987     }
    988   } else {
    989     if (*TransferResult == EFI_USB_NOERROR) {
    990       Status = EFI_SUCCESS;
    991     } else if (*TransferResult == EFI_USB_ERR_STALL) {
    992       RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
    993       if (EFI_ERROR (RecoveryStatus)) {
    994         DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
    995       }
    996       Status = EFI_DEVICE_ERROR;
    997     }
    998   }
    999 
   1000   XhcPeiFreeUrb (Xhc, Urb);
   1001 
   1002 ON_EXIT:
   1003 
   1004   if (EFI_ERROR (Status)) {
   1005     DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
   1006   }
   1007 
   1008   return Status;
   1009 }
   1010 
   1011 /**
   1012   Retrieves the number of root hub ports.
   1013 
   1014   @param[in]  PeiServices           The pointer to the PEI Services Table.
   1015   @param[in]  This                  The pointer to this instance of the
   1016                                     PEI_USB2_HOST_CONTROLLER_PPI.
   1017   @param[out] PortNumber            The pointer to the number of the root hub ports.
   1018 
   1019   @retval EFI_SUCCESS               The port number was retrieved successfully.
   1020   @retval EFI_INVALID_PARAMETER     PortNumber is NULL.
   1021 
   1022 **/
   1023 EFI_STATUS
   1024 EFIAPI
   1025 XhcPeiGetRootHubPortNumber (
   1026   IN EFI_PEI_SERVICES               **PeiServices,
   1027   IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
   1028   OUT UINT8                         *PortNumber
   1029   )
   1030 {
   1031   PEI_XHC_DEV           *XhcDev;
   1032   XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
   1033 
   1034   if (PortNumber == NULL) {
   1035     return EFI_INVALID_PARAMETER;
   1036   }
   1037 
   1038   *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;
   1039   DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));
   1040   return EFI_SUCCESS;
   1041 }
   1042 
   1043 /**
   1044   Clears a feature for the specified root hub port.
   1045 
   1046   @param  PeiServices               The pointer of EFI_PEI_SERVICES.
   1047   @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
   1048   @param  PortNumber                Specifies the root hub port whose feature
   1049                                     is requested to be cleared.
   1050   @param  PortFeature               Indicates the feature selector associated with the
   1051                                     feature clear request.
   1052 
   1053   @retval EFI_SUCCESS               The feature specified by PortFeature was cleared
   1054                                     for the USB root hub port specified by PortNumber.
   1055   @retval EFI_INVALID_PARAMETER     PortNumber is invalid or PortFeature is invalid.
   1056 
   1057 **/
   1058 EFI_STATUS
   1059 EFIAPI
   1060 XhcPeiClearRootHubPortFeature (
   1061   IN EFI_PEI_SERVICES               **PeiServices,
   1062   IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
   1063   IN UINT8                          PortNumber,
   1064   IN EFI_USB_PORT_FEATURE           PortFeature
   1065   )
   1066 {
   1067   PEI_XHC_DEV           *Xhc;
   1068   UINT32                Offset;
   1069   UINT32                State;
   1070   EFI_STATUS            Status;
   1071 
   1072   Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
   1073   Status = EFI_SUCCESS;
   1074 
   1075   if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
   1076     Status = EFI_INVALID_PARAMETER;
   1077     goto ON_EXIT;
   1078   }
   1079 
   1080   Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
   1081   State = XhcPeiReadOpReg (Xhc, Offset);
   1082   DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
   1083 
   1084   //
   1085   // Mask off the port status change bits, these bits are
   1086   // write clean bits
   1087   //
   1088   State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
   1089 
   1090   switch (PortFeature) {
   1091     case EfiUsbPortEnable:
   1092       //
   1093       // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
   1094       // A port may be disabled by software writing a '1' to this flag.
   1095       //
   1096       State |= XHC_PORTSC_PED;
   1097       State &= ~XHC_PORTSC_RESET;
   1098       XhcPeiWriteOpReg (Xhc, Offset, State);
   1099       break;
   1100 
   1101     case EfiUsbPortSuspend:
   1102       State |= XHC_PORTSC_LWS;
   1103       XhcPeiWriteOpReg (Xhc, Offset, State);
   1104       State &= ~XHC_PORTSC_PLS;
   1105       XhcPeiWriteOpReg (Xhc, Offset, State);
   1106       break;
   1107 
   1108     case EfiUsbPortReset:
   1109       //
   1110       // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
   1111       // Register bits indicate status when read, a clear bit may be set by
   1112       // writing a '1'. Writing a '0' to RW1S bits has no effect.
   1113       //
   1114       break;
   1115 
   1116     case EfiUsbPortPower:
   1117       if (Xhc->HcCParams.Data.Ppc) {
   1118         //
   1119         // Port Power Control supported
   1120         //
   1121         State &= ~XHC_PORTSC_PP;
   1122         XhcPeiWriteOpReg (Xhc, Offset, State);
   1123       }
   1124       break;
   1125 
   1126     case EfiUsbPortOwner:
   1127       //
   1128       // XHCI root hub port don't has the owner bit, ignore the operation
   1129       //
   1130       break;
   1131 
   1132     case EfiUsbPortConnectChange:
   1133       //
   1134       // Clear connect status change
   1135       //
   1136       State |= XHC_PORTSC_CSC;
   1137       XhcPeiWriteOpReg (Xhc, Offset, State);
   1138       break;
   1139 
   1140     case EfiUsbPortEnableChange:
   1141       //
   1142       // Clear enable status change
   1143       //
   1144       State |= XHC_PORTSC_PEC;
   1145       XhcPeiWriteOpReg (Xhc, Offset, State);
   1146       break;
   1147 
   1148     case EfiUsbPortOverCurrentChange:
   1149       //
   1150       // Clear PortOverCurrent change
   1151       //
   1152       State |= XHC_PORTSC_OCC;
   1153       XhcPeiWriteOpReg (Xhc, Offset, State);
   1154       break;
   1155 
   1156     case EfiUsbPortResetChange:
   1157       //
   1158       // Clear Port Reset change
   1159       //
   1160       State |= XHC_PORTSC_PRC;
   1161       XhcPeiWriteOpReg (Xhc, Offset, State);
   1162       break;
   1163 
   1164     case EfiUsbPortSuspendChange:
   1165       //
   1166       // Not supported or not related operation
   1167       //
   1168       break;
   1169 
   1170     default:
   1171       Status = EFI_INVALID_PARAMETER;
   1172       break;
   1173   }
   1174 
   1175 ON_EXIT:
   1176   DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
   1177   return Status;
   1178 }
   1179 
   1180 /**
   1181   Sets a feature for the specified root hub port.
   1182 
   1183   @param  PeiServices               The pointer of EFI_PEI_SERVICES
   1184   @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI
   1185   @param  PortNumber                Root hub port to set.
   1186   @param  PortFeature               Feature to set.
   1187 
   1188   @retval EFI_SUCCESS               The feature specified by PortFeature was set.
   1189   @retval EFI_INVALID_PARAMETER     PortNumber is invalid or PortFeature is invalid.
   1190   @retval EFI_TIMEOUT               The time out occurred.
   1191 
   1192 **/
   1193 EFI_STATUS
   1194 EFIAPI
   1195 XhcPeiSetRootHubPortFeature (
   1196   IN EFI_PEI_SERVICES               **PeiServices,
   1197   IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
   1198   IN UINT8                          PortNumber,
   1199   IN EFI_USB_PORT_FEATURE           PortFeature
   1200   )
   1201 {
   1202   PEI_XHC_DEV           *Xhc;
   1203   UINT32                Offset;
   1204   UINT32                State;
   1205   EFI_STATUS            Status;
   1206 
   1207   Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
   1208   Status = EFI_SUCCESS;
   1209 
   1210   if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
   1211     Status = EFI_INVALID_PARAMETER;
   1212     goto ON_EXIT;
   1213   }
   1214 
   1215   Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
   1216   State = XhcPeiReadOpReg (Xhc, Offset);
   1217   DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
   1218 
   1219   //
   1220   // Mask off the port status change bits, these bits are
   1221   // write clean bits
   1222   //
   1223   State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
   1224 
   1225   switch (PortFeature) {
   1226     case EfiUsbPortEnable:
   1227       //
   1228       // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
   1229       // A port may be disabled by software writing a '1' to this flag.
   1230       //
   1231       break;
   1232 
   1233     case EfiUsbPortSuspend:
   1234       State |= XHC_PORTSC_LWS;
   1235       XhcPeiWriteOpReg (Xhc, Offset, State);
   1236       State &= ~XHC_PORTSC_PLS;
   1237       State |= (3 << 5) ;
   1238       XhcPeiWriteOpReg (Xhc, Offset, State);
   1239       break;
   1240 
   1241     case EfiUsbPortReset:
   1242       //
   1243       // Make sure Host Controller not halt before reset it
   1244       //
   1245       if (XhcPeiIsHalt (Xhc)) {
   1246         Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);
   1247         if (EFI_ERROR (Status)) {
   1248           break;
   1249         }
   1250       }
   1251 
   1252       //
   1253       // 4.3.1 Resetting a Root Hub Port
   1254       // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
   1255       // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
   1256       //    bit in the PORTSC field is set to '1'.
   1257       //
   1258       State |= XHC_PORTSC_RESET;
   1259       XhcPeiWriteOpReg (Xhc, Offset, State);
   1260       XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
   1261       break;
   1262 
   1263     case EfiUsbPortPower:
   1264       if (Xhc->HcCParams.Data.Ppc) {
   1265         //
   1266         // Port Power Control supported
   1267         //
   1268         State |= XHC_PORTSC_PP;
   1269         XhcPeiWriteOpReg (Xhc, Offset, State);
   1270       }
   1271       break;
   1272 
   1273     case EfiUsbPortOwner:
   1274       //
   1275       // XHCI root hub port don't has the owner bit, ignore the operation
   1276       //
   1277       break;
   1278 
   1279     default:
   1280       Status = EFI_INVALID_PARAMETER;
   1281   }
   1282 
   1283 ON_EXIT:
   1284   DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
   1285   return Status;
   1286 }
   1287 
   1288 /**
   1289   Retrieves the current status of a USB root hub port.
   1290 
   1291   @param  PeiServices               The pointer of EFI_PEI_SERVICES.
   1292   @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
   1293   @param  PortNumber                The root hub port to retrieve the state from.
   1294   @param  PortStatus                Variable to receive the port state.
   1295 
   1296   @retval EFI_SUCCESS               The status of the USB root hub port specified.
   1297                                     by PortNumber was returned in PortStatus.
   1298   @retval EFI_INVALID_PARAMETER     PortNumber is invalid.
   1299 
   1300 **/
   1301 EFI_STATUS
   1302 EFIAPI
   1303 XhcPeiGetRootHubPortStatus (
   1304   IN EFI_PEI_SERVICES               **PeiServices,
   1305   IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
   1306   IN UINT8                          PortNumber,
   1307   OUT EFI_USB_PORT_STATUS           *PortStatus
   1308   )
   1309 {
   1310   PEI_XHC_DEV               *Xhc;
   1311   UINT32                    Offset;
   1312   UINT32                    State;
   1313   UINTN                     Index;
   1314   UINTN                     MapSize;
   1315   USB_DEV_ROUTE             ParentRouteChart;
   1316 
   1317   if (PortStatus == NULL) {
   1318     return EFI_INVALID_PARAMETER;
   1319   }
   1320 
   1321   Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
   1322 
   1323   if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
   1324     return EFI_INVALID_PARAMETER;
   1325   }
   1326 
   1327   //
   1328   // Clear port status.
   1329   //
   1330   PortStatus->PortStatus        = 0;
   1331   PortStatus->PortChangeStatus  = 0;
   1332 
   1333   Offset                        = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
   1334   State                         = XhcPeiReadOpReg (Xhc, Offset);
   1335   DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));
   1336 
   1337   //
   1338   // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.
   1339   //
   1340   switch ((State & XHC_PORTSC_PS) >> 10) {
   1341     case 2:
   1342       PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
   1343       break;
   1344 
   1345     case 3:
   1346       PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
   1347       break;
   1348 
   1349     case 4:
   1350       PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
   1351       break;
   1352 
   1353     default:
   1354       break;
   1355   }
   1356 
   1357   //
   1358   // Convert the XHCI port/port change state to UEFI status
   1359   //
   1360   MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
   1361 
   1362   for (Index = 0; Index < MapSize; Index++) {
   1363     if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
   1364       PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
   1365     }
   1366   }
   1367   //
   1368   // Bit5~8 reflects its current link state.
   1369   //
   1370   if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
   1371     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
   1372   }
   1373 
   1374   MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
   1375 
   1376   for (Index = 0; Index < MapSize; Index++) {
   1377     if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
   1378       PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
   1379     }
   1380   }
   1381 
   1382   MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
   1383 
   1384   for (Index = 0; Index < MapSize; Index++) {
   1385     if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
   1386       XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
   1387     }
   1388   }
   1389 
   1390   //
   1391   // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
   1392   // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
   1393   //
   1394   ParentRouteChart.Dword = 0;
   1395   XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
   1396 
   1397   DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));
   1398   return EFI_SUCCESS;
   1399 }
   1400 
   1401 /**
   1402   @param FileHandle     Handle of the file being invoked.
   1403   @param PeiServices    Describes the list of possible PEI Services.
   1404 
   1405   @retval EFI_SUCCESS   PPI successfully installed.
   1406 
   1407 **/
   1408 EFI_STATUS
   1409 EFIAPI
   1410 XhcPeimEntry (
   1411   IN EFI_PEI_FILE_HANDLE    FileHandle,
   1412   IN CONST EFI_PEI_SERVICES **PeiServices
   1413   )
   1414 {
   1415   PEI_USB_CONTROLLER_PPI      *UsbControllerPpi;
   1416   EFI_STATUS                  Status;
   1417   UINT8                       Index;
   1418   UINTN                       ControllerType;
   1419   UINTN                       BaseAddress;
   1420   UINTN                       MemPages;
   1421   PEI_XHC_DEV                 *XhcDev;
   1422   EFI_PHYSICAL_ADDRESS        TempPtr;
   1423   UINT32                      PageSize;
   1424 
   1425   //
   1426   // Shadow this PEIM to run from memory.
   1427   //
   1428   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
   1429     return EFI_SUCCESS;
   1430   }
   1431 
   1432   Status = PeiServicesLocatePpi (
   1433              &gPeiUsbControllerPpiGuid,
   1434              0,
   1435              NULL,
   1436              (VOID **) &UsbControllerPpi
   1437              );
   1438   if (EFI_ERROR (Status)) {
   1439     return EFI_UNSUPPORTED;
   1440   }
   1441 
   1442   Index = 0;
   1443   while (TRUE) {
   1444     Status = UsbControllerPpi->GetUsbController (
   1445                                  (EFI_PEI_SERVICES **) PeiServices,
   1446                                  UsbControllerPpi,
   1447                                  Index,
   1448                                  &ControllerType,
   1449                                  &BaseAddress
   1450                                  );
   1451     //
   1452     // When status is error, it means no controller is found.
   1453     //
   1454     if (EFI_ERROR (Status)) {
   1455       break;
   1456     }
   1457 
   1458     //
   1459     // This PEIM is for XHC type controller.
   1460     //
   1461     if (ControllerType != PEI_XHCI_CONTROLLER) {
   1462       Index++;
   1463       continue;
   1464     }
   1465 
   1466     MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));
   1467     Status = PeiServicesAllocatePages (
   1468                EfiBootServicesData,
   1469                MemPages,
   1470                &TempPtr
   1471                );
   1472     if (EFI_ERROR (Status)) {
   1473       return EFI_OUT_OF_RESOURCES;
   1474     }
   1475     ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));
   1476     XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);
   1477 
   1478     XhcDev->Signature = USB_XHC_DEV_SIGNATURE;
   1479     XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
   1480     XhcDev->CapLength           = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);
   1481     XhcDev->HcSParams1.Dword    = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);
   1482     XhcDev->HcSParams2.Dword    = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);
   1483     XhcDev->HcCParams.Dword     = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);
   1484     XhcDev->DBOff               = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);
   1485     XhcDev->RTSOff              = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);
   1486 
   1487     //
   1488     // This PageSize field defines the page size supported by the xHC implementation.
   1489     // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
   1490     // if bit 0 is Set, the xHC supports 4k byte page sizes.
   1491     //
   1492     PageSize         = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
   1493     XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
   1494 
   1495     DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));
   1496     DEBUG ((EFI_D_INFO, "XhciPei: CapLength:                    %x\n", XhcDev->CapLength));
   1497     DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1:                   %x\n", XhcDev->HcSParams1.Dword));
   1498     DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2:                   %x\n", XhcDev->HcSParams2.Dword));
   1499     DEBUG ((EFI_D_INFO, "XhciPei: HcCParams:                    %x\n", XhcDev->HcCParams.Dword));
   1500     DEBUG ((EFI_D_INFO, "XhciPei: DBOff:                        %x\n", XhcDev->DBOff));
   1501     DEBUG ((EFI_D_INFO, "XhciPei: RTSOff:                       %x\n", XhcDev->RTSOff));
   1502     DEBUG ((EFI_D_INFO, "XhciPei: PageSize:                     %x\n", XhcDev->PageSize));
   1503 
   1504     XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);
   1505     ASSERT (XhcPeiIsHalt (XhcDev));
   1506 
   1507     //
   1508     // Initialize the schedule
   1509     //
   1510     XhcPeiInitSched (XhcDev);
   1511 
   1512     //
   1513     // Start the Host Controller
   1514     //
   1515     XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);
   1516 
   1517     //
   1518     // Wait for root port state stable
   1519     //
   1520     MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);
   1521 
   1522     XhcDev->Usb2HostControllerPpi.ControlTransfer           = XhcPeiControlTransfer;
   1523     XhcDev->Usb2HostControllerPpi.BulkTransfer              = XhcPeiBulkTransfer;
   1524     XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber      = XhcPeiGetRootHubPortNumber;
   1525     XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus      = XhcPeiGetRootHubPortStatus;
   1526     XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature     = XhcPeiSetRootHubPortFeature;
   1527     XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature   = XhcPeiClearRootHubPortFeature;
   1528 
   1529     XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
   1530     XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
   1531     XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
   1532 
   1533     PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
   1534 
   1535     Index++;
   1536   }
   1537 
   1538   return EFI_SUCCESS;
   1539 }
   1540 
   1541