• 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   Create a command transfer TRB to support XHCI command interfaces.
22 
23   @param  Xhc       The XHCI device.
24   @param  CmdTrb    The cmd TRB to be executed.
25 
26   @return Created URB or NULL.
27 
28 **/
29 URB*
XhcPeiCreateCmdTrb(IN PEI_XHC_DEV * Xhc,IN TRB_TEMPLATE * CmdTrb)30 XhcPeiCreateCmdTrb (
31   IN PEI_XHC_DEV    *Xhc,
32   IN TRB_TEMPLATE   *CmdTrb
33   )
34 {
35   URB   *Urb;
36 
37   Urb = AllocateZeroPool (sizeof (URB));
38   if (Urb == NULL) {
39     return NULL;
40   }
41 
42   Urb->Signature  = XHC_URB_SIG;
43 
44   Urb->Ring       = &Xhc->CmdRing;
45   XhcPeiSyncTrsRing (Xhc, Urb->Ring);
46   Urb->TrbNum     = 1;
47   Urb->TrbStart   = Urb->Ring->RingEnqueue;
48   CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
49   Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
50   Urb->TrbEnd             = Urb->TrbStart;
51 
52   return Urb;
53 }
54 
55 /**
56   Execute a XHCI cmd TRB pointed by CmdTrb.
57 
58   @param  Xhc                   The XHCI device.
59   @param  CmdTrb                The cmd TRB to be executed.
60   @param  Timeout               Indicates the maximum time, in millisecond, which the
61                                 transfer is allowed to complete.
62   @param  EvtTrb                The event TRB corresponding to the cmd TRB.
63 
64   @retval EFI_SUCCESS           The transfer was completed successfully.
65   @retval EFI_INVALID_PARAMETER Some parameters are invalid.
66   @retval EFI_TIMEOUT           The transfer failed due to timeout.
67   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
68 
69 **/
70 EFI_STATUS
XhcPeiCmdTransfer(IN PEI_XHC_DEV * Xhc,IN TRB_TEMPLATE * CmdTrb,IN UINTN Timeout,OUT TRB_TEMPLATE ** EvtTrb)71 XhcPeiCmdTransfer (
72   IN PEI_XHC_DEV                *Xhc,
73   IN TRB_TEMPLATE               *CmdTrb,
74   IN UINTN                      Timeout,
75   OUT TRB_TEMPLATE              **EvtTrb
76   )
77 {
78   EFI_STATUS    Status;
79   URB           *Urb;
80 
81   //
82   // Validate the parameters
83   //
84   if ((Xhc == NULL) || (CmdTrb == NULL)) {
85     return EFI_INVALID_PARAMETER;
86   }
87 
88   Status = EFI_DEVICE_ERROR;
89 
90   if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
91     DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
92     goto ON_EXIT;
93   }
94 
95   //
96   // Create a new URB, then poll the execution status.
97   //
98   Urb = XhcPeiCreateCmdTrb (Xhc, CmdTrb);
99   if (Urb == NULL) {
100     DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));
101     Status = EFI_OUT_OF_RESOURCES;
102     goto ON_EXIT;
103   }
104 
105   Status  = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);
106   *EvtTrb = Urb->EvtTrb;
107 
108   if (Urb->Result == EFI_USB_NOERROR) {
109     Status = EFI_SUCCESS;
110   }
111 
112   XhcPeiFreeUrb (Xhc, Urb);
113 
114 ON_EXIT:
115   return Status;
116 }
117 
118 /**
119   Create a new URB for a new transaction.
120 
121   @param  Xhc       The XHCI device
122   @param  BusAddr   The logical device address assigned by UsbBus driver
123   @param  EpAddr    Endpoint addrress
124   @param  DevSpeed  The device speed
125   @param  MaxPacket The max packet length of the endpoint
126   @param  Type      The transaction type
127   @param  Request   The standard USB request for control transfer
128   @param  Data      The user data to transfer
129   @param  DataLen   The length of data buffer
130   @param  Callback  The function to call when data is transferred
131   @param  Context   The context to the callback
132 
133   @return Created URB or NULL
134 
135 **/
136 URB*
XhcPeiCreateUrb(IN PEI_XHC_DEV * Xhc,IN UINT8 BusAddr,IN UINT8 EpAddr,IN UINT8 DevSpeed,IN UINTN MaxPacket,IN UINTN Type,IN EFI_USB_DEVICE_REQUEST * Request,IN VOID * Data,IN UINTN DataLen,IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,IN VOID * Context)137 XhcPeiCreateUrb (
138   IN PEI_XHC_DEV                        *Xhc,
139   IN UINT8                              BusAddr,
140   IN UINT8                              EpAddr,
141   IN UINT8                              DevSpeed,
142   IN UINTN                              MaxPacket,
143   IN UINTN                              Type,
144   IN EFI_USB_DEVICE_REQUEST             *Request,
145   IN VOID                               *Data,
146   IN UINTN                              DataLen,
147   IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
148   IN VOID                               *Context
149   )
150 {
151   USB_ENDPOINT      *Ep;
152   EFI_STATUS        Status;
153   URB               *Urb;
154 
155   Urb = AllocateZeroPool (sizeof (URB));
156   if (Urb == NULL) {
157     return NULL;
158   }
159 
160   Urb->Signature = XHC_URB_SIG;
161 
162   Ep            = &Urb->Ep;
163   Ep->BusAddr   = BusAddr;
164   Ep->EpAddr    = (UINT8) (EpAddr & 0x0F);
165   Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
166   Ep->DevSpeed  = DevSpeed;
167   Ep->MaxPacket = MaxPacket;
168   Ep->Type      = Type;
169 
170   Urb->Request  = Request;
171   Urb->Data     = Data;
172   Urb->DataLen  = DataLen;
173   Urb->Callback = Callback;
174   Urb->Context  = Context;
175 
176   Status = XhcPeiCreateTransferTrb (Xhc, Urb);
177   if (EFI_ERROR (Status)) {
178     DEBUG ((EFI_D_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));
179     FreePool (Urb);
180     Urb = NULL;
181   }
182 
183   return Urb;
184 }
185 
186 /**
187   Free an allocated URB.
188 
189   @param  Xhc       The XHCI device.
190   @param  Urb       The URB to free.
191 
192 **/
193 VOID
XhcPeiFreeUrb(IN PEI_XHC_DEV * Xhc,IN URB * Urb)194 XhcPeiFreeUrb (
195   IN PEI_XHC_DEV    *Xhc,
196   IN URB            *Urb
197   )
198 {
199   if ((Xhc == NULL) || (Urb == NULL)) {
200     return;
201   }
202 
203   FreePool (Urb);
204 }
205 
206 /**
207   Create a transfer TRB.
208 
209   @param  Xhc       The XHCI device
210   @param  Urb       The urb used to construct the transfer TRB.
211 
212   @return Created TRB or NULL
213 
214 **/
215 EFI_STATUS
XhcPeiCreateTransferTrb(IN PEI_XHC_DEV * Xhc,IN URB * Urb)216 XhcPeiCreateTransferTrb (
217   IN PEI_XHC_DEV    *Xhc,
218   IN URB            *Urb
219   )
220 {
221   VOID                          *OutputContext;
222   TRANSFER_RING                 *EPRing;
223   UINT8                         EPType;
224   UINT8                         SlotId;
225   UINT8                         Dci;
226   TRB                           *TrbStart;
227   UINTN                         TotalLen;
228   UINTN                         Len;
229   UINTN                         TrbNum;
230 
231   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
232   if (SlotId == 0) {
233     return EFI_DEVICE_ERROR;
234   }
235 
236   Urb->Finished  = FALSE;
237   Urb->StartDone = FALSE;
238   Urb->EndDone   = FALSE;
239   Urb->Completed = 0;
240   Urb->Result    = EFI_USB_NOERROR;
241 
242   Dci       = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
243   EPRing    = (TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
244   Urb->Ring = EPRing;
245   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
246   if (Xhc->HcCParams.Data.Csz == 0) {
247     EPType  = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
248   } else {
249     EPType  = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
250   }
251 
252   Urb->DataPhy = Urb->Data;
253 
254   //
255   // Construct the TRB
256   //
257   XhcPeiSyncTrsRing (Xhc, EPRing);
258   Urb->TrbStart = EPRing->RingEnqueue;
259   switch (EPType) {
260     case ED_CONTROL_BIDIR:
261       //
262       // For control transfer, create SETUP_STAGE_TRB first.
263       //
264       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
265       TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
266       TrbStart->TrbCtrSetup.bRequest      = Urb->Request->Request;
267       TrbStart->TrbCtrSetup.wValue        = Urb->Request->Value;
268       TrbStart->TrbCtrSetup.wIndex        = Urb->Request->Index;
269       TrbStart->TrbCtrSetup.wLength       = Urb->Request->Length;
270       TrbStart->TrbCtrSetup.Length        = 8;
271       TrbStart->TrbCtrSetup.IntTarget     = 0;
272       TrbStart->TrbCtrSetup.IOC           = 1;
273       TrbStart->TrbCtrSetup.IDT           = 1;
274       TrbStart->TrbCtrSetup.Type          = TRB_TYPE_SETUP_STAGE;
275       if (Urb->Ep.Direction == EfiUsbDataIn) {
276         TrbStart->TrbCtrSetup.TRT = 3;
277       } else if (Urb->Ep.Direction == EfiUsbDataOut) {
278         TrbStart->TrbCtrSetup.TRT = 2;
279       } else {
280         TrbStart->TrbCtrSetup.TRT = 0;
281       }
282       //
283       // Update the cycle bit
284       //
285       TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
286       Urb->TrbNum++;
287 
288       //
289       // For control transfer, create DATA_STAGE_TRB.
290       //
291       if (Urb->DataLen > 0) {
292         XhcPeiSyncTrsRing (Xhc, EPRing);
293         TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
294         TrbStart->TrbCtrData.TRBPtrLo  = XHC_LOW_32BIT (Urb->DataPhy);
295         TrbStart->TrbCtrData.TRBPtrHi  = XHC_HIGH_32BIT (Urb->DataPhy);
296         TrbStart->TrbCtrData.Length    = (UINT32) Urb->DataLen;
297         TrbStart->TrbCtrData.TDSize    = 0;
298         TrbStart->TrbCtrData.IntTarget = 0;
299         TrbStart->TrbCtrData.ISP       = 1;
300         TrbStart->TrbCtrData.IOC       = 1;
301         TrbStart->TrbCtrData.IDT       = 0;
302         TrbStart->TrbCtrData.CH        = 0;
303         TrbStart->TrbCtrData.Type      = TRB_TYPE_DATA_STAGE;
304         if (Urb->Ep.Direction == EfiUsbDataIn) {
305           TrbStart->TrbCtrData.DIR = 1;
306         } else if (Urb->Ep.Direction == EfiUsbDataOut) {
307           TrbStart->TrbCtrData.DIR = 0;
308         } else {
309           TrbStart->TrbCtrData.DIR = 0;
310         }
311         //
312         // Update the cycle bit
313         //
314         TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
315         Urb->TrbNum++;
316       }
317       //
318       // For control transfer, create STATUS_STAGE_TRB.
319       // Get the pointer to next TRB for status stage use
320       //
321       XhcPeiSyncTrsRing (Xhc, EPRing);
322       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
323       TrbStart->TrbCtrStatus.IntTarget = 0;
324       TrbStart->TrbCtrStatus.IOC       = 1;
325       TrbStart->TrbCtrStatus.CH        = 0;
326       TrbStart->TrbCtrStatus.Type      = TRB_TYPE_STATUS_STAGE;
327       if (Urb->Ep.Direction == EfiUsbDataIn) {
328         TrbStart->TrbCtrStatus.DIR = 0;
329       } else if (Urb->Ep.Direction == EfiUsbDataOut) {
330         TrbStart->TrbCtrStatus.DIR = 1;
331       } else {
332         TrbStart->TrbCtrStatus.DIR = 0;
333       }
334       //
335       // Update the cycle bit
336       //
337       TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
338       //
339       // Update the enqueue pointer
340       //
341       XhcPeiSyncTrsRing (Xhc, EPRing);
342       Urb->TrbNum++;
343       Urb->TrbEnd = (TRB_TEMPLATE *) (UINTN) TrbStart;
344 
345       break;
346 
347     case ED_BULK_OUT:
348     case ED_BULK_IN:
349       TotalLen = 0;
350       Len      = 0;
351       TrbNum   = 0;
352       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
353       while (TotalLen < Urb->DataLen) {
354         if ((TotalLen + 0x10000) >= Urb->DataLen) {
355           Len = Urb->DataLen - TotalLen;
356         } else {
357           Len = 0x10000;
358         }
359         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
360         TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
361         TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
362         TrbStart->TrbNormal.Length    = (UINT32) Len;
363         TrbStart->TrbNormal.TDSize    = 0;
364         TrbStart->TrbNormal.IntTarget = 0;
365         TrbStart->TrbNormal.ISP       = 1;
366         TrbStart->TrbNormal.IOC       = 1;
367         TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;
368         //
369         // Update the cycle bit
370         //
371         TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
372 
373         XhcPeiSyncTrsRing (Xhc, EPRing);
374         TrbNum++;
375         TotalLen += Len;
376       }
377 
378       Urb->TrbNum = TrbNum;
379       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
380       break;
381 
382     case ED_INTERRUPT_OUT:
383     case ED_INTERRUPT_IN:
384       TotalLen = 0;
385       Len      = 0;
386       TrbNum   = 0;
387       TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
388       while (TotalLen < Urb->DataLen) {
389         if ((TotalLen + 0x10000) >= Urb->DataLen) {
390           Len = Urb->DataLen - TotalLen;
391         } else {
392           Len = 0x10000;
393         }
394         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
395         TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
396         TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
397         TrbStart->TrbNormal.Length    = (UINT32) Len;
398         TrbStart->TrbNormal.TDSize    = 0;
399         TrbStart->TrbNormal.IntTarget = 0;
400         TrbStart->TrbNormal.ISP       = 1;
401         TrbStart->TrbNormal.IOC       = 1;
402         TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;
403         //
404         // Update the cycle bit
405         //
406         TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
407 
408         XhcPeiSyncTrsRing (Xhc, EPRing);
409         TrbNum++;
410         TotalLen += Len;
411       }
412 
413       Urb->TrbNum = TrbNum;
414       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
415       break;
416 
417     default:
418       DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
419       ASSERT (FALSE);
420       break;
421   }
422 
423   return EFI_SUCCESS;
424 }
425 
426 /**
427   System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
428   condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
429   Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
430   reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
431   Stopped to the Running state.
432 
433   @param  Xhc           The XHCI device.
434   @param  Urb           The urb which makes the endpoint halted.
435 
436   @retval EFI_SUCCESS   The recovery is successful.
437   @retval Others        Failed to recovery halted endpoint.
438 
439 **/
440 EFI_STATUS
XhcPeiRecoverHaltedEndpoint(IN PEI_XHC_DEV * Xhc,IN URB * Urb)441 XhcPeiRecoverHaltedEndpoint (
442   IN PEI_XHC_DEV        *Xhc,
443   IN URB                *Urb
444   )
445 {
446   EFI_STATUS                  Status;
447   UINT8                       Dci;
448   UINT8                       SlotId;
449 
450   Status = EFI_SUCCESS;
451   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
452   if (SlotId == 0) {
453     return EFI_DEVICE_ERROR;
454   }
455   Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));
456 
457   DEBUG ((EFI_D_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));
458 
459   //
460   // 1) Send Reset endpoint command to transit from halt to stop state
461   //
462   Status = XhcPeiResetEndpoint (Xhc, SlotId, Dci);
463   if (EFI_ERROR(Status)) {
464     DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
465     goto Done;
466   }
467 
468   //
469   // 2) Set dequeue pointer
470   //
471   Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
472   if (EFI_ERROR(Status)) {
473     DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
474     goto Done;
475   }
476 
477   //
478   // 3) Ring the doorbell to transit from stop to active
479   //
480   XhcPeiRingDoorBell (Xhc, SlotId, Dci);
481 
482 Done:
483   return Status;
484 }
485 
486 /**
487   System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
488   Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
489   the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
490   state.
491 
492   @param  Xhc                   The XHCI device.
493   @param  Urb                   The urb which doesn't get completed in a specified timeout range.
494 
495   @retval EFI_SUCCESS           The dequeuing of the TDs is successful.
496   @retval Others                Failed to stop the endpoint and dequeue the TDs.
497 
498 **/
499 EFI_STATUS
XhcPeiDequeueTrbFromEndpoint(IN PEI_XHC_DEV * Xhc,IN URB * Urb)500 XhcPeiDequeueTrbFromEndpoint (
501   IN PEI_XHC_DEV        *Xhc,
502   IN URB                *Urb
503   )
504 {
505   EFI_STATUS                  Status;
506   UINT8                       Dci;
507   UINT8                       SlotId;
508 
509   Status = EFI_SUCCESS;
510   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
511   if (SlotId == 0) {
512     return EFI_DEVICE_ERROR;
513   }
514   Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));
515 
516   DEBUG ((EFI_D_INFO, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId, Dci));
517 
518   //
519   // 1) Send Stop endpoint command to stop endpoint.
520   //
521   Status = XhcPeiStopEndpoint (Xhc, SlotId, Dci);
522   if (EFI_ERROR(Status)) {
523     DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
524     goto Done;
525   }
526 
527   //
528   // 2) Set dequeue pointer
529   //
530   Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
531   if (EFI_ERROR(Status)) {
532     DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
533     goto Done;
534   }
535 
536   //
537   // 3) Ring the doorbell to transit from stop to active
538   //
539   XhcPeiRingDoorBell (Xhc, SlotId, Dci);
540 
541 Done:
542   return Status;
543 }
544 
545 /**
546   Check if the Trb is a transaction of the URB.
547 
548   @param Trb        The TRB to be checked
549   @param Urb        The transfer ring to be checked.
550 
551   @retval TRUE      It is a transaction of the URB.
552   @retval FALSE     It is not any transaction of the URB.
553 
554 **/
555 BOOLEAN
XhcPeiIsTransferRingTrb(IN TRB_TEMPLATE * Trb,IN URB * Urb)556 XhcPeiIsTransferRingTrb (
557   IN TRB_TEMPLATE   *Trb,
558   IN URB            *Urb
559   )
560 {
561   TRB_TEMPLATE  *CheckedTrb;
562   UINTN         Index;
563 
564   CheckedTrb = Urb->Ring->RingSeg0;
565 
566   ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
567 
568   for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
569     if (Trb == CheckedTrb) {
570       return TRUE;
571     }
572     CheckedTrb++;
573   }
574 
575   return FALSE;
576 }
577 
578 /**
579   Check the URB's execution result and update the URB's
580   result accordingly.
581 
582   @param  Xhc               The XHCI device.
583   @param  Urb               The URB to check result.
584 
585   @return Whether the result of URB transfer is finialized.
586 
587 **/
588 BOOLEAN
XhcPeiCheckUrbResult(IN PEI_XHC_DEV * Xhc,IN URB * Urb)589 XhcPeiCheckUrbResult (
590   IN PEI_XHC_DEV            *Xhc,
591   IN URB                    *Urb
592   )
593 {
594   EVT_TRB_TRANSFER          *EvtTrb;
595   TRB_TEMPLATE              *TRBPtr;
596   UINTN                     Index;
597   UINT8                     TRBType;
598   EFI_STATUS                Status;
599   URB                       *CheckedUrb;
600   UINT64                    XhcDequeue;
601   UINT32                    High;
602   UINT32                    Low;
603   EFI_PHYSICAL_ADDRESS      PhyAddr;
604 
605   ASSERT ((Xhc != NULL) && (Urb != NULL));
606 
607   Status = EFI_SUCCESS;
608 
609   if (Urb->Finished) {
610     goto EXIT;
611   }
612 
613   EvtTrb = NULL;
614 
615   if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
616     Urb->Result |= EFI_USB_ERR_SYSTEM;
617     goto EXIT;
618   }
619 
620   //
621   // Traverse the event ring to find out all new events from the previous check.
622   //
623   XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);
624   for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
625     Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **) &EvtTrb));
626     if (Status == EFI_NOT_READY) {
627       //
628       // All new events are handled, return directly.
629       //
630       goto EXIT;
631     }
632 
633     //
634     // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
635     //
636     if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
637       continue;
638     }
639 
640     //
641     // Need convert pci device address to host address
642     //
643     PhyAddr = (EFI_PHYSICAL_ADDRESS) (EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
644     TRBPtr = (TRB_TEMPLATE *) (UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *) (UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
645 
646     //
647     // Update the status of Urb according to the finished event regardless of whether
648     // the urb is current checked one or in the XHCI's async transfer list.
649     // This way is used to avoid that those completed async transfer events don't get
650     // handled in time and are flushed by newer coming events.
651     //
652     if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {
653       CheckedUrb = Urb;
654     } else {
655       continue;
656     }
657 
658     switch (EvtTrb->Completecode) {
659       case TRB_COMPLETION_STALL_ERROR:
660         CheckedUrb->Result  |= EFI_USB_ERR_STALL;
661         CheckedUrb->Finished = TRUE;
662         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));
663         goto EXIT;
664 
665       case TRB_COMPLETION_BABBLE_ERROR:
666         CheckedUrb->Result  |= EFI_USB_ERR_BABBLE;
667         CheckedUrb->Finished = TRUE;
668         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));
669         goto EXIT;
670 
671       case TRB_COMPLETION_DATA_BUFFER_ERROR:
672         CheckedUrb->Result  |= EFI_USB_ERR_BUFFER;
673         CheckedUrb->Finished = TRUE;
674         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));
675         goto EXIT;
676 
677       case TRB_COMPLETION_USB_TRANSACTION_ERROR:
678         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
679         CheckedUrb->Finished = TRUE;
680         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));
681         goto EXIT;
682 
683       case TRB_COMPLETION_SHORT_PACKET:
684       case TRB_COMPLETION_SUCCESS:
685         if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
686           DEBUG ((EFI_D_VERBOSE, "XhcPeiCheckUrbResult: short packet happens!\n"));
687         }
688 
689         TRBType = (UINT8) (TRBPtr->Type);
690         if ((TRBType == TRB_TYPE_DATA_STAGE) ||
691             (TRBType == TRB_TYPE_NORMAL) ||
692             (TRBType == TRB_TYPE_ISOCH)) {
693           CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
694         }
695 
696         break;
697 
698       default:
699         DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));
700         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
701         CheckedUrb->Finished = TRUE;
702         goto EXIT;
703     }
704 
705     //
706     // Only check first and end Trb event address
707     //
708     if (TRBPtr == CheckedUrb->TrbStart) {
709       CheckedUrb->StartDone = TRUE;
710     }
711 
712     if (TRBPtr == CheckedUrb->TrbEnd) {
713       CheckedUrb->EndDone = TRUE;
714     }
715 
716     if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
717       CheckedUrb->Finished = TRUE;
718       CheckedUrb->EvtTrb   = (TRB_TEMPLATE *) EvtTrb;
719     }
720   }
721 
722 EXIT:
723 
724   //
725   // Advance event ring to last available entry
726   //
727   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
728   // So divide it to two 32-bytes width register access.
729   //
730   Low  = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
731   High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
732   XhcDequeue = (UINT64) (LShiftU64((UINT64) High, 32) | Low);
733 
734   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
735 
736   if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
737     //
738     // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
739     // So divide it to two 32-bytes width register access.
740     //
741     XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
742     XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
743   }
744 
745   return Urb->Finished;
746 }
747 
748 /**
749   Execute the transfer by polling the URB. This is a synchronous operation.
750 
751   @param  Xhc               The XHCI device.
752   @param  CmdTransfer       The executed URB is for cmd transfer or not.
753   @param  Urb               The URB to execute.
754   @param  Timeout           The time to wait before abort, in millisecond.
755 
756   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
757   @return EFI_TIMEOUT       The transfer failed due to time out.
758   @return EFI_SUCCESS       The transfer finished OK.
759 
760 **/
761 EFI_STATUS
XhcPeiExecTransfer(IN PEI_XHC_DEV * Xhc,IN BOOLEAN CmdTransfer,IN URB * Urb,IN UINTN Timeout)762 XhcPeiExecTransfer (
763   IN PEI_XHC_DEV            *Xhc,
764   IN BOOLEAN                CmdTransfer,
765   IN URB                    *Urb,
766   IN UINTN                  Timeout
767   )
768 {
769   EFI_STATUS    Status;
770   UINTN         Index;
771   UINT64        Loop;
772   UINT8         SlotId;
773   UINT8         Dci;
774   BOOLEAN       Finished;
775 
776   if (CmdTransfer) {
777     SlotId = 0;
778     Dci    = 0;
779   } else {
780     SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
781     if (SlotId == 0) {
782       return EFI_DEVICE_ERROR;
783     }
784     Dci  = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
785   }
786 
787   Status = EFI_SUCCESS;
788   Loop   = Timeout * XHC_1_MILLISECOND;
789   if (Timeout == 0) {
790     Loop = 0xFFFFFFFF;
791   }
792 
793   XhcPeiRingDoorBell (Xhc, SlotId, Dci);
794 
795   for (Index = 0; Index < Loop; Index++) {
796     Finished = XhcPeiCheckUrbResult (Xhc, Urb);
797     if (Finished) {
798       break;
799     }
800     MicroSecondDelay (XHC_1_MICROSECOND);
801   }
802 
803   if (Index == Loop) {
804     Urb->Result = EFI_USB_ERR_TIMEOUT;
805     Status      = EFI_TIMEOUT;
806   } else if (Urb->Result != EFI_USB_NOERROR) {
807     Status      = EFI_DEVICE_ERROR;
808   }
809 
810   return Status;
811 }
812 
813 /**
814   Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
815 
816   @param  Xhc               The XHCI device.
817   @param  ParentRouteChart  The route string pointed to the parent device if it exists.
818   @param  Port              The port to be polled.
819   @param  PortState         The port state.
820 
821   @retval EFI_SUCCESS       Successfully enable/disable device slot according to port state.
822   @retval Others            Should not appear.
823 
824 **/
825 EFI_STATUS
XhcPeiPollPortStatusChange(IN PEI_XHC_DEV * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT8 Port,IN EFI_USB_PORT_STATUS * PortState)826 XhcPeiPollPortStatusChange (
827   IN PEI_XHC_DEV            *Xhc,
828   IN USB_DEV_ROUTE          ParentRouteChart,
829   IN UINT8                  Port,
830   IN EFI_USB_PORT_STATUS    *PortState
831   )
832 {
833   EFI_STATUS        Status;
834   UINT8             Speed;
835   UINT8             SlotId;
836   USB_DEV_ROUTE     RouteChart;
837 
838   DEBUG ((EFI_D_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));
839 
840   Status = EFI_SUCCESS;
841 
842   if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
843     return EFI_SUCCESS;
844   }
845 
846   if (ParentRouteChart.Dword == 0) {
847     RouteChart.Route.RouteString = 0;
848     RouteChart.Route.RootPortNum = Port + 1;
849     RouteChart.Route.TierNum     = 1;
850   } else {
851     if(Port < 14) {
852       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
853     } else {
854       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
855     }
856     RouteChart.Route.RootPortNum   = ParentRouteChart.Route.RootPortNum;
857     RouteChart.Route.TierNum       = ParentRouteChart.Route.TierNum + 1;
858   }
859 
860   SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
861   if (SlotId != 0) {
862     if (Xhc->HcCParams.Data.Csz == 0) {
863       Status = XhcPeiDisableSlotCmd (Xhc, SlotId);
864     } else {
865       Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);
866     }
867   }
868 
869   if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
870       ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
871     //
872     // Has a device attached, Identify device speed after port is enabled.
873     //
874     Speed = EFI_USB_SPEED_FULL;
875     if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
876       Speed = EFI_USB_SPEED_LOW;
877     } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
878       Speed = EFI_USB_SPEED_HIGH;
879     } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
880       Speed = EFI_USB_SPEED_SUPER;
881     }
882     //
883     // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
884     //
885     SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
886     if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
887       if (Xhc->HcCParams.Data.Csz == 0) {
888         Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
889       } else {
890         Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
891       }
892     }
893   }
894 
895   return Status;
896 }
897 
898 /**
899   Calculate the device context index by endpoint address and direction.
900 
901   @param  EpAddr        The target endpoint number.
902   @param  Direction     The direction of the target endpoint.
903 
904   @return The device context index of endpoint.
905 
906 **/
907 UINT8
XhcPeiEndpointToDci(IN UINT8 EpAddr,IN EFI_USB_DATA_DIRECTION Direction)908 XhcPeiEndpointToDci (
909   IN UINT8                      EpAddr,
910   IN EFI_USB_DATA_DIRECTION     Direction
911   )
912 {
913   UINT8 Index;
914 
915   ASSERT (EpAddr <= 15);
916 
917   if (EpAddr == 0) {
918     return 1;
919   } else {
920     Index = (UINT8) (2 * EpAddr);
921     if (Direction == EfiUsbDataIn) {
922       Index += 1;
923     }
924     return Index;
925   }
926 }
927 
928 /**
929   Find out the actual device address according to the requested device address from UsbBus.
930 
931   @param  Xhc           The XHCI device.
932   @param  BusDevAddr    The requested device address by UsbBus upper driver.
933 
934   @return The actual device address assigned to the device.
935 
936 **/
937 UINT8
XhcPeiBusDevAddrToSlotId(IN PEI_XHC_DEV * Xhc,IN UINT8 BusDevAddr)938 XhcPeiBusDevAddrToSlotId (
939   IN PEI_XHC_DEV        *Xhc,
940   IN UINT8              BusDevAddr
941   )
942 {
943   UINT8   Index;
944 
945   for (Index = 0; Index < 255; Index++) {
946     if (Xhc->UsbDevContext[Index + 1].Enabled &&
947         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
948         (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
949       break;
950     }
951   }
952 
953   if (Index == 255) {
954     return 0;
955   }
956 
957   return Xhc->UsbDevContext[Index + 1].SlotId;
958 }
959 
960 /**
961   Find out the slot id according to the device's route string.
962 
963   @param  Xhc           The XHCI device.
964   @param  RouteString   The route string described the device location.
965 
966   @return The slot id used by the device.
967 
968 **/
969 UINT8
XhcPeiRouteStringToSlotId(IN PEI_XHC_DEV * Xhc,IN USB_DEV_ROUTE RouteString)970 XhcPeiRouteStringToSlotId (
971   IN PEI_XHC_DEV        *Xhc,
972   IN USB_DEV_ROUTE      RouteString
973   )
974 {
975   UINT8   Index;
976 
977   for (Index = 0; Index < 255; Index++) {
978     if (Xhc->UsbDevContext[Index + 1].Enabled &&
979         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
980         (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
981       break;
982     }
983   }
984 
985   if (Index == 255) {
986     return 0;
987   }
988 
989   return Xhc->UsbDevContext[Index + 1].SlotId;
990 }
991 
992 /**
993   Ring the door bell to notify XHCI there is a transaction to be executed.
994 
995   @param  Xhc           The XHCI device.
996   @param  SlotId        The slot id of the target device.
997   @param  Dci           The device context index of the target slot or endpoint.
998 
999 **/
1000 VOID
XhcPeiRingDoorBell(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci)1001 XhcPeiRingDoorBell (
1002   IN PEI_XHC_DEV        *Xhc,
1003   IN UINT8              SlotId,
1004   IN UINT8              Dci
1005   )
1006 {
1007   if (SlotId == 0) {
1008     XhcPeiWriteDoorBellReg (Xhc, 0, 0);
1009   } else {
1010     XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1011   }
1012 }
1013 
1014 /**
1015   Assign and initialize the device slot for a new device.
1016 
1017   @param  Xhc                   The XHCI device.
1018   @param  ParentRouteChart      The route string pointed to the parent device.
1019   @param  ParentPort            The port at which the device is located.
1020   @param  RouteChart            The route string pointed to the device.
1021   @param  DeviceSpeed           The device speed.
1022 
1023   @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.
1024   @retval Others                Fail to initialize device slot.
1025 
1026 **/
1027 EFI_STATUS
XhcPeiInitializeDeviceSlot(IN PEI_XHC_DEV * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)1028 XhcPeiInitializeDeviceSlot (
1029   IN PEI_XHC_DEV                *Xhc,
1030   IN USB_DEV_ROUTE              ParentRouteChart,
1031   IN UINT16                     ParentPort,
1032   IN USB_DEV_ROUTE              RouteChart,
1033   IN UINT8                      DeviceSpeed
1034   )
1035 {
1036   EFI_STATUS                    Status;
1037   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1038   INPUT_CONTEXT                 *InputContext;
1039   DEVICE_CONTEXT                *OutputContext;
1040   TRANSFER_RING                 *EndpointTransferRing;
1041   CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;
1042   UINT8                         DeviceAddress;
1043   CMD_TRB_ENABLE_SLOT           CmdTrb;
1044   UINT8                         SlotId;
1045   UINT8                         ParentSlotId;
1046   DEVICE_CONTEXT                *ParentDeviceContext;
1047   EFI_PHYSICAL_ADDRESS          PhyAddr;
1048 
1049   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1050   CmdTrb.CycleBit = 1;
1051   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
1052 
1053   Status = XhcPeiCmdTransfer (
1054              Xhc,
1055              (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1056              XHC_GENERIC_TIMEOUT,
1057              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1058              );
1059   if (EFI_ERROR (Status)) {
1060     DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
1061     return Status;
1062   }
1063   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1064   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1065   SlotId = (UINT8) EvtTrb->SlotId;
1066   ASSERT (SlotId != 0);
1067 
1068   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1069   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
1070   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
1071   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
1072   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1073 
1074   //
1075   // 4.3.3 Device Slot Initialization
1076   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1077   //
1078   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
1079   ASSERT (InputContext != NULL);
1080   ASSERT (((UINTN) InputContext & 0x3F) == 0);
1081   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1082 
1083   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1084 
1085   //
1086   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1087   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1088   //    Context are affected by the command.
1089   //
1090   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1091 
1092   //
1093   // 3) Initialize the Input Slot Context data structure
1094   //
1095   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
1096   InputContext->Slot.Speed          = DeviceSpeed + 1;
1097   InputContext->Slot.ContextEntries = 1;
1098   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1099 
1100   if (RouteChart.Route.RouteString != 0) {
1101     //
1102     // The device is behind of hub device.
1103     //
1104     ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
1105     ASSERT (ParentSlotId != 0);
1106     //
1107     // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1108     //
1109     ParentDeviceContext = (DEVICE_CONTEXT *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
1110     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1111         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1112       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1113         //
1114         // Full/Low device attached to High speed hub port that isolates the high speed signaling
1115         // environment from Full/Low speed signaling environment for a device
1116         //
1117         InputContext->Slot.TTPortNum   = ParentPort;
1118         InputContext->Slot.TTHubSlotId = ParentSlotId;
1119       }
1120     } else {
1121       //
1122       // Inherit the TT parameters from parent device.
1123       //
1124       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
1125       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1126       //
1127       // If the device is a High speed device then down the speed to be the same as its parent Hub
1128       //
1129       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1130         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1131       }
1132     }
1133   }
1134 
1135   //
1136   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1137   //
1138   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1139   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1140   XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1141   //
1142   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1143   //
1144   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1145 
1146   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1147     InputContext->EP[0].MaxPacketSize = 512;
1148   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1149     InputContext->EP[0].MaxPacketSize = 64;
1150   } else {
1151     InputContext->EP[0].MaxPacketSize = 8;
1152   }
1153   //
1154   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1155   // 1KB, and Bulk and Isoch endpoints 3KB.
1156   //
1157   InputContext->EP[0].AverageTRBLength = 8;
1158   InputContext->EP[0].MaxBurstSize     = 0;
1159   InputContext->EP[0].Interval         = 0;
1160   InputContext->EP[0].MaxPStreams      = 0;
1161   InputContext->EP[0].Mult             = 0;
1162   InputContext->EP[0].CErr             = 3;
1163 
1164   //
1165   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1166   //
1167   PhyAddr = UsbHcGetPciAddrForHostAddr (
1168               Xhc->MemPool,
1169               ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
1170               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
1171               );
1172   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
1173   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1174 
1175   //
1176   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1177   //
1178   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
1179   ASSERT (OutputContext != NULL);
1180   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
1181   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
1182 
1183   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1184   //
1185   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1186   //    a pointer to the Output Device Context data structure (6.2.1).
1187   //
1188   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
1189   //
1190   // Fill DCBAA with PCI device address
1191   //
1192   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
1193 
1194   //
1195   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1196   //    Context data structure described above.
1197   //
1198   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1199   // to device.
1200   //
1201   MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
1202   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1203   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
1204   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
1205   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
1206   CmdTrbAddr.CycleBit = 1;
1207   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
1208   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
1209   Status = XhcPeiCmdTransfer (
1210              Xhc,
1211              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1212              XHC_GENERIC_TIMEOUT,
1213              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1214              );
1215   if (!EFI_ERROR (Status)) {
1216     DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
1217     DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));
1218     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1219   }
1220 
1221   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));
1222   return Status;
1223 }
1224 
1225 /**
1226   Assign and initialize the device slot for a new device.
1227 
1228   @param  Xhc                   The XHCI device.
1229   @param  ParentRouteChart      The route string pointed to the parent device.
1230   @param  ParentPort            The port at which the device is located.
1231   @param  RouteChart            The route string pointed to the device.
1232   @param  DeviceSpeed           The device speed.
1233 
1234   @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.
1235   @retval Others                Fail to initialize device slot.
1236 
1237 **/
1238 EFI_STATUS
XhcPeiInitializeDeviceSlot64(IN PEI_XHC_DEV * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)1239 XhcPeiInitializeDeviceSlot64 (
1240   IN PEI_XHC_DEV                *Xhc,
1241   IN USB_DEV_ROUTE              ParentRouteChart,
1242   IN UINT16                     ParentPort,
1243   IN USB_DEV_ROUTE              RouteChart,
1244   IN UINT8                      DeviceSpeed
1245   )
1246 {
1247   EFI_STATUS                    Status;
1248   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1249   INPUT_CONTEXT_64              *InputContext;
1250   DEVICE_CONTEXT_64             *OutputContext;
1251   TRANSFER_RING                 *EndpointTransferRing;
1252   CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;
1253   UINT8                         DeviceAddress;
1254   CMD_TRB_ENABLE_SLOT           CmdTrb;
1255   UINT8                         SlotId;
1256   UINT8                         ParentSlotId;
1257   DEVICE_CONTEXT_64             *ParentDeviceContext;
1258   EFI_PHYSICAL_ADDRESS          PhyAddr;
1259 
1260   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1261   CmdTrb.CycleBit = 1;
1262   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
1263 
1264   Status = XhcPeiCmdTransfer (
1265              Xhc,
1266              (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1267              XHC_GENERIC_TIMEOUT,
1268              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1269              );
1270   if (EFI_ERROR (Status)) {
1271     DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
1272     return Status;
1273   }
1274   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1275   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1276   SlotId = (UINT8)EvtTrb->SlotId;
1277   ASSERT (SlotId != 0);
1278 
1279   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1280   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
1281   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
1282   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
1283   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1284 
1285   //
1286   // 4.3.3 Device Slot Initialization
1287   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1288   //
1289   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
1290   ASSERT (InputContext != NULL);
1291   ASSERT (((UINTN) InputContext & 0x3F) == 0);
1292   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1293 
1294   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1295 
1296   //
1297   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1298   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1299   //    Context are affected by the command.
1300   //
1301   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1302 
1303   //
1304   // 3) Initialize the Input Slot Context data structure
1305   //
1306   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
1307   InputContext->Slot.Speed          = DeviceSpeed + 1;
1308   InputContext->Slot.ContextEntries = 1;
1309   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1310 
1311   if (RouteChart.Route.RouteString != 0) {
1312     //
1313     // The device is behind of hub device.
1314     //
1315     ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
1316     ASSERT (ParentSlotId != 0);
1317     //
1318     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1319     //
1320     ParentDeviceContext = (DEVICE_CONTEXT_64 *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
1321     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1322         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1323       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1324         //
1325         // Full/Low device attached to High speed hub port that isolates the high speed signaling
1326         // environment from Full/Low speed signaling environment for a device
1327         //
1328         InputContext->Slot.TTPortNum   = ParentPort;
1329         InputContext->Slot.TTHubSlotId = ParentSlotId;
1330       }
1331     } else {
1332       //
1333       // Inherit the TT parameters from parent device.
1334       //
1335       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
1336       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1337       //
1338       // If the device is a High speed device then down the speed to be the same as its parent Hub
1339       //
1340       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1341         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1342       }
1343     }
1344   }
1345 
1346   //
1347   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1348   //
1349   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1350   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1351   XhcPeiCreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1352   //
1353   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1354   //
1355   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1356 
1357   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1358     InputContext->EP[0].MaxPacketSize = 512;
1359   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1360     InputContext->EP[0].MaxPacketSize = 64;
1361   } else {
1362     InputContext->EP[0].MaxPacketSize = 8;
1363   }
1364   //
1365   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1366   // 1KB, and Bulk and Isoch endpoints 3KB.
1367   //
1368   InputContext->EP[0].AverageTRBLength = 8;
1369   InputContext->EP[0].MaxBurstSize     = 0;
1370   InputContext->EP[0].Interval         = 0;
1371   InputContext->EP[0].MaxPStreams      = 0;
1372   InputContext->EP[0].Mult             = 0;
1373   InputContext->EP[0].CErr             = 3;
1374 
1375   //
1376   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1377   //
1378   PhyAddr = UsbHcGetPciAddrForHostAddr (
1379               Xhc->MemPool,
1380               ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
1381               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
1382               );
1383   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
1384   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1385 
1386   //
1387   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1388   //
1389   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
1390   ASSERT (OutputContext != NULL);
1391   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
1392   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
1393 
1394   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1395   //
1396   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1397   //    a pointer to the Output Device Context data structure (6.2.1).
1398   //
1399   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
1400   //
1401   // Fill DCBAA with PCI device address
1402   //
1403   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
1404 
1405   //
1406   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1407   //    Context data structure described above.
1408   //
1409   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1410   // to device.
1411   //
1412   MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
1413   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1414   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
1415   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
1416   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
1417   CmdTrbAddr.CycleBit = 1;
1418   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
1419   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
1420   Status = XhcPeiCmdTransfer (
1421              Xhc,
1422              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1423              XHC_GENERIC_TIMEOUT,
1424              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1425              );
1426   if (!EFI_ERROR (Status)) {
1427     DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
1428     DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));
1429     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1430   }
1431 
1432   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));
1433   return Status;
1434 }
1435 
1436 
1437 /**
1438   Disable the specified device slot.
1439 
1440   @param  Xhc           The XHCI device.
1441   @param  SlotId        The slot id to be disabled.
1442 
1443   @retval EFI_SUCCESS   Successfully disable the device slot.
1444 
1445 **/
1446 EFI_STATUS
XhcPeiDisableSlotCmd(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId)1447 XhcPeiDisableSlotCmd (
1448   IN PEI_XHC_DEV               *Xhc,
1449   IN UINT8                     SlotId
1450   )
1451 {
1452   EFI_STATUS            Status;
1453   TRB_TEMPLATE          *EvtTrb;
1454   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
1455   UINT8                 Index;
1456   VOID                  *RingSeg;
1457 
1458   //
1459   // Disable the device slots occupied by these devices on its downstream ports.
1460   // Entry 0 is reserved.
1461   //
1462   for (Index = 0; Index < 255; Index++) {
1463     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1464         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1465         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
1466       continue;
1467     }
1468 
1469     Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1470 
1471     if (EFI_ERROR (Status)) {
1472       DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1473       Xhc->UsbDevContext[Index + 1].SlotId = 0;
1474     }
1475   }
1476 
1477   //
1478   // Construct the disable slot command
1479   //
1480   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));
1481 
1482   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1483   CmdTrbDisSlot.CycleBit = 1;
1484   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
1485   CmdTrbDisSlot.SlotId   = SlotId;
1486   Status = XhcPeiCmdTransfer (
1487              Xhc,
1488              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
1489              XHC_GENERIC_TIMEOUT,
1490              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1491              );
1492   if (EFI_ERROR (Status)) {
1493     DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
1494     return Status;
1495   }
1496   //
1497   // Free the slot's device context entry
1498   //
1499   Xhc->DCBAA[SlotId] = 0;
1500 
1501   //
1502   // Free the slot related data structure
1503   //
1504   for (Index = 0; Index < 31; Index++) {
1505     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1506       RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1507       if (RingSeg != NULL) {
1508         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
1509       }
1510       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1511       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
1512     }
1513   }
1514 
1515   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1516     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1517       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1518     }
1519   }
1520 
1521   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1522     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
1523   }
1524 
1525   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1526     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
1527   }
1528   //
1529   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1530   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1531   // remove urb from XHCI's asynchronous transfer list.
1532   //
1533   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1534   Xhc->UsbDevContext[SlotId].SlotId  = 0;
1535 
1536   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));
1537   return Status;
1538 }
1539 
1540 /**
1541   Disable the specified device slot.
1542 
1543   @param  Xhc           The XHCI device.
1544   @param  SlotId        The slot id to be disabled.
1545 
1546   @retval EFI_SUCCESS   Successfully disable the device slot.
1547 
1548 **/
1549 EFI_STATUS
XhcPeiDisableSlotCmd64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId)1550 XhcPeiDisableSlotCmd64 (
1551   IN PEI_XHC_DEV               *Xhc,
1552   IN UINT8                     SlotId
1553   )
1554 {
1555   EFI_STATUS            Status;
1556   TRB_TEMPLATE          *EvtTrb;
1557   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
1558   UINT8                 Index;
1559   VOID                  *RingSeg;
1560 
1561   //
1562   // Disable the device slots occupied by these devices on its downstream ports.
1563   // Entry 0 is reserved.
1564   //
1565   for (Index = 0; Index < 255; Index++) {
1566     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1567         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1568         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
1569       continue;
1570     }
1571 
1572     Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1573 
1574     if (EFI_ERROR (Status)) {
1575       DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1576       Xhc->UsbDevContext[Index + 1].SlotId = 0;
1577     }
1578   }
1579 
1580   //
1581   // Construct the disable slot command
1582   //
1583   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));
1584 
1585   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1586   CmdTrbDisSlot.CycleBit = 1;
1587   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
1588   CmdTrbDisSlot.SlotId   = SlotId;
1589   Status = XhcPeiCmdTransfer (
1590              Xhc,
1591              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
1592              XHC_GENERIC_TIMEOUT,
1593              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1594              );
1595   if (EFI_ERROR (Status)) {
1596     DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));
1597     return Status;
1598   }
1599   //
1600   // Free the slot's device context entry
1601   //
1602   Xhc->DCBAA[SlotId] = 0;
1603 
1604   //
1605   // Free the slot related data structure
1606   //
1607   for (Index = 0; Index < 31; Index++) {
1608     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1609       RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1610       if (RingSeg != NULL) {
1611         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
1612       }
1613       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1614       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
1615     }
1616   }
1617 
1618   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1619     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1620       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1621     }
1622   }
1623 
1624   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1625     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
1626   }
1627 
1628   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1629      UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
1630   }
1631   //
1632   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1633   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1634   // remove urb from XHCI's asynchronous transfer list.
1635   //
1636   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1637   Xhc->UsbDevContext[SlotId].SlotId  = 0;
1638 
1639   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));
1640   return Status;
1641 }
1642 
1643 /**
1644   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1645 
1646   @param  Xhc           The XHCI device.
1647   @param  SlotId        The slot id to be configured.
1648   @param  DeviceSpeed   The device's speed.
1649   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
1650 
1651   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
1652 
1653 **/
1654 EFI_STATUS
XhcPeiSetConfigCmd(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)1655 XhcPeiSetConfigCmd (
1656   IN PEI_XHC_DEV                *Xhc,
1657   IN UINT8                      SlotId,
1658   IN UINT8                      DeviceSpeed,
1659   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc
1660   )
1661 {
1662   EFI_STATUS                    Status;
1663   USB_INTERFACE_DESCRIPTOR      *IfDesc;
1664   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
1665   UINT8                         Index;
1666   UINTN                         NumEp;
1667   UINTN                         EpIndex;
1668   UINT8                         EpAddr;
1669   EFI_USB_DATA_DIRECTION        Direction;
1670   UINT8                         Dci;
1671   UINT8                         MaxDci;
1672   EFI_PHYSICAL_ADDRESS          PhyAddr;
1673   UINT8                         Interval;
1674 
1675   TRANSFER_RING                 *EndpointTransferRing;
1676   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
1677   INPUT_CONTEXT                 *InputContext;
1678   DEVICE_CONTEXT                *OutputContext;
1679   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1680   //
1681   // 4.6.6 Configure Endpoint
1682   //
1683   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
1684   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1685   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1686   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
1687 
1688   ASSERT (ConfigDesc != NULL);
1689 
1690   MaxDci = 0;
1691 
1692   IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
1693   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1694     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
1695       IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
1696     }
1697 
1698     NumEp = IfDesc->NumEndpoints;
1699 
1700     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
1701     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1702       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1703         EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
1704       }
1705 
1706       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
1707       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
1708 
1709       Dci = XhcPeiEndpointToDci (EpAddr, Direction);
1710       if (Dci > MaxDci) {
1711         MaxDci = Dci;
1712       }
1713 
1714       InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
1715       InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
1716 
1717       if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1718         //
1719         // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1720         //
1721         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1722       } else {
1723         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1724       }
1725 
1726       switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
1727         case USB_ENDPOINT_BULK:
1728           if (Direction == EfiUsbDataIn) {
1729             InputContext->EP[Dci-1].CErr   = 3;
1730             InputContext->EP[Dci-1].EPType = ED_BULK_IN;
1731           } else {
1732             InputContext->EP[Dci-1].CErr   = 3;
1733             InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
1734           }
1735 
1736           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1737           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1738             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1739             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1740             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1741           }
1742 
1743           break;
1744         case USB_ENDPOINT_ISO:
1745           if (Direction == EfiUsbDataIn) {
1746             InputContext->EP[Dci-1].CErr   = 0;
1747             InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
1748           } else {
1749             InputContext->EP[Dci-1].CErr   = 0;
1750             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
1751           }
1752           //
1753           // Do not support isochronous transfer now.
1754           //
1755           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1756           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1757           continue;
1758         case USB_ENDPOINT_INTERRUPT:
1759           if (Direction == EfiUsbDataIn) {
1760             InputContext->EP[Dci-1].CErr   = 3;
1761             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
1762           } else {
1763             InputContext->EP[Dci-1].CErr   = 3;
1764             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
1765           }
1766           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1767           InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
1768           //
1769           // Get the bInterval from descriptor and init the interval field of endpoint context
1770           //
1771           if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
1772             Interval = EpDesc->Interval;
1773             //
1774             // Calculate through the bInterval field of Endpoint descriptor.
1775             //
1776             ASSERT (Interval != 0);
1777             InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32 ((UINT32) Interval) + 3;
1778           } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
1779             Interval = EpDesc->Interval;
1780             ASSERT (Interval >= 1 && Interval <= 16);
1781             //
1782             // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1783             //
1784             InputContext->EP[Dci-1].Interval = Interval - 1;
1785           }
1786 
1787           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1788             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1789             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1790             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1791           }
1792           break;
1793 
1794         case USB_ENDPOINT_CONTROL:
1795           //
1796           // Do not support control transfer now.
1797           //
1798           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1799         default:
1800           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1801           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1802           continue;
1803       }
1804 
1805       PhyAddr = UsbHcGetPciAddrForHostAddr (
1806                   Xhc->MemPool,
1807                   ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
1808                   sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
1809                   );
1810       PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
1811       PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
1812       InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
1813       InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1814 
1815       EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
1816     }
1817     IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
1818   }
1819 
1820   InputContext->InputControlContext.Dword2 |= BIT0;
1821   InputContext->Slot.ContextEntries         = MaxDci;
1822   //
1823   // configure endpoint
1824   //
1825   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
1826   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
1827   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
1828   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
1829   CmdTrbCfgEP.CycleBit = 1;
1830   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
1831   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
1832   DEBUG ((EFI_D_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));
1833   Status = XhcPeiCmdTransfer (
1834              Xhc,
1835              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
1836              XHC_GENERIC_TIMEOUT,
1837              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1838              );
1839   if (EFI_ERROR (Status)) {
1840     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
1841   }
1842   return Status;
1843 }
1844 
1845 /**
1846   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1847 
1848   @param  Xhc           The XHCI device.
1849   @param  SlotId        The slot id to be configured.
1850   @param  DeviceSpeed   The device's speed.
1851   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
1852 
1853   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
1854 
1855 **/
1856 EFI_STATUS
XhcPeiSetConfigCmd64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)1857 XhcPeiSetConfigCmd64 (
1858   IN PEI_XHC_DEV                *Xhc,
1859   IN UINT8                      SlotId,
1860   IN UINT8                      DeviceSpeed,
1861   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc
1862   )
1863 {
1864   EFI_STATUS                    Status;
1865   USB_INTERFACE_DESCRIPTOR      *IfDesc;
1866   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
1867   UINT8                         Index;
1868   UINTN                         NumEp;
1869   UINTN                         EpIndex;
1870   UINT8                         EpAddr;
1871   EFI_USB_DATA_DIRECTION        Direction;
1872   UINT8                         Dci;
1873   UINT8                         MaxDci;
1874   EFI_PHYSICAL_ADDRESS          PhyAddr;
1875   UINT8                         Interval;
1876 
1877   TRANSFER_RING                 *EndpointTransferRing;
1878   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
1879   INPUT_CONTEXT_64              *InputContext;
1880   DEVICE_CONTEXT_64             *OutputContext;
1881   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1882   //
1883   // 4.6.6 Configure Endpoint
1884   //
1885   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
1886   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1887   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1888   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
1889 
1890   ASSERT (ConfigDesc != NULL);
1891 
1892   MaxDci = 0;
1893 
1894   IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
1895   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1896     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
1897       IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
1898     }
1899 
1900     NumEp = IfDesc->NumEndpoints;
1901 
1902     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
1903     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1904       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1905         EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
1906       }
1907 
1908       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
1909       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
1910 
1911       Dci = XhcPeiEndpointToDci (EpAddr, Direction);
1912       ASSERT (Dci < 32);
1913       if (Dci > MaxDci) {
1914         MaxDci = Dci;
1915       }
1916 
1917       InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
1918       InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
1919 
1920       if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1921         //
1922         // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1923         //
1924         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1925       } else {
1926         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1927       }
1928 
1929       switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
1930         case USB_ENDPOINT_BULK:
1931           if (Direction == EfiUsbDataIn) {
1932             InputContext->EP[Dci-1].CErr   = 3;
1933             InputContext->EP[Dci-1].EPType = ED_BULK_IN;
1934           } else {
1935             InputContext->EP[Dci-1].CErr   = 3;
1936             InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
1937           }
1938 
1939           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1940           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1941             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1942             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1943             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1944           }
1945 
1946           break;
1947         case USB_ENDPOINT_ISO:
1948           if (Direction == EfiUsbDataIn) {
1949             InputContext->EP[Dci-1].CErr   = 0;
1950             InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
1951           } else {
1952             InputContext->EP[Dci-1].CErr   = 0;
1953             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
1954           }
1955           //
1956           // Do not support isochronous transfer now.
1957           //
1958           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1959           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1960           continue;
1961         case USB_ENDPOINT_INTERRUPT:
1962           if (Direction == EfiUsbDataIn) {
1963             InputContext->EP[Dci-1].CErr   = 3;
1964             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
1965           } else {
1966             InputContext->EP[Dci-1].CErr   = 3;
1967             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
1968           }
1969           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1970           InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
1971           //
1972           // Get the bInterval from descriptor and init the the interval field of endpoint context
1973           //
1974           if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
1975             Interval = EpDesc->Interval;
1976             //
1977             // Calculate through the bInterval field of Endpoint descriptor.
1978             //
1979             ASSERT (Interval != 0);
1980             InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32( (UINT32) Interval) + 3;
1981           } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
1982             Interval = EpDesc->Interval;
1983             ASSERT (Interval >= 1 && Interval <= 16);
1984             //
1985             // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1986             //
1987             InputContext->EP[Dci-1].Interval = Interval - 1;
1988           }
1989 
1990           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1991             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1992             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1993             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1994           }
1995           break;
1996 
1997         case USB_ENDPOINT_CONTROL:
1998           //
1999           // Do not support control transfer now.
2000           //
2001           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2002         default:
2003           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
2004           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2005           continue;
2006       }
2007 
2008       PhyAddr = UsbHcGetPciAddrForHostAddr (
2009                   Xhc->MemPool,
2010                   ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2011                   sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2012                   );
2013 
2014       PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2015       PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2016 
2017       InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2018       InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2019 
2020       EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN)EpDesc + EpDesc->Length);
2021     }
2022     IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN)IfDesc + IfDesc->Length);
2023   }
2024 
2025   InputContext->InputControlContext.Dword2 |= BIT0;
2026   InputContext->Slot.ContextEntries         = MaxDci;
2027   //
2028   // configure endpoint
2029   //
2030   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2031   PhyAddr  = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2032   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2033   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2034   CmdTrbCfgEP.CycleBit = 1;
2035   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2036   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2037   DEBUG ((EFI_D_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));
2038   Status = XhcPeiCmdTransfer (
2039              Xhc,
2040              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2041              XHC_GENERIC_TIMEOUT,
2042              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2043              );
2044   if (EFI_ERROR (Status)) {
2045     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
2046   }
2047 
2048   return Status;
2049 }
2050 
2051 
2052 /**
2053   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2054 
2055   @param  Xhc           The XHCI device.
2056   @param  SlotId        The slot id to be evaluated.
2057   @param  MaxPacketSize The max packet size supported by the device control transfer.
2058 
2059   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
2060 
2061 **/
2062 EFI_STATUS
XhcPeiEvaluateContext(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)2063 XhcPeiEvaluateContext (
2064   IN PEI_XHC_DEV                *Xhc,
2065   IN UINT8                      SlotId,
2066   IN UINT32                     MaxPacketSize
2067   )
2068 {
2069   EFI_STATUS                    Status;
2070   CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;
2071   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2072   INPUT_CONTEXT                 *InputContext;
2073   EFI_PHYSICAL_ADDRESS          PhyAddr;
2074 
2075   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2076 
2077   //
2078   // 4.6.7 Evaluate Context
2079   //
2080   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2081   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2082 
2083   InputContext->InputControlContext.Dword2 |= BIT1;
2084   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
2085 
2086   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2087   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2088   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2089   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2090   CmdTrbEvalu.CycleBit = 1;
2091   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
2092   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2093   DEBUG ((EFI_D_INFO, "XhcEvaluateContext: Evaluate context\n"));
2094   Status = XhcPeiCmdTransfer (
2095              Xhc,
2096              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2097              XHC_GENERIC_TIMEOUT,
2098              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2099              );
2100   if (EFI_ERROR (Status)) {
2101     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
2102   }
2103   return Status;
2104 }
2105 
2106 /**
2107   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2108 
2109   @param  Xhc           The XHCI device.
2110   @param  SlotId        The slot id to be evaluated.
2111   @param  MaxPacketSize The max packet size supported by the device control transfer.
2112 
2113   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
2114 
2115 **/
2116 EFI_STATUS
XhcPeiEvaluateContext64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)2117 XhcPeiEvaluateContext64 (
2118   IN PEI_XHC_DEV                *Xhc,
2119   IN UINT8                      SlotId,
2120   IN UINT32                     MaxPacketSize
2121   )
2122 {
2123   EFI_STATUS                    Status;
2124   CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;
2125   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2126   INPUT_CONTEXT_64              *InputContext;
2127   EFI_PHYSICAL_ADDRESS          PhyAddr;
2128 
2129   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2130 
2131   //
2132   // 4.6.7 Evaluate Context
2133   //
2134   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2135   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2136 
2137   InputContext->InputControlContext.Dword2 |= BIT1;
2138   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
2139 
2140   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2141   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2142   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2143   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2144   CmdTrbEvalu.CycleBit = 1;
2145   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
2146   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2147   DEBUG ((EFI_D_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));
2148   Status = XhcPeiCmdTransfer (
2149              Xhc,
2150              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2151              XHC_GENERIC_TIMEOUT,
2152              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2153              );
2154   if (EFI_ERROR (Status)) {
2155     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
2156   }
2157   return Status;
2158 }
2159 
2160 /**
2161   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2162 
2163   @param  Xhc           The XHCI device.
2164   @param  SlotId        The slot id to be configured.
2165   @param  PortNum       The total number of downstream port supported by the hub.
2166   @param  TTT           The TT think time of the hub device.
2167   @param  MTT           The multi-TT of the hub device.
2168 
2169   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
2170 
2171 **/
2172 EFI_STATUS
XhcPeiConfigHubContext(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)2173 XhcPeiConfigHubContext (
2174   IN PEI_XHC_DEV                *Xhc,
2175   IN UINT8                      SlotId,
2176   IN UINT8                      PortNum,
2177   IN UINT8                      TTT,
2178   IN UINT8                      MTT
2179   )
2180 {
2181   EFI_STATUS                    Status;
2182   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2183   INPUT_CONTEXT                 *InputContext;
2184   DEVICE_CONTEXT                *OutputContext;
2185   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
2186   EFI_PHYSICAL_ADDRESS          PhyAddr;
2187 
2188   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2189   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
2190   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2191 
2192   //
2193   // 4.6.7 Evaluate Context
2194   //
2195   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2196 
2197   InputContext->InputControlContext.Dword2 |= BIT0;
2198 
2199   //
2200   // Copy the slot context from OutputContext to Input context
2201   //
2202   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
2203   InputContext->Slot.Hub     = 1;
2204   InputContext->Slot.PortNum = PortNum;
2205   InputContext->Slot.TTT     = TTT;
2206   InputContext->Slot.MTT     = MTT;
2207 
2208   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2209   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2210   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2211   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2212   CmdTrbCfgEP.CycleBit = 1;
2213   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2214   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2215   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2216   Status = XhcPeiCmdTransfer (
2217              Xhc,
2218              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2219              XHC_GENERIC_TIMEOUT,
2220              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2221              );
2222   if (EFI_ERROR (Status)) {
2223     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
2224   }
2225   return Status;
2226 }
2227 
2228 /**
2229   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2230 
2231   @param  Xhc           The XHCI device.
2232   @param  SlotId        The slot id to be configured.
2233   @param  PortNum       The total number of downstream port supported by the hub.
2234   @param  TTT           The TT think time of the hub device.
2235   @param  MTT           The multi-TT of the hub device.
2236 
2237   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
2238 
2239 **/
2240 EFI_STATUS
XhcPeiConfigHubContext64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)2241 XhcPeiConfigHubContext64 (
2242   IN PEI_XHC_DEV                *Xhc,
2243   IN UINT8                      SlotId,
2244   IN UINT8                      PortNum,
2245   IN UINT8                      TTT,
2246   IN UINT8                      MTT
2247   )
2248 {
2249   EFI_STATUS                    Status;
2250   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2251   INPUT_CONTEXT_64              *InputContext;
2252   DEVICE_CONTEXT_64             *OutputContext;
2253   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
2254   EFI_PHYSICAL_ADDRESS          PhyAddr;
2255 
2256   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2257   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
2258   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2259 
2260   //
2261   // 4.6.7 Evaluate Context
2262   //
2263   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2264 
2265   InputContext->InputControlContext.Dword2 |= BIT0;
2266 
2267   //
2268   // Copy the slot context from OutputContext to Input context
2269   //
2270   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
2271   InputContext->Slot.Hub     = 1;
2272   InputContext->Slot.PortNum = PortNum;
2273   InputContext->Slot.TTT     = TTT;
2274   InputContext->Slot.MTT     = MTT;
2275 
2276   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2277   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2278   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2279   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2280   CmdTrbCfgEP.CycleBit = 1;
2281   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2282   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2283   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context 64\n"));
2284   Status = XhcPeiCmdTransfer (
2285              Xhc,
2286              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2287              XHC_GENERIC_TIMEOUT,
2288              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2289              );
2290   if (EFI_ERROR (Status)) {
2291     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
2292   }
2293   return Status;
2294 }
2295 
2296 /**
2297   Stop endpoint through XHCI's Stop_Endpoint cmd.
2298 
2299   @param  Xhc           The XHCI device.
2300   @param  SlotId        The slot id of the target device.
2301   @param  Dci           The device context index of the target slot or endpoint.
2302 
2303   @retval EFI_SUCCESS   Stop endpoint successfully.
2304   @retval Others        Failed to stop endpoint.
2305 
2306 **/
2307 EFI_STATUS
2308 EFIAPI
XhcPeiStopEndpoint(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci)2309 XhcPeiStopEndpoint (
2310   IN PEI_XHC_DEV        *Xhc,
2311   IN UINT8              SlotId,
2312   IN UINT8              Dci
2313   )
2314 {
2315   EFI_STATUS                    Status;
2316   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2317   CMD_TRB_STOP_ENDPOINT         CmdTrbStopED;
2318 
2319   DEBUG ((EFI_D_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
2320 
2321   //
2322   // Send stop endpoint command to transit Endpoint from running to stop state
2323   //
2324   ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
2325   CmdTrbStopED.CycleBit = 1;
2326   CmdTrbStopED.Type     = TRB_TYPE_STOP_ENDPOINT;
2327   CmdTrbStopED.EDID     = Dci;
2328   CmdTrbStopED.SlotId   = SlotId;
2329   Status = XhcPeiCmdTransfer (
2330              Xhc,
2331              (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
2332              XHC_GENERIC_TIMEOUT,
2333              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2334              );
2335   if (EFI_ERROR(Status)) {
2336     DEBUG ((EFI_D_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
2337   }
2338 
2339   return Status;
2340 }
2341 
2342 /**
2343   Reset endpoint through XHCI's Reset_Endpoint cmd.
2344 
2345   @param  Xhc           The XHCI device.
2346   @param  SlotId        The slot id of the target device.
2347   @param  Dci           The device context index of the target slot or endpoint.
2348 
2349   @retval EFI_SUCCESS   Reset endpoint successfully.
2350   @retval Others        Failed to reset endpoint.
2351 
2352 **/
2353 EFI_STATUS
2354 EFIAPI
XhcPeiResetEndpoint(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci)2355 XhcPeiResetEndpoint (
2356   IN PEI_XHC_DEV        *Xhc,
2357   IN UINT8              SlotId,
2358   IN UINT8              Dci
2359   )
2360 {
2361   EFI_STATUS                  Status;
2362   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2363   CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;
2364 
2365   DEBUG ((EFI_D_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
2366 
2367   //
2368   // Send stop endpoint command to transit Endpoint from running to stop state
2369   //
2370   ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
2371   CmdTrbResetED.CycleBit = 1;
2372   CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;
2373   CmdTrbResetED.EDID     = Dci;
2374   CmdTrbResetED.SlotId   = SlotId;
2375   Status = XhcPeiCmdTransfer (
2376              Xhc,
2377              (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
2378              XHC_GENERIC_TIMEOUT,
2379              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2380              );
2381   if (EFI_ERROR(Status)) {
2382     DEBUG ((EFI_D_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
2383   }
2384 
2385   return Status;
2386 }
2387 
2388 /**
2389   Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
2390 
2391   @param  Xhc           The XHCI device.
2392   @param  SlotId        The slot id of the target device.
2393   @param  Dci           The device context index of the target slot or endpoint.
2394   @param  Urb           The dequeue pointer of the transfer ring specified
2395                         by the urb to be updated.
2396 
2397   @retval EFI_SUCCESS   Set transfer ring dequeue pointer succeeds.
2398   @retval Others        Failed to set transfer ring dequeue pointer.
2399 
2400 **/
2401 EFI_STATUS
2402 EFIAPI
XhcPeiSetTrDequeuePointer(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci,IN URB * Urb)2403 XhcPeiSetTrDequeuePointer (
2404   IN PEI_XHC_DEV        *Xhc,
2405   IN UINT8              SlotId,
2406   IN UINT8              Dci,
2407   IN URB                *Urb
2408   )
2409 {
2410   EFI_STATUS                  Status;
2411   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2412   CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;
2413   EFI_PHYSICAL_ADDRESS        PhyAddr;
2414 
2415   DEBUG ((EFI_D_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
2416 
2417   //
2418   // Send stop endpoint command to transit Endpoint from running to stop state
2419   //
2420   ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
2421   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
2422   CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
2423   CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2424   CmdSetTRDeq.CycleBit = 1;
2425   CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;
2426   CmdSetTRDeq.Endpoint = Dci;
2427   CmdSetTRDeq.SlotId   = SlotId;
2428   Status = XhcPeiCmdTransfer (
2429              Xhc,
2430              (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
2431              XHC_GENERIC_TIMEOUT,
2432              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2433              );
2434   if (EFI_ERROR(Status)) {
2435     DEBUG ((EFI_D_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
2436   }
2437 
2438   return Status;
2439 }
2440 
2441 /**
2442   Check if there is a new generated event.
2443 
2444   @param  Xhc           The XHCI device.
2445   @param  EvtRing       The event ring to check.
2446   @param  NewEvtTrb     The new event TRB found.
2447 
2448   @retval EFI_SUCCESS   Found a new event TRB at the event ring.
2449   @retval EFI_NOT_READY The event ring has no new event.
2450 
2451 **/
2452 EFI_STATUS
XhcPeiCheckNewEvent(IN PEI_XHC_DEV * Xhc,IN EVENT_RING * EvtRing,OUT TRB_TEMPLATE ** NewEvtTrb)2453 XhcPeiCheckNewEvent (
2454   IN PEI_XHC_DEV        *Xhc,
2455   IN EVENT_RING         *EvtRing,
2456   OUT TRB_TEMPLATE      **NewEvtTrb
2457   )
2458 {
2459   ASSERT (EvtRing != NULL);
2460 
2461   *NewEvtTrb = EvtRing->EventRingDequeue;
2462 
2463   if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
2464     return EFI_NOT_READY;
2465   }
2466 
2467   EvtRing->EventRingDequeue++;
2468   //
2469   // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2470   //
2471   if ((UINTN) EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2472     EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
2473   }
2474 
2475   return EFI_SUCCESS;
2476 }
2477 
2478 /**
2479   Synchronize the specified event ring to update the enqueue and dequeue pointer.
2480 
2481   @param  Xhc       The XHCI device.
2482   @param  EvtRing   The event ring to sync.
2483 
2484   @retval EFI_SUCCESS The event ring is synchronized successfully.
2485 
2486 **/
2487 EFI_STATUS
XhcPeiSyncEventRing(IN PEI_XHC_DEV * Xhc,IN EVENT_RING * EvtRing)2488 XhcPeiSyncEventRing (
2489   IN PEI_XHC_DEV    *Xhc,
2490   IN EVENT_RING     *EvtRing
2491   )
2492 {
2493   UINTN             Index;
2494   TRB_TEMPLATE      *EvtTrb;
2495 
2496   ASSERT (EvtRing != NULL);
2497 
2498   //
2499   // Calculate the EventRingEnqueue and EventRingCCS.
2500   // Note: only support single Segment
2501   //
2502   EvtTrb = EvtRing->EventRingDequeue;
2503 
2504   for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
2505     if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {
2506       break;
2507     }
2508 
2509     EvtTrb++;
2510 
2511     if ((UINTN) EvtTrb >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2512       EvtTrb = EvtRing->EventRingSeg0;
2513       EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
2514     }
2515   }
2516 
2517   if (Index < EvtRing->TrbNumber) {
2518     EvtRing->EventRingEnqueue = EvtTrb;
2519   } else {
2520     ASSERT (FALSE);
2521   }
2522 
2523   return EFI_SUCCESS;
2524 }
2525 
2526 /**
2527   Free XHCI event ring.
2528 
2529   @param  Xhc           The XHCI device.
2530   @param  EventRing     The event ring to be freed.
2531 
2532 **/
2533 VOID
XhcPeiFreeEventRing(IN PEI_XHC_DEV * Xhc,IN EVENT_RING * EventRing)2534 XhcPeiFreeEventRing (
2535   IN PEI_XHC_DEV        *Xhc,
2536   IN EVENT_RING         *EventRing
2537   )
2538 {
2539   if(EventRing->EventRingSeg0 == NULL) {
2540     return;
2541   }
2542 
2543   //
2544   // Free EventRing Segment 0
2545   //
2546   UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
2547 
2548   //
2549   // Free ERST table
2550   //
2551   UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
2552 }
2553 
2554 /**
2555   Create XHCI event ring.
2556 
2557   @param  Xhc           The XHCI device.
2558   @param  EventRing     The created event ring.
2559 
2560 **/
2561 VOID
XhcPeiCreateEventRing(IN PEI_XHC_DEV * Xhc,OUT EVENT_RING * EventRing)2562 XhcPeiCreateEventRing (
2563   IN PEI_XHC_DEV        *Xhc,
2564   OUT EVENT_RING        *EventRing
2565   )
2566 {
2567   VOID                          *Buf;
2568   EVENT_RING_SEG_TABLE_ENTRY    *ERSTBase;
2569   UINTN                         Size;
2570   EFI_PHYSICAL_ADDRESS          ERSTPhy;
2571   EFI_PHYSICAL_ADDRESS          DequeuePhy;
2572 
2573   ASSERT (EventRing != NULL);
2574 
2575   Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
2576   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
2577   ASSERT (Buf != NULL);
2578   ASSERT (((UINTN) Buf & 0x3F) == 0);
2579   ZeroMem (Buf, Size);
2580 
2581   DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
2582 
2583   EventRing->EventRingSeg0      = Buf;
2584   EventRing->TrbNumber          = EVENT_RING_TRB_NUMBER;
2585   EventRing->EventRingDequeue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
2586   EventRing->EventRingEnqueue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
2587 
2588   //
2589   // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2590   // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2591   //
2592   EventRing->EventRingCCS = 1;
2593 
2594   Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
2595   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
2596   ASSERT (Buf != NULL);
2597   ASSERT (((UINTN) Buf & 0x3F) == 0);
2598   ZeroMem (Buf, Size);
2599 
2600   ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
2601   EventRing->ERSTBase   = ERSTBase;
2602   ERSTBase->PtrLo       = XHC_LOW_32BIT (DequeuePhy);
2603   ERSTBase->PtrHi       = XHC_HIGH_32BIT (DequeuePhy);
2604   ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
2605 
2606   ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
2607 
2608   //
2609   // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2610   //
2611   XhcPeiWriteRuntimeReg (
2612     Xhc,
2613     XHC_ERSTSZ_OFFSET,
2614     ERST_NUMBER
2615     );
2616   //
2617   // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2618   //
2619   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2620   // So divide it to two 32-bytes width register access.
2621   //
2622   XhcPeiWriteRuntimeReg (
2623     Xhc,
2624     XHC_ERDP_OFFSET,
2625     XHC_LOW_32BIT ((UINT64) (UINTN) DequeuePhy)
2626     );
2627   XhcPeiWriteRuntimeReg (
2628     Xhc,
2629     XHC_ERDP_OFFSET + 4,
2630     XHC_HIGH_32BIT ((UINT64) (UINTN) DequeuePhy)
2631     );
2632   //
2633   // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2634   //
2635   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2636   // So divide it to two 32-bytes width register access.
2637   //
2638   XhcPeiWriteRuntimeReg (
2639     Xhc,
2640     XHC_ERSTBA_OFFSET,
2641     XHC_LOW_32BIT ((UINT64) (UINTN) ERSTPhy)
2642     );
2643   XhcPeiWriteRuntimeReg (
2644     Xhc,
2645     XHC_ERSTBA_OFFSET + 4,
2646     XHC_HIGH_32BIT ((UINT64) (UINTN) ERSTPhy)
2647     );
2648   //
2649   // Need set IMAN IE bit to enable the ring interrupt
2650   //
2651   XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
2652 }
2653 
2654 /**
2655   Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2656 
2657   @param  Xhc       The XHCI device.
2658   @param  TrsRing   The transfer ring to sync.
2659 
2660   @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2661 
2662 **/
2663 EFI_STATUS
XhcPeiSyncTrsRing(IN PEI_XHC_DEV * Xhc,IN TRANSFER_RING * TrsRing)2664 XhcPeiSyncTrsRing (
2665   IN PEI_XHC_DEV    *Xhc,
2666   IN TRANSFER_RING  *TrsRing
2667   )
2668 {
2669   UINTN             Index;
2670   TRB_TEMPLATE      *TrsTrb;
2671 
2672   ASSERT (TrsRing != NULL);
2673   //
2674   // Calculate the latest RingEnqueue and RingPCS
2675   //
2676   TrsTrb = TrsRing->RingEnqueue;
2677   ASSERT (TrsTrb != NULL);
2678 
2679   for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
2680     if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
2681       break;
2682     }
2683     TrsTrb++;
2684     if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
2685       ASSERT (((LINK_TRB *) TrsTrb)->TC != 0);
2686       //
2687       // set cycle bit in Link TRB as normal
2688       //
2689       ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
2690       //
2691       // Toggle PCS maintained by software
2692       //
2693       TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
2694       TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0;  // Use host address
2695     }
2696   }
2697 
2698   ASSERT (Index != TrsRing->TrbNumber);
2699 
2700   if (TrsTrb != TrsRing->RingEnqueue) {
2701     TrsRing->RingEnqueue = TrsTrb;
2702   }
2703 
2704   //
2705   // Clear the Trb context for enqueue, but reserve the PCS bit
2706   //
2707   TrsTrb->Parameter1 = 0;
2708   TrsTrb->Parameter2 = 0;
2709   TrsTrb->Status     = 0;
2710   TrsTrb->RsvdZ1     = 0;
2711   TrsTrb->Type       = 0;
2712   TrsTrb->Control    = 0;
2713 
2714   return EFI_SUCCESS;
2715 }
2716 
2717 /**
2718   Create XHCI transfer ring.
2719 
2720   @param  Xhc               The XHCI Device.
2721   @param  TrbNum            The number of TRB in the ring.
2722   @param  TransferRing      The created transfer ring.
2723 
2724 **/
2725 VOID
XhcPeiCreateTransferRing(IN PEI_XHC_DEV * Xhc,IN UINTN TrbNum,OUT TRANSFER_RING * TransferRing)2726 XhcPeiCreateTransferRing (
2727   IN PEI_XHC_DEV            *Xhc,
2728   IN UINTN                  TrbNum,
2729   OUT TRANSFER_RING         *TransferRing
2730   )
2731 {
2732   VOID                  *Buf;
2733   LINK_TRB              *EndTrb;
2734   EFI_PHYSICAL_ADDRESS  PhyAddr;
2735 
2736   Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
2737   ASSERT (Buf != NULL);
2738   ASSERT (((UINTN) Buf & 0x3F) == 0);
2739   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
2740 
2741   TransferRing->RingSeg0     = Buf;
2742   TransferRing->TrbNumber    = TrbNum;
2743   TransferRing->RingEnqueue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
2744   TransferRing->RingDequeue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
2745   TransferRing->RingPCS      = 1;
2746   //
2747   // 4.9.2 Transfer Ring Management
2748   // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2749   // point to the first TRB in the ring.
2750   //
2751   EndTrb        = (LINK_TRB *) ((UINTN) Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
2752   EndTrb->Type  = TRB_TYPE_LINK;
2753   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
2754   EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
2755   EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
2756   //
2757   // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2758   //
2759   EndTrb->TC    = 1;
2760   //
2761   // Set Cycle bit as other TRB PCS init value
2762   //
2763   EndTrb->CycleBit = 0;
2764 }
2765 
2766 /**
2767   Initialize the XHCI host controller for schedule.
2768 
2769   @param  Xhc       The XHCI device to be initialized.
2770 
2771 **/
2772 VOID
XhcPeiInitSched(IN PEI_XHC_DEV * Xhc)2773 XhcPeiInitSched (
2774   IN PEI_XHC_DEV        *Xhc
2775   )
2776 {
2777   VOID                  *Dcbaa;
2778   EFI_PHYSICAL_ADDRESS  DcbaaPhy;
2779   UINTN                 Size;
2780   EFI_PHYSICAL_ADDRESS  CmdRingPhy;
2781   UINT32                MaxScratchpadBufs;
2782   UINT64                *ScratchBuf;
2783   EFI_PHYSICAL_ADDRESS  ScratchPhy;
2784   UINT64                *ScratchEntry;
2785   EFI_PHYSICAL_ADDRESS  ScratchEntryPhy;
2786   UINT32                Index;
2787   EFI_STATUS            Status;
2788 
2789   //
2790   // Initialize memory management.
2791   //
2792   Xhc->MemPool = UsbHcInitMemPool ();
2793   ASSERT (Xhc->MemPool != NULL);
2794 
2795   //
2796   // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2797   // to enable the device slots that system software is going to use.
2798   //
2799   Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
2800   ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
2801   XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);
2802 
2803   //
2804   // The Device Context Base Address Array entry associated with each allocated Device Slot
2805   // shall contain a 64-bit pointer to the base of the associated Device Context.
2806   // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2807   // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2808   //
2809   Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);
2810   Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);
2811   ASSERT (Dcbaa != NULL);
2812 
2813   //
2814   // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2815   // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2816   // mode (Run/Stop(R/S) ='1').
2817   //
2818   MaxScratchpadBufs      = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
2819   Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
2820   ASSERT (MaxScratchpadBufs <= 1023);
2821   if (MaxScratchpadBufs != 0) {
2822     //
2823     // Allocate the buffer to record the host address for each entry
2824     //
2825     ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
2826     ASSERT (ScratchEntry != NULL);
2827     Xhc->ScratchEntry = ScratchEntry;
2828 
2829     ScratchPhy = 0;
2830     Status = UsbHcAllocateAlignedPages (
2831                EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
2832                Xhc->PageSize,
2833                (VOID **) &ScratchBuf,
2834                &ScratchPhy
2835                );
2836     ASSERT_EFI_ERROR (Status);
2837 
2838     ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
2839     Xhc->ScratchBuf = ScratchBuf;
2840 
2841     //
2842     // Allocate each scratch buffer
2843     //
2844     for (Index = 0; Index < MaxScratchpadBufs; Index++) {
2845       ScratchEntryPhy = 0;
2846       Status = UsbHcAllocateAlignedPages (
2847                  EFI_SIZE_TO_PAGES (Xhc->PageSize),
2848                  Xhc->PageSize,
2849                  (VOID **) &ScratchEntry[Index],
2850                  &ScratchEntryPhy
2851                  );
2852       ASSERT_EFI_ERROR (Status);
2853       ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);
2854       //
2855       // Fill with the PCI device address
2856       //
2857       *ScratchBuf++ = ScratchEntryPhy;
2858     }
2859     //
2860     // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2861     // Device Context Base Address Array points to the Scratchpad Buffer Array.
2862     //
2863     *(UINT64 *) Dcbaa = (UINT64) (UINTN) ScratchPhy;
2864   }
2865 
2866   //
2867   // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2868   // a 64-bit address pointing to where the Device Context Base Address Array is located.
2869   //
2870   Xhc->DCBAA = (UINT64 *) (UINTN) Dcbaa;
2871   //
2872   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2873   // So divide it to two 32-bytes width register access.
2874   //
2875   DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);
2876   XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));
2877   XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
2878 
2879   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));
2880 
2881   //
2882   // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2883   // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
2884   // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
2885   // always be '0'.
2886   //
2887   XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
2888   //
2889   // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
2890   // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
2891   // So we set RCS as inverted PCS init value to let Command Ring empty
2892   //
2893   CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
2894   ASSERT ((CmdRingPhy & 0x3F) == 0);
2895   CmdRingPhy |= XHC_CRCR_RCS;
2896   //
2897   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2898   // So divide it to two 32-bytes width register access.
2899   //
2900   XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));
2901   XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
2902 
2903   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
2904 
2905   //
2906   // Disable the 'interrupter enable' bit in USB_CMD
2907   // and clear IE & IP bit in all Interrupter X Management Registers.
2908   //
2909   XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
2910   for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
2911     XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
2912     XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
2913   }
2914 
2915   //
2916   // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
2917   //
2918   XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);
2919   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
2920 }
2921 
2922 /**
2923   Free the resouce allocated at initializing schedule.
2924 
2925   @param  Xhc       The XHCI device.
2926 
2927 **/
2928 VOID
XhcPeiFreeSched(IN PEI_XHC_DEV * Xhc)2929 XhcPeiFreeSched (
2930   IN PEI_XHC_DEV    *Xhc
2931   )
2932 {
2933   UINT32                  Index;
2934   UINT64                  *ScratchEntry;
2935 
2936   if (Xhc->ScratchBuf != NULL) {
2937     ScratchEntry = Xhc->ScratchEntry;
2938     for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
2939       //
2940       // Free Scratchpad Buffers
2941       //
2942       UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));
2943     }
2944     //
2945     // Free Scratchpad Buffer Array
2946     //
2947     UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));
2948     FreePool (Xhc->ScratchEntry);
2949   }
2950 
2951   if (Xhc->CmdRing.RingSeg0 != NULL) {
2952     UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
2953     Xhc->CmdRing.RingSeg0 = NULL;
2954   }
2955 
2956   XhcPeiFreeEventRing (Xhc,&Xhc->EventRing);
2957 
2958   if (Xhc->DCBAA != NULL) {
2959     UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));
2960     Xhc->DCBAA = NULL;
2961   }
2962 
2963   //
2964   // Free memory pool at last
2965   //
2966   if (Xhc->MemPool != NULL) {
2967     UsbHcFreeMemPool (Xhc->MemPool);
2968     Xhc->MemPool = NULL;
2969   }
2970 }
2971 
2972