1/** @file
2PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3which is used to enable recovery function from USB Drivers.
4
5Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
6
7This program and the accompanying materials
8are licensed and made available under the terms and conditions
9of the BSD License which accompanies this distribution.  The
10full text of the license may be found at
11http://opensource.org/licenses/bsd-license.php
12
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14WITHOUT 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//
24USB_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
32USB_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
39USB_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
46USB_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
54USB_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
61USB_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**/
78UINT32
79XhcPeiReadOpReg (
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**/
100VOID
101XhcPeiWriteOpReg (
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**/
120VOID
121XhcPeiSetOpRegBit (
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**/
142VOID
143XhcPeiClearOpRegBit (
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**/
170EFI_STATUS
171XhcPeiWaitOpRegBit (
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**/
201UINT32
202XhcPeiReadCapRegister (
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**/
223UINT32
224XhcPeiReadDoorBellReg (
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**/
246VOID
247XhcPeiWriteDoorBellReg (
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**/
267UINT32
268XhcPeiReadRuntimeReg (
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**/
290VOID
291XhcPeiWriteRuntimeReg (
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**/
310VOID
311XhcPeiSetRuntimeRegBit (
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**/
332VOID
333XhcPeiClearRuntimeRegBit (
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**/
355BOOLEAN
356XhcPeiIsHalt (
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**/
372BOOLEAN
373XhcPeiIsSysError (
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**/
390EFI_STATUS
391XhcPeiResetHC (
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  Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
411ON_EXIT:
412  DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));
413  return Status;
414}
415
416/**
417  Halt the host controller.
418
419  @param  Xhc           The XHCI device.
420  @param  Timeout       Time to wait before abort.
421
422  @retval EFI_TIMEOUT   Failed to halt the controller before Timeout.
423  @retval EFI_SUCCESS   The XHCI is halt.
424
425**/
426EFI_STATUS
427XhcPeiHaltHC (
428  IN PEI_XHC_DEV        *Xhc,
429  IN UINT32             Timeout
430  )
431{
432  EFI_STATUS            Status;
433
434  XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
435  Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
436  DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));
437  return Status;
438}
439
440/**
441  Set the XHCI to run.
442
443  @param  Xhc           The XHCI device.
444  @param  Timeout       Time to wait before abort.
445
446  @retval EFI_SUCCESS   The XHCI is running.
447  @retval Others        Failed to set the XHCI to run.
448
449**/
450EFI_STATUS
451XhcPeiRunHC (
452  IN PEI_XHC_DEV        *Xhc,
453  IN UINT32             Timeout
454  )
455{
456  EFI_STATUS            Status;
457
458  XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
459  Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
460  DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));
461  return Status;
462}
463
464/**
465  Submits control transfer to a target USB device.
466
467  @param  PeiServices               The pointer of EFI_PEI_SERVICES.
468  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
469  @param  DeviceAddress             The target device address.
470  @param  DeviceSpeed               Target device speed.
471  @param  MaximumPacketLength       Maximum packet size the default control transfer
472                                    endpoint is capable of sending or receiving.
473  @param  Request                   USB device request to send.
474  @param  TransferDirection         Specifies the data direction for the data stage.
475  @param  Data                      Data buffer to be transmitted or received from USB device.
476  @param  DataLength                The size (in bytes) of the data buffer.
477  @param  TimeOut                   Indicates the maximum timeout, in millisecond.
478                                    If Timeout is 0, then the caller must wait for the function
479                                    to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
480  @param  Translator                Transaction translator to be used by this device.
481  @param  TransferResult            Return the result of this control transfer.
482
483  @retval EFI_SUCCESS               Transfer was completed successfully.
484  @retval EFI_OUT_OF_RESOURCES      The transfer failed due to lack of resources.
485  @retval EFI_INVALID_PARAMETER     Some parameters are invalid.
486  @retval EFI_TIMEOUT               Transfer failed due to timeout.
487  @retval EFI_DEVICE_ERROR          Transfer failed due to host controller or device error.
488
489**/
490EFI_STATUS
491EFIAPI
492XhcPeiControlTransfer (
493  IN EFI_PEI_SERVICES                       **PeiServices,
494  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
495  IN UINT8                                  DeviceAddress,
496  IN UINT8                                  DeviceSpeed,
497  IN UINTN                                  MaximumPacketLength,
498  IN EFI_USB_DEVICE_REQUEST                 *Request,
499  IN EFI_USB_DATA_DIRECTION                 TransferDirection,
500  IN OUT VOID                               *Data,
501  IN OUT UINTN                              *DataLength,
502  IN UINTN                                  TimeOut,
503  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR     *Translator,
504  OUT UINT32                                *TransferResult
505  )
506{
507  PEI_XHC_DEV                   *Xhc;
508  URB                           *Urb;
509  UINT8                         Endpoint;
510  UINT8                         Index;
511  UINT8                         DescriptorType;
512  UINT8                         SlotId;
513  UINT8                         TTT;
514  UINT8                         MTT;
515  UINT32                        MaxPacket0;
516  EFI_USB_HUB_DESCRIPTOR        *HubDesc;
517  EFI_STATUS                    Status;
518  EFI_STATUS                    RecoveryStatus;
519  UINTN                         MapSize;
520  EFI_USB_PORT_STATUS           PortStatus;
521  UINT32                        State;
522  EFI_USB_DEVICE_REQUEST        ClearPortRequest;
523  UINTN                         Len;
524
525  //
526  // Validate parameters
527  //
528  if ((Request == NULL) || (TransferResult == NULL)) {
529    return EFI_INVALID_PARAMETER;
530  }
531
532  if ((TransferDirection != EfiUsbDataIn) &&
533      (TransferDirection != EfiUsbDataOut) &&
534      (TransferDirection != EfiUsbNoData)) {
535    return EFI_INVALID_PARAMETER;
536  }
537
538  if ((TransferDirection == EfiUsbNoData) &&
539      ((Data != NULL) || (*DataLength != 0))) {
540    return EFI_INVALID_PARAMETER;
541  }
542
543  if ((TransferDirection != EfiUsbNoData) &&
544     ((Data == NULL) || (*DataLength == 0))) {
545    return EFI_INVALID_PARAMETER;
546  }
547
548  if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&
549      (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
550      (MaximumPacketLength != 512)
551      ) {
552    return EFI_INVALID_PARAMETER;
553  }
554
555  if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
556    return EFI_INVALID_PARAMETER;
557  }
558
559  if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
560    return EFI_INVALID_PARAMETER;
561  }
562
563  Xhc             = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
564
565  Status          = EFI_DEVICE_ERROR;
566  *TransferResult = EFI_USB_ERR_SYSTEM;
567  Len             = 0;
568
569  if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
570    DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));
571    goto ON_EXIT;
572  }
573
574  //
575  // Check if the device is still enabled before every transaction.
576  //
577  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
578  if (SlotId == 0) {
579    goto ON_EXIT;
580  }
581
582  //
583  // Hook the Set_Address request from UsbBus.
584  // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
585  //
586  if ((Request->Request     == USB_REQ_SET_ADDRESS) &&
587      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
588    //
589    // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
590    // This way is used to clean the history to avoid using wrong device address afterwards.
591    //
592    for (Index = 0; Index < 255; Index++) {
593      if (!Xhc->UsbDevContext[Index + 1].Enabled &&
594          (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
595          (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {
596        Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
597      }
598    }
599
600    if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
601      goto ON_EXIT;
602    }
603    //
604    // The actual device address has been assigned by XHCI during initializing the device slot.
605    // So we just need establish the mapping relationship between the device address requested from UsbBus
606    // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface
607    // can find out the actual device address by it.
608    //
609    Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;
610    Status = EFI_SUCCESS;
611    goto ON_EXIT;
612  }
613
614  //
615  // Create a new URB, insert it into the asynchronous
616  // schedule list, then poll the execution status.
617  // Note that we encode the direction in address although default control
618  // endpoint is bidirectional. XhcPeiCreateUrb expects this
619  // combination of Ep addr and its direction.
620  //
621  Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
622  Urb = XhcPeiCreateUrb (
623          Xhc,
624          DeviceAddress,
625          Endpoint,
626          DeviceSpeed,
627          MaximumPacketLength,
628          XHC_CTRL_TRANSFER,
629          Request,
630          Data,
631          *DataLength,
632          NULL,
633          NULL
634          );
635
636  if (Urb == NULL) {
637    DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));
638    Status = EFI_OUT_OF_RESOURCES;
639    goto ON_EXIT;
640  }
641
642  Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
643
644  //
645  // Get the status from URB. The result is updated in XhcPeiCheckUrbResult
646  // which is called by XhcPeiExecTransfer
647  //
648  *TransferResult = Urb->Result;
649  *DataLength     = Urb->Completed;
650
651  if (Status == EFI_TIMEOUT) {
652    //
653    // The transfer timed out. Abort the transfer by dequeueing of the TD.
654    //
655    RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
656    if (EFI_ERROR(RecoveryStatus)) {
657      DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
658    }
659    goto FREE_URB;
660  } else {
661    if (*TransferResult == EFI_USB_NOERROR) {
662      Status = EFI_SUCCESS;
663    } else if (*TransferResult == EFI_USB_ERR_STALL) {
664      RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
665      if (EFI_ERROR (RecoveryStatus)) {
666        DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
667      }
668      Status = EFI_DEVICE_ERROR;
669      goto FREE_URB;
670    } else {
671      goto FREE_URB;
672    }
673  }
674
675  //
676  // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
677  // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
678  // Hook Set_Config request from UsbBus as we need configure device endpoint.
679  //
680  if ((Request->Request     == USB_REQ_GET_DESCRIPTOR) &&
681      ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
682      ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
683    DescriptorType = (UINT8) (Request->Value >> 8);
684    if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
685      ASSERT (Data != NULL);
686      //
687      // Store a copy of device scriptor as hub device need this info to configure endpoint.
688      //
689      CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
690      if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {
691        //
692        // If it's a usb3.0 device, then its max packet size is a 2^n.
693        //
694        MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
695      } else {
696        MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
697      }
698      Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
699      if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
700        Status = EFI_OUT_OF_RESOURCES;
701        goto FREE_URB;
702      }
703      if (Xhc->HcCParams.Data.Csz == 0) {
704        Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
705      } else {
706        Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);
707      }
708    } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
709      ASSERT (Data != NULL);
710      if (*DataLength == ((UINT16 *) Data)[1]) {
711        //
712        // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
713        //
714        Index = (UINT8) Request->Value;
715        ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
716        Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
717        if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
718          Status = EFI_OUT_OF_RESOURCES;
719          goto FREE_URB;
720        }
721        CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
722      }
723    } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
724               (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
725      ASSERT (Data != NULL);
726      HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;
727      ASSERT (HubDesc->NumPorts <= 15);
728      //
729      // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
730      //
731      TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
732      if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
733        //
734        // Don't support multi-TT feature for super speed hub now.
735        //
736        MTT = 0;
737        DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
738      } else {
739        MTT = 0;
740      }
741
742      if (Xhc->HcCParams.Data.Csz == 0) {
743        Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
744      } else {
745        Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
746      }
747    }
748  } else if ((Request->Request     == USB_REQ_SET_CONFIG) &&
749             (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
750    //
751    // Hook Set_Config request from UsbBus as we need configure device endpoint.
752    //
753    for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
754      if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
755        if (Xhc->HcCParams.Data.Csz == 0) {
756          Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
757        } else {
758          Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
759        }
760        break;
761      }
762    }
763  } else if ((Request->Request     == USB_REQ_GET_STATUS) &&
764             (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
765    ASSERT (Data != NULL);
766    //
767    // Hook Get_Status request from UsbBus to keep track of the port status change.
768    //
769    State                       = *(UINT32 *) Data;
770    PortStatus.PortStatus       = 0;
771    PortStatus.PortChangeStatus = 0;
772
773    if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
774      //
775      // For super speed hub, its bit10~12 presents the attached device speed.
776      //
777      if ((State & XHC_PORTSC_PS) >> 10 == 0) {
778        PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
779      }
780    } else {
781      //
782      // For high or full/low speed hub, its bit9~10 presents the attached device speed.
783      //
784      if (XHC_BIT_IS_SET (State, BIT9)) {
785        PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
786      } else if (XHC_BIT_IS_SET (State, BIT10)) {
787        PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
788      }
789    }
790
791    //
792    // Convert the XHCI port/port change state to UEFI status
793    //
794    MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
795    for (Index = 0; Index < MapSize; Index++) {
796      if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
797        PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
798      }
799    }
800
801    MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
802    for (Index = 0; Index < MapSize; Index++) {
803      if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
804        PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
805      }
806    }
807
808    MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
809
810    for (Index = 0; Index < MapSize; Index++) {
811      if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
812        ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
813        ClearPortRequest.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
814        ClearPortRequest.Request      = (UINT8) USB_REQ_CLEAR_FEATURE;
815        ClearPortRequest.Value        = mUsbHubClearPortChangeMap[Index].Selector;
816        ClearPortRequest.Index        = Request->Index;
817        ClearPortRequest.Length       = 0;
818
819        XhcPeiControlTransfer (
820          PeiServices,
821          This,
822          DeviceAddress,
823          DeviceSpeed,
824          MaximumPacketLength,
825          &ClearPortRequest,
826          EfiUsbNoData,
827          NULL,
828          &Len,
829          TimeOut,
830          Translator,
831          TransferResult
832          );
833      }
834    }
835
836    XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
837
838    *(UINT32 *) Data = *(UINT32 *) &PortStatus;
839  }
840
841FREE_URB:
842  XhcPeiFreeUrb (Xhc, Urb);
843
844ON_EXIT:
845
846  if (EFI_ERROR (Status)) {
847    DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
848  }
849
850  return Status;
851}
852
853/**
854  Submits bulk transfer to a bulk endpoint of a USB device.
855
856  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
857  @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
858  @param  DeviceAddress         Target device address.
859  @param  EndPointAddress       Endpoint number and its direction in bit 7.
860  @param  DeviceSpeed           Device speed, Low speed device doesn't support
861                                bulk transfer.
862  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
863                                sending or receiving.
864  @param  Data                  Array of pointers to the buffers of data to transmit
865                                from or receive into.
866  @param  DataLength            The lenght of the data buffer.
867  @param  DataToggle            On input, the initial data toggle for the transfer;
868                                On output, it is updated to to next data toggle to use of
869                                the subsequent bulk transfer.
870  @param  TimeOut               Indicates the maximum time, in millisecond, which the
871                                transfer is allowed to complete.
872                                If Timeout is 0, then the caller must wait for the function
873                                to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
874  @param  Translator            A pointr to the transaction translator data.
875  @param  TransferResult        A pointer to the detailed result information of the
876                                bulk transfer.
877
878  @retval EFI_SUCCESS           The transfer was completed successfully.
879  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
880  @retval EFI_INVALID_PARAMETER Parameters are invalid.
881  @retval EFI_TIMEOUT           The transfer failed due to timeout.
882  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
883
884**/
885EFI_STATUS
886EFIAPI
887XhcPeiBulkTransfer (
888  IN EFI_PEI_SERVICES                       **PeiServices,
889  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
890  IN UINT8                                  DeviceAddress,
891  IN UINT8                                  EndPointAddress,
892  IN UINT8                                  DeviceSpeed,
893  IN UINTN                                  MaximumPacketLength,
894  IN OUT VOID                               *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
895  IN OUT UINTN                              *DataLength,
896  IN OUT UINT8                              *DataToggle,
897  IN UINTN                                  TimeOut,
898  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR     *Translator,
899  OUT UINT32                                *TransferResult
900  )
901{
902  PEI_XHC_DEV                   *Xhc;
903  URB                           *Urb;
904  UINT8                         SlotId;
905  EFI_STATUS                    Status;
906  EFI_STATUS                    RecoveryStatus;
907
908  //
909  // Validate the parameters
910  //
911  if ((DataLength == NULL) || (*DataLength == 0) ||
912      (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
913    return EFI_INVALID_PARAMETER;
914  }
915
916  if ((*DataToggle != 0) && (*DataToggle != 1)) {
917    return EFI_INVALID_PARAMETER;
918  }
919
920  if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
921      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
922      ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||
923      ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {
924    return EFI_INVALID_PARAMETER;
925  }
926
927  Xhc             = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
928
929  *TransferResult = EFI_USB_ERR_SYSTEM;
930  Status          = EFI_DEVICE_ERROR;
931
932  if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
933    DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
934    goto ON_EXIT;
935  }
936
937  //
938  // Check if the device is still enabled before every transaction.
939  //
940  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
941  if (SlotId == 0) {
942    goto ON_EXIT;
943  }
944
945  //
946  // Create a new URB, insert it into the asynchronous
947  // schedule list, then poll the execution status.
948  //
949  Urb = XhcPeiCreateUrb (
950          Xhc,
951          DeviceAddress,
952          EndPointAddress,
953          DeviceSpeed,
954          MaximumPacketLength,
955          XHC_BULK_TRANSFER,
956          NULL,
957          Data[0],
958          *DataLength,
959          NULL,
960          NULL
961          );
962
963  if (Urb == NULL) {
964    DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));
965    Status = EFI_OUT_OF_RESOURCES;
966    goto ON_EXIT;
967  }
968
969  Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
970
971  *TransferResult = Urb->Result;
972  *DataLength     = Urb->Completed;
973
974  if (Status == EFI_TIMEOUT) {
975    //
976    // The transfer timed out. Abort the transfer by dequeueing of the TD.
977    //
978    RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
979    if (EFI_ERROR(RecoveryStatus)) {
980      DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
981    }
982  } else {
983    if (*TransferResult == EFI_USB_NOERROR) {
984      Status = EFI_SUCCESS;
985    } else if (*TransferResult == EFI_USB_ERR_STALL) {
986      RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
987      if (EFI_ERROR (RecoveryStatus)) {
988        DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
989      }
990      Status = EFI_DEVICE_ERROR;
991    }
992  }
993
994  XhcPeiFreeUrb (Xhc, Urb);
995
996ON_EXIT:
997
998  if (EFI_ERROR (Status)) {
999    DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1000  }
1001
1002  return Status;
1003}
1004
1005/**
1006  Retrieves the number of root hub ports.
1007
1008  @param[in]  PeiServices           The pointer to the PEI Services Table.
1009  @param[in]  This                  The pointer to this instance of the
1010                                    PEI_USB2_HOST_CONTROLLER_PPI.
1011  @param[out] PortNumber            The pointer to the number of the root hub ports.
1012
1013  @retval EFI_SUCCESS               The port number was retrieved successfully.
1014  @retval EFI_INVALID_PARAMETER     PortNumber is NULL.
1015
1016**/
1017EFI_STATUS
1018EFIAPI
1019XhcPeiGetRootHubPortNumber (
1020  IN EFI_PEI_SERVICES               **PeiServices,
1021  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
1022  OUT UINT8                         *PortNumber
1023  )
1024{
1025  PEI_XHC_DEV           *XhcDev;
1026  XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1027
1028  if (PortNumber == NULL) {
1029    return EFI_INVALID_PARAMETER;
1030  }
1031
1032  *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;
1033  DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));
1034  return EFI_SUCCESS;
1035}
1036
1037/**
1038  Clears a feature for the specified root hub port.
1039
1040  @param  PeiServices               The pointer of EFI_PEI_SERVICES.
1041  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1042  @param  PortNumber                Specifies the root hub port whose feature
1043                                    is requested to be cleared.
1044  @param  PortFeature               Indicates the feature selector associated with the
1045                                    feature clear request.
1046
1047  @retval EFI_SUCCESS               The feature specified by PortFeature was cleared
1048                                    for the USB root hub port specified by PortNumber.
1049  @retval EFI_INVALID_PARAMETER     PortNumber is invalid or PortFeature is invalid.
1050
1051**/
1052EFI_STATUS
1053EFIAPI
1054XhcPeiClearRootHubPortFeature (
1055  IN EFI_PEI_SERVICES               **PeiServices,
1056  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
1057  IN UINT8                          PortNumber,
1058  IN EFI_USB_PORT_FEATURE           PortFeature
1059  )
1060{
1061  PEI_XHC_DEV           *Xhc;
1062  UINT32                Offset;
1063  UINT32                State;
1064  EFI_STATUS            Status;
1065
1066  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1067  Status = EFI_SUCCESS;
1068
1069  if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1070    Status = EFI_INVALID_PARAMETER;
1071    goto ON_EXIT;
1072  }
1073
1074  Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1075  State = XhcPeiReadOpReg (Xhc, Offset);
1076  DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1077
1078  //
1079  // Mask off the port status change bits, these bits are
1080  // write clean bits
1081  //
1082  State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1083
1084  switch (PortFeature) {
1085    case EfiUsbPortEnable:
1086      //
1087      // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1088      // A port may be disabled by software writing a '1' to this flag.
1089      //
1090      State |= XHC_PORTSC_PED;
1091      State &= ~XHC_PORTSC_RESET;
1092      XhcPeiWriteOpReg (Xhc, Offset, State);
1093      break;
1094
1095    case EfiUsbPortSuspend:
1096      State |= XHC_PORTSC_LWS;
1097      XhcPeiWriteOpReg (Xhc, Offset, State);
1098      State &= ~XHC_PORTSC_PLS;
1099      XhcPeiWriteOpReg (Xhc, Offset, State);
1100      break;
1101
1102    case EfiUsbPortReset:
1103      //
1104      // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
1105      // Register bits indicate status when read, a clear bit may be set by
1106      // writing a '1'. Writing a '0' to RW1S bits has no effect.
1107      //
1108      break;
1109
1110    case EfiUsbPortPower:
1111      if (Xhc->HcCParams.Data.Ppc) {
1112        //
1113        // Port Power Control supported
1114        //
1115        State &= ~XHC_PORTSC_PP;
1116        XhcPeiWriteOpReg (Xhc, Offset, State);
1117      }
1118      break;
1119
1120    case EfiUsbPortOwner:
1121      //
1122      // XHCI root hub port don't has the owner bit, ignore the operation
1123      //
1124      break;
1125
1126    case EfiUsbPortConnectChange:
1127      //
1128      // Clear connect status change
1129      //
1130      State |= XHC_PORTSC_CSC;
1131      XhcPeiWriteOpReg (Xhc, Offset, State);
1132      break;
1133
1134    case EfiUsbPortEnableChange:
1135      //
1136      // Clear enable status change
1137      //
1138      State |= XHC_PORTSC_PEC;
1139      XhcPeiWriteOpReg (Xhc, Offset, State);
1140      break;
1141
1142    case EfiUsbPortOverCurrentChange:
1143      //
1144      // Clear PortOverCurrent change
1145      //
1146      State |= XHC_PORTSC_OCC;
1147      XhcPeiWriteOpReg (Xhc, Offset, State);
1148      break;
1149
1150    case EfiUsbPortResetChange:
1151      //
1152      // Clear Port Reset change
1153      //
1154      State |= XHC_PORTSC_PRC;
1155      XhcPeiWriteOpReg (Xhc, Offset, State);
1156      break;
1157
1158    case EfiUsbPortSuspendChange:
1159      //
1160      // Not supported or not related operation
1161      //
1162      break;
1163
1164    default:
1165      Status = EFI_INVALID_PARAMETER;
1166      break;
1167  }
1168
1169ON_EXIT:
1170  DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1171  return Status;
1172}
1173
1174/**
1175  Sets a feature for the specified root hub port.
1176
1177  @param  PeiServices               The pointer of EFI_PEI_SERVICES
1178  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI
1179  @param  PortNumber                Root hub port to set.
1180  @param  PortFeature               Feature to set.
1181
1182  @retval EFI_SUCCESS               The feature specified by PortFeature was set.
1183  @retval EFI_INVALID_PARAMETER     PortNumber is invalid or PortFeature is invalid.
1184  @retval EFI_TIMEOUT               The time out occurred.
1185
1186**/
1187EFI_STATUS
1188EFIAPI
1189XhcPeiSetRootHubPortFeature (
1190  IN EFI_PEI_SERVICES               **PeiServices,
1191  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
1192  IN UINT8                          PortNumber,
1193  IN EFI_USB_PORT_FEATURE           PortFeature
1194  )
1195{
1196  PEI_XHC_DEV           *Xhc;
1197  UINT32                Offset;
1198  UINT32                State;
1199  EFI_STATUS            Status;
1200
1201  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1202  Status = EFI_SUCCESS;
1203
1204  if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1205    Status = EFI_INVALID_PARAMETER;
1206    goto ON_EXIT;
1207  }
1208
1209  Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1210  State = XhcPeiReadOpReg (Xhc, Offset);
1211  DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
1212
1213  //
1214  // Mask off the port status change bits, these bits are
1215  // write clean bits
1216  //
1217  State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
1218
1219  switch (PortFeature) {
1220    case EfiUsbPortEnable:
1221      //
1222      // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1223      // A port may be disabled by software writing a '1' to this flag.
1224      //
1225      break;
1226
1227    case EfiUsbPortSuspend:
1228      State |= XHC_PORTSC_LWS;
1229      XhcPeiWriteOpReg (Xhc, Offset, State);
1230      State &= ~XHC_PORTSC_PLS;
1231      State |= (3 << 5) ;
1232      XhcPeiWriteOpReg (Xhc, Offset, State);
1233      break;
1234
1235    case EfiUsbPortReset:
1236      //
1237      // Make sure Host Controller not halt before reset it
1238      //
1239      if (XhcPeiIsHalt (Xhc)) {
1240        Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);
1241        if (EFI_ERROR (Status)) {
1242          break;
1243        }
1244      }
1245
1246      //
1247      // 4.3.1 Resetting a Root Hub Port
1248      // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
1249      // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
1250      //    bit in the PORTSC field is set to '1'.
1251      //
1252      State |= XHC_PORTSC_RESET;
1253      XhcPeiWriteOpReg (Xhc, Offset, State);
1254      XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
1255      break;
1256
1257    case EfiUsbPortPower:
1258      if (Xhc->HcCParams.Data.Ppc) {
1259        //
1260        // Port Power Control supported
1261        //
1262        State |= XHC_PORTSC_PP;
1263        XhcPeiWriteOpReg (Xhc, Offset, State);
1264      }
1265      break;
1266
1267    case EfiUsbPortOwner:
1268      //
1269      // XHCI root hub port don't has the owner bit, ignore the operation
1270      //
1271      break;
1272
1273    default:
1274      Status = EFI_INVALID_PARAMETER;
1275  }
1276
1277ON_EXIT:
1278  DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
1279  return Status;
1280}
1281
1282/**
1283  Retrieves the current status of a USB root hub port.
1284
1285  @param  PeiServices               The pointer of EFI_PEI_SERVICES.
1286  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1287  @param  PortNumber                The root hub port to retrieve the state from.
1288  @param  PortStatus                Variable to receive the port state.
1289
1290  @retval EFI_SUCCESS               The status of the USB root hub port specified.
1291                                    by PortNumber was returned in PortStatus.
1292  @retval EFI_INVALID_PARAMETER     PortNumber is invalid.
1293
1294**/
1295EFI_STATUS
1296EFIAPI
1297XhcPeiGetRootHubPortStatus (
1298  IN EFI_PEI_SERVICES               **PeiServices,
1299  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,
1300  IN UINT8                          PortNumber,
1301  OUT EFI_USB_PORT_STATUS           *PortStatus
1302  )
1303{
1304  PEI_XHC_DEV               *Xhc;
1305  UINT32                    Offset;
1306  UINT32                    State;
1307  UINTN                     Index;
1308  UINTN                     MapSize;
1309  USB_DEV_ROUTE             ParentRouteChart;
1310
1311  if (PortStatus == NULL) {
1312    return EFI_INVALID_PARAMETER;
1313  }
1314
1315  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
1316
1317  if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
1318    return EFI_INVALID_PARAMETER;
1319  }
1320
1321  //
1322  // Clear port status.
1323  //
1324  PortStatus->PortStatus        = 0;
1325  PortStatus->PortChangeStatus  = 0;
1326
1327  Offset                        = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
1328  State                         = XhcPeiReadOpReg (Xhc, Offset);
1329  DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));
1330
1331  //
1332  // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.
1333  //
1334  switch ((State & XHC_PORTSC_PS) >> 10) {
1335    case 2:
1336      PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
1337      break;
1338
1339    case 3:
1340      PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1341      break;
1342
1343    case 4:
1344      PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1345      break;
1346
1347    default:
1348      break;
1349  }
1350
1351  //
1352  // Convert the XHCI port/port change state to UEFI status
1353  //
1354  MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1355
1356  for (Index = 0; Index < MapSize; Index++) {
1357    if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
1358      PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
1359    }
1360  }
1361  //
1362  // Bit5~8 reflects its current link state.
1363  //
1364  if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
1365    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
1366  }
1367
1368  MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1369
1370  for (Index = 0; Index < MapSize; Index++) {
1371    if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
1372      PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
1373    }
1374  }
1375
1376  MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1377
1378  for (Index = 0; Index < MapSize; Index++) {
1379    if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
1380      XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
1381    }
1382  }
1383
1384  //
1385  // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
1386  // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
1387  //
1388  ParentRouteChart.Dword = 0;
1389  XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
1390
1391  DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));
1392  return EFI_SUCCESS;
1393}
1394
1395/**
1396  @param FileHandle     Handle of the file being invoked.
1397  @param PeiServices    Describes the list of possible PEI Services.
1398
1399  @retval EFI_SUCCESS   PPI successfully installed.
1400
1401**/
1402EFI_STATUS
1403EFIAPI
1404XhcPeimEntry (
1405  IN EFI_PEI_FILE_HANDLE    FileHandle,
1406  IN CONST EFI_PEI_SERVICES **PeiServices
1407  )
1408{
1409  PEI_USB_CONTROLLER_PPI      *UsbControllerPpi;
1410  EFI_STATUS                  Status;
1411  UINT8                       Index;
1412  UINTN                       ControllerType;
1413  UINTN                       BaseAddress;
1414  UINTN                       MemPages;
1415  PEI_XHC_DEV                 *XhcDev;
1416  EFI_PHYSICAL_ADDRESS        TempPtr;
1417  UINT32                      PageSize;
1418
1419  //
1420  // Shadow this PEIM to run from memory.
1421  //
1422  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1423    return EFI_SUCCESS;
1424  }
1425
1426  Status = PeiServicesLocatePpi (
1427             &gPeiUsbControllerPpiGuid,
1428             0,
1429             NULL,
1430             (VOID **) &UsbControllerPpi
1431             );
1432  if (EFI_ERROR (Status)) {
1433    return EFI_UNSUPPORTED;
1434  }
1435
1436  Index = 0;
1437  while (TRUE) {
1438    Status = UsbControllerPpi->GetUsbController (
1439                                 (EFI_PEI_SERVICES **) PeiServices,
1440                                 UsbControllerPpi,
1441                                 Index,
1442                                 &ControllerType,
1443                                 &BaseAddress
1444                                 );
1445    //
1446    // When status is error, it means no controller is found.
1447    //
1448    if (EFI_ERROR (Status)) {
1449      break;
1450    }
1451
1452    //
1453    // This PEIM is for XHC type controller.
1454    //
1455    if (ControllerType != PEI_XHCI_CONTROLLER) {
1456      Index++;
1457      continue;
1458    }
1459
1460    MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));
1461    Status = PeiServicesAllocatePages (
1462               EfiBootServicesData,
1463               MemPages,
1464               &TempPtr
1465               );
1466    if (EFI_ERROR (Status)) {
1467      return EFI_OUT_OF_RESOURCES;
1468    }
1469    ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));
1470    XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);
1471
1472    XhcDev->Signature = USB_XHC_DEV_SIGNATURE;
1473    XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1474    XhcDev->CapLength           = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);
1475    XhcDev->HcSParams1.Dword    = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);
1476    XhcDev->HcSParams2.Dword    = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);
1477    XhcDev->HcCParams.Dword     = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);
1478    XhcDev->DBOff               = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);
1479    XhcDev->RTSOff              = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);
1480
1481    //
1482    // This PageSize field defines the page size supported by the xHC implementation.
1483    // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1484    // if bit 0 is Set, the xHC supports 4k byte page sizes.
1485    //
1486    PageSize         = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
1487    XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
1488
1489    DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));
1490    DEBUG ((EFI_D_INFO, "XhciPei: CapLength:                    %x\n", XhcDev->CapLength));
1491    DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1:                   %x\n", XhcDev->HcSParams1.Dword));
1492    DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2:                   %x\n", XhcDev->HcSParams2.Dword));
1493    DEBUG ((EFI_D_INFO, "XhciPei: HcCParams:                    %x\n", XhcDev->HcCParams.Dword));
1494    DEBUG ((EFI_D_INFO, "XhciPei: DBOff:                        %x\n", XhcDev->DBOff));
1495    DEBUG ((EFI_D_INFO, "XhciPei: RTSOff:                       %x\n", XhcDev->RTSOff));
1496    DEBUG ((EFI_D_INFO, "XhciPei: PageSize:                     %x\n", XhcDev->PageSize));
1497
1498    XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);
1499    ASSERT (XhcPeiIsHalt (XhcDev));
1500
1501    //
1502    // Initialize the schedule
1503    //
1504    XhcPeiInitSched (XhcDev);
1505
1506    //
1507    // Start the Host Controller
1508    //
1509    XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);
1510
1511    //
1512    // Wait for root port state stable
1513    //
1514    MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);
1515
1516    XhcDev->Usb2HostControllerPpi.ControlTransfer           = XhcPeiControlTransfer;
1517    XhcDev->Usb2HostControllerPpi.BulkTransfer              = XhcPeiBulkTransfer;
1518    XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber      = XhcPeiGetRootHubPortNumber;
1519    XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus      = XhcPeiGetRootHubPortStatus;
1520    XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature     = XhcPeiSetRootHubPortFeature;
1521    XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature   = XhcPeiClearRootHubPortFeature;
1522
1523    XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1524    XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1525    XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
1526
1527    PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
1528
1529    Index++;
1530  }
1531
1532  return EFI_SUCCESS;
1533}
1534
1535