1 /** @file
2 Usb Hub Request Support In PEI Phase
3 
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution.  The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "UsbPeim.h"
18 #include "HubPeim.h"
19 #include "PeiUsbLib.h"
20 
21 /**
22   Get a given hub port status.
23 
24   @param  PeiServices   General-purpose services that are available to every PEIM.
25   @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
26   @param  Port          Usb hub port number (starting from 1).
27   @param  PortStatus    Current Hub port status and change status.
28 
29   @retval EFI_SUCCESS       Port status is obtained successfully.
30   @retval EFI_DEVICE_ERROR  Cannot get the port status due to a hardware error.
31   @retval Others            Other failure occurs.
32 
33 **/
34 EFI_STATUS
PeiHubGetPortStatus(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINT8 Port,OUT UINT32 * PortStatus)35 PeiHubGetPortStatus (
36   IN  EFI_PEI_SERVICES    **PeiServices,
37   IN  PEI_USB_IO_PPI      *UsbIoPpi,
38   IN  UINT8               Port,
39   OUT UINT32              *PortStatus
40   )
41 {
42   EFI_USB_DEVICE_REQUEST  DeviceRequest;
43 
44   ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
45 
46   //
47   // Fill Device request packet
48   //
49   DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;
50   DeviceRequest.Request     = USB_HUB_GET_PORT_STATUS;
51   DeviceRequest.Index       = Port;
52   DeviceRequest.Length      = (UINT16) sizeof (UINT32);
53 
54 
55   return UsbIoPpi->UsbControlTransfer (
56                      PeiServices,
57                      UsbIoPpi,
58                      &DeviceRequest,
59                      EfiUsbDataIn,
60                      PcdGet32 (PcdUsbTransferTimeoutValue),
61                      PortStatus,
62                      sizeof (UINT32)
63                      );
64 
65 }
66 
67 /**
68   Set specified feature to a given hub port.
69 
70   @param  PeiServices   General-purpose services that are available to every PEIM.
71   @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
72   @param  Port          Usb hub port number (starting from 1).
73   @param  Value         New feature value.
74 
75   @retval EFI_SUCCESS       Port feature is set successfully.
76   @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.
77   @retval Others            Other failure occurs.
78 
79 **/
80 EFI_STATUS
PeiHubSetPortFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINT8 Port,IN UINT8 Value)81 PeiHubSetPortFeature (
82   IN EFI_PEI_SERVICES    **PeiServices,
83   IN PEI_USB_IO_PPI      *UsbIoPpi,
84   IN UINT8               Port,
85   IN UINT8               Value
86   )
87 {
88   EFI_USB_DEVICE_REQUEST      DeviceRequest;
89 
90   ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
91 
92   //
93   // Fill Device request packet
94   //
95   DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;
96   DeviceRequest.Request     = USB_HUB_SET_PORT_FEATURE;
97   DeviceRequest.Value       = Value;
98   DeviceRequest.Index       = Port;
99 
100   return UsbIoPpi->UsbControlTransfer (
101                      PeiServices,
102                      UsbIoPpi,
103                      &DeviceRequest,
104                      EfiUsbNoData,
105                      PcdGet32 (PcdUsbTransferTimeoutValue),
106                      NULL,
107                      0
108                      );
109 }
110 
111 /**
112   Clear specified feature on a given hub port.
113 
114   @param  PeiServices   General-purpose services that are available to every PEIM.
115   @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
116   @param  Port          Usb hub port number (starting from 1).
117   @param  Value         Feature value that will be cleared from the hub port.
118 
119   @retval EFI_SUCCESS       Port feature is cleared successfully.
120   @retval EFI_DEVICE_ERROR  Cannot clear the port feature due to a hardware error.
121   @retval Others            Other failure occurs.
122 
123 **/
124 EFI_STATUS
PeiHubClearPortFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINT8 Port,IN UINT8 Value)125 PeiHubClearPortFeature (
126   IN EFI_PEI_SERVICES    **PeiServices,
127   IN PEI_USB_IO_PPI      *UsbIoPpi,
128   IN UINT8               Port,
129   IN UINT8               Value
130   )
131 {
132   EFI_USB_DEVICE_REQUEST      DeviceRequest;
133 
134   ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
135 
136   //
137   // Fill Device request packet
138   //
139   DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;
140   DeviceRequest.Request     = USB_HUB_CLEAR_FEATURE_PORT;
141   DeviceRequest.Value       = Value;
142   DeviceRequest.Index       = Port;
143 
144   return UsbIoPpi->UsbControlTransfer (
145                      PeiServices,
146                      UsbIoPpi,
147                      &DeviceRequest,
148                      EfiUsbNoData,
149                      PcdGet32 (PcdUsbTransferTimeoutValue),
150                      NULL,
151                      0
152                      );
153 }
154 
155 /**
156   Get a given hub status.
157 
158   @param  PeiServices   General-purpose services that are available to every PEIM.
159   @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
160   @param  HubStatus     Current Hub status and change status.
161 
162   @retval EFI_SUCCESS       Hub status is obtained successfully.
163   @retval EFI_DEVICE_ERROR  Cannot get the hub status due to a hardware error.
164   @retval Others            Other failure occurs.
165 
166 **/
167 EFI_STATUS
PeiHubGetHubStatus(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,OUT UINT32 * HubStatus)168 PeiHubGetHubStatus (
169   IN  EFI_PEI_SERVICES    **PeiServices,
170   IN  PEI_USB_IO_PPI      *UsbIoPpi,
171   OUT UINT32              *HubStatus
172   )
173 {
174   EFI_USB_DEVICE_REQUEST  DeviceRequest;
175 
176   ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
177 
178   //
179   // Fill Device request packet
180   //
181   DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;
182   DeviceRequest.Request     = USB_HUB_GET_HUB_STATUS;
183   DeviceRequest.Length      = (UINT16) sizeof (UINT32);
184 
185   return UsbIoPpi->UsbControlTransfer (
186                      PeiServices,
187                      UsbIoPpi,
188                      &DeviceRequest,
189                      EfiUsbDataIn,
190                      PcdGet32 (PcdUsbTransferTimeoutValue),
191                      HubStatus,
192                      sizeof (UINT32)
193                      );
194 }
195 
196 /**
197   Set specified feature to a given hub.
198 
199   @param  PeiServices   General-purpose services that are available to every PEIM.
200   @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
201   @param  Value         New feature value.
202 
203   @retval EFI_SUCCESS       Port feature is set successfully.
204   @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.
205   @retval Others            Other failure occurs.
206 
207 **/
208 EFI_STATUS
PeiHubSetHubFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINT8 Value)209 PeiHubSetHubFeature (
210   IN EFI_PEI_SERVICES    **PeiServices,
211   IN PEI_USB_IO_PPI      *UsbIoPpi,
212   IN UINT8               Value
213   )
214 {
215   EFI_USB_DEVICE_REQUEST      DeviceRequest;
216 
217   ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
218 
219   //
220   // Fill Device request packet
221   //
222   DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE;
223   DeviceRequest.Request     = USB_HUB_SET_HUB_FEATURE;
224   DeviceRequest.Value       = Value;
225 
226   return UsbIoPpi->UsbControlTransfer (
227                      PeiServices,
228                      UsbIoPpi,
229                      &DeviceRequest,
230                      EfiUsbNoData,
231                      PcdGet32 (PcdUsbTransferTimeoutValue),
232                      NULL,
233                      0
234                      );
235 }
236 
237 /**
238   Clear specified feature on a given hub.
239 
240   @param  PeiServices   General-purpose services that are available to every PEIM.
241   @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
242   @param  Value         Feature value that will be cleared from the hub port.
243 
244   @retval EFI_SUCCESS       Hub feature is cleared successfully.
245   @retval EFI_DEVICE_ERROR  Cannot clear the hub feature due to a hardware error.
246   @retval Others            Other failure occurs.
247 
248 **/
249 EFI_STATUS
PeiHubClearHubFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINT8 Value)250 PeiHubClearHubFeature (
251   IN EFI_PEI_SERVICES    **PeiServices,
252   IN PEI_USB_IO_PPI      *UsbIoPpi,
253   IN UINT8               Value
254   )
255 {
256   EFI_USB_DEVICE_REQUEST      DeviceRequest;
257 
258   ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
259 
260   //
261   // Fill Device request packet
262   //
263   DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;
264   DeviceRequest.Request     = USB_HUB_CLEAR_FEATURE;
265   DeviceRequest.Value       = Value;
266 
267   return  UsbIoPpi->UsbControlTransfer (
268                       PeiServices,
269                       UsbIoPpi,
270                       &DeviceRequest,
271                       EfiUsbNoData,
272                       PcdGet32 (PcdUsbTransferTimeoutValue),
273                       NULL,
274                       0
275                       );
276 }
277 
278 /**
279   Get a given hub descriptor.
280 
281   @param  PeiServices    General-purpose services that are available to every PEIM.
282   @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.
283   @param  DescriptorSize The length of Hub Descriptor buffer.
284   @param  HubDescriptor  Caller allocated buffer to store the hub descriptor if
285                          successfully returned.
286 
287   @retval EFI_SUCCESS       Hub descriptor is obtained successfully.
288   @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.
289   @retval Others            Other failure occurs.
290 
291 **/
292 EFI_STATUS
PeiGetHubDescriptor(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINTN DescriptorSize,OUT EFI_USB_HUB_DESCRIPTOR * HubDescriptor)293 PeiGetHubDescriptor (
294   IN  EFI_PEI_SERVICES          **PeiServices,
295   IN  PEI_USB_IO_PPI            *UsbIoPpi,
296   IN  UINTN                     DescriptorSize,
297   OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor
298   )
299 {
300   EFI_USB_DEVICE_REQUEST      DevReq;
301   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
302 
303   //
304   // Fill Device request packet
305   //
306   DevReq.RequestType = USB_RT_HUB | 0x80;
307   DevReq.Request     = USB_HUB_GET_DESCRIPTOR;
308   DevReq.Value       = USB_DT_HUB << 8;
309   DevReq.Length      = (UINT16)DescriptorSize;
310 
311   return  UsbIoPpi->UsbControlTransfer (
312                       PeiServices,
313                       UsbIoPpi,
314                       &DevReq,
315                       EfiUsbDataIn,
316                       PcdGet32 (PcdUsbTransferTimeoutValue),
317                       HubDescriptor,
318                       (UINT16)DescriptorSize
319                       );
320 }
321 
322 /**
323   Get a given SuperSpeed hub descriptor.
324 
325   @param  PeiServices       General-purpose services that are available to every PEIM.
326   @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.
327   @param  HubDescriptor     Caller allocated buffer to store the hub descriptor if
328                             successfully returned.
329 
330   @retval EFI_SUCCESS       Hub descriptor is obtained successfully.
331   @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.
332   @retval Others            Other failure occurs.
333 
334 **/
335 EFI_STATUS
PeiGetSuperSpeedHubDesc(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,OUT EFI_USB_HUB_DESCRIPTOR * HubDescriptor)336 PeiGetSuperSpeedHubDesc (
337   IN  EFI_PEI_SERVICES          **PeiServices,
338   IN  PEI_USB_IO_PPI            *UsbIoPpi,
339   OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor
340   )
341 {
342   EFI_USB_DEVICE_REQUEST        DevReq;
343   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
344 
345   //
346   // Fill Device request packet
347   //
348   DevReq.RequestType = USB_RT_HUB | 0x80;
349   DevReq.Request     = USB_HUB_GET_DESCRIPTOR;
350   DevReq.Value       = USB_DT_SUPERSPEED_HUB << 8;
351   DevReq.Length      = 12;
352 
353   return  UsbIoPpi->UsbControlTransfer (
354                       PeiServices,
355                       UsbIoPpi,
356                       &DevReq,
357                       EfiUsbDataIn,
358                       PcdGet32 (PcdUsbTransferTimeoutValue),
359                       HubDescriptor,
360                       12
361                       );
362 }
363 
364 /**
365   Read the whole usb hub descriptor. It is necessary
366   to do it in two steps because hub descriptor is of
367   variable length.
368 
369   @param  PeiServices       General-purpose services that are available to every PEIM.
370   @param  PeiUsbDevice      Indicates the hub controller device.
371   @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.
372   @param  HubDescriptor     Caller allocated buffer to store the hub descriptor if
373                             successfully returned.
374 
375   @retval EFI_SUCCESS       Hub descriptor is obtained successfully.
376   @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.
377   @retval Others            Other failure occurs.
378 
379 **/
380 EFI_STATUS
PeiUsbHubReadDesc(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_DEVICE * PeiUsbDevice,IN PEI_USB_IO_PPI * UsbIoPpi,OUT EFI_USB_HUB_DESCRIPTOR * HubDescriptor)381 PeiUsbHubReadDesc (
382   IN EFI_PEI_SERVICES           **PeiServices,
383   IN PEI_USB_DEVICE             *PeiUsbDevice,
384   IN PEI_USB_IO_PPI             *UsbIoPpi,
385   OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor
386   )
387 {
388   EFI_STATUS Status;
389 
390   if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
391     //
392     // Get the super speed hub descriptor
393     //
394     Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor);
395   } else {
396 
397     //
398     // First get the hub descriptor length
399     //
400     Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor);
401 
402     if (EFI_ERROR (Status)) {
403       return Status;
404     }
405 
406     //
407     // Get the whole hub descriptor
408     //
409     Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
410   }
411 
412   return Status;
413 }
414 
415 /**
416   USB hub control transfer to set the hub depth.
417 
418   @param  PeiServices       General-purpose services that are available to every PEIM.
419   @param  PeiUsbDevice      Indicates the hub controller device.
420   @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.
421 
422   @retval EFI_SUCCESS       Depth of the hub is set.
423   @retval Others            Failed to set the depth.
424 
425 **/
426 EFI_STATUS
PeiUsbHubCtrlSetHubDepth(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_DEVICE * PeiUsbDevice,IN PEI_USB_IO_PPI * UsbIoPpi)427 PeiUsbHubCtrlSetHubDepth (
428   IN EFI_PEI_SERVICES           **PeiServices,
429   IN PEI_USB_DEVICE             *PeiUsbDevice,
430   IN PEI_USB_IO_PPI             *UsbIoPpi
431   )
432 {
433   EFI_USB_DEVICE_REQUEST        DevReq;
434   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
435 
436   //
437   // Fill Device request packet
438   //
439   DevReq.RequestType = USB_RT_HUB;
440   DevReq.Request     = USB_HUB_REQ_SET_DEPTH;
441   DevReq.Value       = PeiUsbDevice->Tier;
442   DevReq.Length      = 0;
443 
444   return  UsbIoPpi->UsbControlTransfer (
445                       PeiServices,
446                       UsbIoPpi,
447                       &DevReq,
448                       EfiUsbNoData,
449                       PcdGet32 (PcdUsbTransferTimeoutValue),
450                       NULL,
451                       0
452                       );
453 }
454 
455 /**
456   Configure a given hub.
457 
458   @param  PeiServices    General-purpose services that are available to every PEIM.
459   @param  PeiUsbDevice   Indicating the hub controller device that will be configured
460 
461   @retval EFI_SUCCESS       Hub configuration is done successfully.
462   @retval EFI_DEVICE_ERROR  Cannot configure the hub due to a hardware error.
463 
464 **/
465 EFI_STATUS
PeiDoHubConfig(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_DEVICE * PeiUsbDevice)466 PeiDoHubConfig (
467   IN EFI_PEI_SERVICES    **PeiServices,
468   IN PEI_USB_DEVICE      *PeiUsbDevice
469   )
470 {
471   EFI_USB_HUB_DESCRIPTOR  HubDescriptor;
472   EFI_STATUS              Status;
473   EFI_USB_HUB_STATUS      HubStatus;
474   UINTN                   Index;
475   PEI_USB_IO_PPI          *UsbIoPpi;
476 
477   ZeroMem (&HubDescriptor, sizeof (HubDescriptor));
478   UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
479 
480   //
481   // Get the hub descriptor
482   //
483   Status = PeiUsbHubReadDesc (
484             PeiServices,
485             PeiUsbDevice,
486             UsbIoPpi,
487             &HubDescriptor
488             );
489   if (EFI_ERROR (Status)) {
490     return EFI_DEVICE_ERROR;
491   }
492 
493   PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;
494 
495   if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
496     DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
497     PeiUsbHubCtrlSetHubDepth (
498       PeiServices,
499       PeiUsbDevice,
500       UsbIoPpi
501       );
502   } else {
503     //
504     //  Power all the hub ports
505     //
506     for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
507       Status = PeiHubSetPortFeature (
508                 PeiServices,
509                 UsbIoPpi,
510                 (UINT8) (Index + 1),
511                 EfiUsbPortPower
512                 );
513       if (EFI_ERROR (Status)) {
514         DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
515         continue;
516       }
517     }
518 
519     DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor.PwrOn2PwrGood));
520     if (HubDescriptor.PwrOn2PwrGood > 0) {
521       MicroSecondDelay (HubDescriptor.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
522     }
523 
524     //
525     // Clear Hub Status Change
526     //
527     Status = PeiHubGetHubStatus (
528               PeiServices,
529               UsbIoPpi,
530               (UINT32 *) &HubStatus
531               );
532     if (EFI_ERROR (Status)) {
533       return EFI_DEVICE_ERROR;
534     } else {
535       //
536       // Hub power supply change happens
537       //
538       if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
539         PeiHubClearHubFeature (
540           PeiServices,
541           UsbIoPpi,
542           C_HUB_LOCAL_POWER
543           );
544       }
545       //
546       // Hub change overcurrent happens
547       //
548       if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
549         PeiHubClearHubFeature (
550           PeiServices,
551           UsbIoPpi,
552           C_HUB_OVER_CURRENT
553           );
554       }
555     }
556   }
557 
558   return EFI_SUCCESS;
559 }
560 
561 /**
562   Send reset signal over the given root hub port.
563 
564   @param  PeiServices    General-purpose services that are available to every PEIM.
565   @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.
566   @param  PortNum        Usb hub port number (starting from 1).
567 
568 **/
569 VOID
PeiResetHubPort(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_IO_PPI * UsbIoPpi,IN UINT8 PortNum)570 PeiResetHubPort (
571   IN EFI_PEI_SERVICES    **PeiServices,
572   IN PEI_USB_IO_PPI      *UsbIoPpi,
573   IN UINT8               PortNum
574   )
575 {
576   EFI_STATUS          Status;
577   UINTN               Index;
578   EFI_USB_PORT_STATUS HubPortStatus;
579 
580   MicroSecondDelay (100 * 1000);
581 
582   //
583   // reset root port
584   //
585   PeiHubSetPortFeature (
586     PeiServices,
587     UsbIoPpi,
588     PortNum,
589     EfiUsbPortReset
590     );
591 
592   //
593   // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
594   // section 7.1.7.5 for timing requirements.
595   //
596   MicroSecondDelay (USB_SET_PORT_RESET_STALL);
597 
598   //
599   // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
600   //
601   ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
602 
603   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
604     Status = PeiHubGetPortStatus (
605                PeiServices,
606                UsbIoPpi,
607                PortNum,
608                (UINT32 *) &HubPortStatus
609                );
610 
611     if (EFI_ERROR (Status)) {
612       return;
613     }
614 
615     if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
616       break;
617     }
618 
619     MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
620   }
621 
622   if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
623     DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
624     return;
625   }
626 
627   //
628   // clear reset change root port
629   //
630   PeiHubClearPortFeature (
631     PeiServices,
632     UsbIoPpi,
633     PortNum,
634     EfiUsbPortResetChange
635     );
636 
637   MicroSecondDelay (1 * 1000);
638 
639   PeiHubClearPortFeature (
640     PeiServices,
641     UsbIoPpi,
642     PortNum,
643     EfiUsbPortConnectChange
644     );
645 
646   //
647   // Set port enable
648   //
649   PeiHubSetPortFeature (
650     PeiServices,
651     UsbIoPpi,
652     PortNum,
653     EfiUsbPortEnable
654     );
655 
656   //
657   // Clear any change status
658   //
659 
660   PeiHubClearPortFeature (
661     PeiServices,
662     UsbIoPpi,
663     PortNum,
664     EfiUsbPortEnableChange
665     );
666 
667   MicroSecondDelay (10 * 1000);
668 
669   return;
670 }
671