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