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