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