• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4 
5 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
6 
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution.  The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include "XhcPeim.h"
19 
20 /**
21   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_ERROR, "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   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1199   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
1200   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
1201   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
1202   CmdTrbAddr.CycleBit = 1;
1203   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
1204   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
1205   Status = XhcPeiCmdTransfer (
1206              Xhc,
1207              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1208              XHC_GENERIC_TIMEOUT,
1209              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1210              );
1211   if (!EFI_ERROR (Status)) {
1212     DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
1213     DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));
1214     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1215   }
1216 
1217   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));
1218   return Status;
1219 }
1220 
1221 /**
1222   Assign and initialize the device slot for a new device.
1223 
1224   @param  Xhc                   The XHCI device.
1225   @param  ParentRouteChart      The route string pointed to the parent device.
1226   @param  ParentPort            The port at which the device is located.
1227   @param  RouteChart            The route string pointed to the device.
1228   @param  DeviceSpeed           The device speed.
1229 
1230   @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.
1231   @retval Others                Fail to initialize device slot.
1232 
1233 **/
1234 EFI_STATUS
XhcPeiInitializeDeviceSlot64(IN PEI_XHC_DEV * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)1235 XhcPeiInitializeDeviceSlot64 (
1236   IN PEI_XHC_DEV                *Xhc,
1237   IN USB_DEV_ROUTE              ParentRouteChart,
1238   IN UINT16                     ParentPort,
1239   IN USB_DEV_ROUTE              RouteChart,
1240   IN UINT8                      DeviceSpeed
1241   )
1242 {
1243   EFI_STATUS                    Status;
1244   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1245   INPUT_CONTEXT_64              *InputContext;
1246   DEVICE_CONTEXT_64             *OutputContext;
1247   TRANSFER_RING                 *EndpointTransferRing;
1248   CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;
1249   UINT8                         DeviceAddress;
1250   CMD_TRB_ENABLE_SLOT           CmdTrb;
1251   UINT8                         SlotId;
1252   UINT8                         ParentSlotId;
1253   DEVICE_CONTEXT_64             *ParentDeviceContext;
1254   EFI_PHYSICAL_ADDRESS          PhyAddr;
1255 
1256   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1257   CmdTrb.CycleBit = 1;
1258   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
1259 
1260   Status = XhcPeiCmdTransfer (
1261              Xhc,
1262              (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1263              XHC_GENERIC_TIMEOUT,
1264              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1265              );
1266   if (EFI_ERROR (Status)) {
1267     DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
1268     return Status;
1269   }
1270   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1271   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1272   SlotId = (UINT8)EvtTrb->SlotId;
1273   ASSERT (SlotId != 0);
1274 
1275   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1276   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
1277   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
1278   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
1279   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1280 
1281   //
1282   // 4.3.3 Device Slot Initialization
1283   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1284   //
1285   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
1286   ASSERT (InputContext != NULL);
1287   ASSERT (((UINTN) InputContext & 0x3F) == 0);
1288   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1289 
1290   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1291 
1292   //
1293   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1294   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1295   //    Context are affected by the command.
1296   //
1297   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1298 
1299   //
1300   // 3) Initialize the Input Slot Context data structure
1301   //
1302   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
1303   InputContext->Slot.Speed          = DeviceSpeed + 1;
1304   InputContext->Slot.ContextEntries = 1;
1305   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1306 
1307   if (RouteChart.Route.RouteString != 0) {
1308     //
1309     // The device is behind of hub device.
1310     //
1311     ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
1312     ASSERT (ParentSlotId != 0);
1313     //
1314     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1315     //
1316     ParentDeviceContext = (DEVICE_CONTEXT_64 *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
1317     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1318         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1319       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1320         //
1321         // Full/Low device attached to High speed hub port that isolates the high speed signaling
1322         // environment from Full/Low speed signaling environment for a device
1323         //
1324         InputContext->Slot.TTPortNum   = ParentPort;
1325         InputContext->Slot.TTHubSlotId = ParentSlotId;
1326       }
1327     } else {
1328       //
1329       // Inherit the TT parameters from parent device.
1330       //
1331       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
1332       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1333       //
1334       // If the device is a High speed device then down the speed to be the same as its parent Hub
1335       //
1336       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1337         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1338       }
1339     }
1340   }
1341 
1342   //
1343   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1344   //
1345   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1346   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1347   XhcPeiCreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1348   //
1349   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1350   //
1351   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1352 
1353   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1354     InputContext->EP[0].MaxPacketSize = 512;
1355   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1356     InputContext->EP[0].MaxPacketSize = 64;
1357   } else {
1358     InputContext->EP[0].MaxPacketSize = 8;
1359   }
1360   //
1361   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1362   // 1KB, and Bulk and Isoch endpoints 3KB.
1363   //
1364   InputContext->EP[0].AverageTRBLength = 8;
1365   InputContext->EP[0].MaxBurstSize     = 0;
1366   InputContext->EP[0].Interval         = 0;
1367   InputContext->EP[0].MaxPStreams      = 0;
1368   InputContext->EP[0].Mult             = 0;
1369   InputContext->EP[0].CErr             = 3;
1370 
1371   //
1372   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1373   //
1374   PhyAddr = UsbHcGetPciAddrForHostAddr (
1375               Xhc->MemPool,
1376               ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
1377               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
1378               );
1379   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
1380   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1381 
1382   //
1383   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1384   //
1385   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
1386   ASSERT (OutputContext != NULL);
1387   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
1388   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
1389 
1390   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1391   //
1392   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1393   //    a pointer to the Output Device Context data structure (6.2.1).
1394   //
1395   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
1396   //
1397   // Fill DCBAA with PCI device address
1398   //
1399   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
1400 
1401   //
1402   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1403   //    Context data structure described above.
1404   //
1405   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1406   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
1407   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
1408   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
1409   CmdTrbAddr.CycleBit = 1;
1410   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
1411   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
1412   Status = XhcPeiCmdTransfer (
1413              Xhc,
1414              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1415              XHC_GENERIC_TIMEOUT,
1416              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1417              );
1418   if (!EFI_ERROR (Status)) {
1419     DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
1420     DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));
1421     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1422   }
1423 
1424   DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));
1425   return Status;
1426 }
1427 
1428 
1429 /**
1430   Disable the specified device slot.
1431 
1432   @param  Xhc           The XHCI device.
1433   @param  SlotId        The slot id to be disabled.
1434 
1435   @retval EFI_SUCCESS   Successfully disable the device slot.
1436 
1437 **/
1438 EFI_STATUS
XhcPeiDisableSlotCmd(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId)1439 XhcPeiDisableSlotCmd (
1440   IN PEI_XHC_DEV               *Xhc,
1441   IN UINT8                     SlotId
1442   )
1443 {
1444   EFI_STATUS            Status;
1445   TRB_TEMPLATE          *EvtTrb;
1446   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
1447   UINT8                 Index;
1448   VOID                  *RingSeg;
1449 
1450   //
1451   // Disable the device slots occupied by these devices on its downstream ports.
1452   // Entry 0 is reserved.
1453   //
1454   for (Index = 0; Index < 255; Index++) {
1455     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1456         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1457         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
1458       continue;
1459     }
1460 
1461     Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1462 
1463     if (EFI_ERROR (Status)) {
1464       DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1465       Xhc->UsbDevContext[Index + 1].SlotId = 0;
1466     }
1467   }
1468 
1469   //
1470   // Construct the disable slot command
1471   //
1472   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));
1473 
1474   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1475   CmdTrbDisSlot.CycleBit = 1;
1476   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
1477   CmdTrbDisSlot.SlotId   = SlotId;
1478   Status = XhcPeiCmdTransfer (
1479              Xhc,
1480              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
1481              XHC_GENERIC_TIMEOUT,
1482              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1483              );
1484   if (EFI_ERROR (Status)) {
1485     DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
1486     return Status;
1487   }
1488   //
1489   // Free the slot's device context entry
1490   //
1491   Xhc->DCBAA[SlotId] = 0;
1492 
1493   //
1494   // Free the slot related data structure
1495   //
1496   for (Index = 0; Index < 31; Index++) {
1497     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1498       RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1499       if (RingSeg != NULL) {
1500         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
1501       }
1502       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1503       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
1504     }
1505   }
1506 
1507   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1508     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1509       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1510     }
1511   }
1512 
1513   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1514     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
1515   }
1516 
1517   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1518     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
1519   }
1520   //
1521   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1522   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1523   // remove urb from XHCI's asynchronous transfer list.
1524   //
1525   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1526   Xhc->UsbDevContext[SlotId].SlotId  = 0;
1527 
1528   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));
1529   return Status;
1530 }
1531 
1532 /**
1533   Disable the specified device slot.
1534 
1535   @param  Xhc           The XHCI device.
1536   @param  SlotId        The slot id to be disabled.
1537 
1538   @retval EFI_SUCCESS   Successfully disable the device slot.
1539 
1540 **/
1541 EFI_STATUS
XhcPeiDisableSlotCmd64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId)1542 XhcPeiDisableSlotCmd64 (
1543   IN PEI_XHC_DEV               *Xhc,
1544   IN UINT8                     SlotId
1545   )
1546 {
1547   EFI_STATUS            Status;
1548   TRB_TEMPLATE          *EvtTrb;
1549   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
1550   UINT8                 Index;
1551   VOID                  *RingSeg;
1552 
1553   //
1554   // Disable the device slots occupied by these devices on its downstream ports.
1555   // Entry 0 is reserved.
1556   //
1557   for (Index = 0; Index < 255; Index++) {
1558     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1559         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1560         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
1561       continue;
1562     }
1563 
1564     Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1565 
1566     if (EFI_ERROR (Status)) {
1567       DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1568       Xhc->UsbDevContext[Index + 1].SlotId = 0;
1569     }
1570   }
1571 
1572   //
1573   // Construct the disable slot command
1574   //
1575   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));
1576 
1577   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1578   CmdTrbDisSlot.CycleBit = 1;
1579   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
1580   CmdTrbDisSlot.SlotId   = SlotId;
1581   Status = XhcPeiCmdTransfer (
1582              Xhc,
1583              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
1584              XHC_GENERIC_TIMEOUT,
1585              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1586              );
1587   if (EFI_ERROR (Status)) {
1588     DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));
1589     return Status;
1590   }
1591   //
1592   // Free the slot's device context entry
1593   //
1594   Xhc->DCBAA[SlotId] = 0;
1595 
1596   //
1597   // Free the slot related data structure
1598   //
1599   for (Index = 0; Index < 31; Index++) {
1600     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1601       RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1602       if (RingSeg != NULL) {
1603         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
1604       }
1605       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1606       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
1607     }
1608   }
1609 
1610   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1611     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1612       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1613     }
1614   }
1615 
1616   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1617     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
1618   }
1619 
1620   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1621      UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
1622   }
1623   //
1624   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1625   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1626   // remove urb from XHCI's asynchronous transfer list.
1627   //
1628   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1629   Xhc->UsbDevContext[SlotId].SlotId  = 0;
1630 
1631   DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));
1632   return Status;
1633 }
1634 
1635 /**
1636   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1637 
1638   @param  Xhc           The XHCI device.
1639   @param  SlotId        The slot id to be configured.
1640   @param  DeviceSpeed   The device's speed.
1641   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
1642 
1643   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
1644 
1645 **/
1646 EFI_STATUS
XhcPeiSetConfigCmd(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)1647 XhcPeiSetConfigCmd (
1648   IN PEI_XHC_DEV                *Xhc,
1649   IN UINT8                      SlotId,
1650   IN UINT8                      DeviceSpeed,
1651   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc
1652   )
1653 {
1654   EFI_STATUS                    Status;
1655   USB_INTERFACE_DESCRIPTOR      *IfDesc;
1656   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
1657   UINT8                         Index;
1658   UINTN                         NumEp;
1659   UINTN                         EpIndex;
1660   UINT8                         EpAddr;
1661   EFI_USB_DATA_DIRECTION        Direction;
1662   UINT8                         Dci;
1663   UINT8                         MaxDci;
1664   EFI_PHYSICAL_ADDRESS          PhyAddr;
1665   UINT8                         Interval;
1666 
1667   TRANSFER_RING                 *EndpointTransferRing;
1668   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
1669   INPUT_CONTEXT                 *InputContext;
1670   DEVICE_CONTEXT                *OutputContext;
1671   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1672   //
1673   // 4.6.6 Configure Endpoint
1674   //
1675   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
1676   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1677   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1678   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
1679 
1680   ASSERT (ConfigDesc != NULL);
1681 
1682   MaxDci = 0;
1683 
1684   IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
1685   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1686     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
1687       IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
1688     }
1689 
1690     NumEp = IfDesc->NumEndpoints;
1691 
1692     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
1693     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1694       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1695         EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
1696       }
1697 
1698       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
1699       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
1700 
1701       Dci = XhcPeiEndpointToDci (EpAddr, Direction);
1702       if (Dci > MaxDci) {
1703         MaxDci = Dci;
1704       }
1705 
1706       InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
1707       InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
1708 
1709       if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1710         //
1711         // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1712         //
1713         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1714       } else {
1715         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1716       }
1717 
1718       switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
1719         case USB_ENDPOINT_BULK:
1720           if (Direction == EfiUsbDataIn) {
1721             InputContext->EP[Dci-1].CErr   = 3;
1722             InputContext->EP[Dci-1].EPType = ED_BULK_IN;
1723           } else {
1724             InputContext->EP[Dci-1].CErr   = 3;
1725             InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
1726           }
1727 
1728           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1729           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1730             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1731             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1732             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1733           }
1734 
1735           break;
1736         case USB_ENDPOINT_ISO:
1737           if (Direction == EfiUsbDataIn) {
1738             InputContext->EP[Dci-1].CErr   = 0;
1739             InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
1740           } else {
1741             InputContext->EP[Dci-1].CErr   = 0;
1742             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
1743           }
1744           //
1745           // Do not support isochronous transfer now.
1746           //
1747           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1748           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1749           continue;
1750         case USB_ENDPOINT_INTERRUPT:
1751           if (Direction == EfiUsbDataIn) {
1752             InputContext->EP[Dci-1].CErr   = 3;
1753             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
1754           } else {
1755             InputContext->EP[Dci-1].CErr   = 3;
1756             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
1757           }
1758           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1759           InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
1760           //
1761           // Get the bInterval from descriptor and init the interval field of endpoint context
1762           //
1763           if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
1764             Interval = EpDesc->Interval;
1765             //
1766             // Calculate through the bInterval field of Endpoint descriptor.
1767             //
1768             ASSERT (Interval != 0);
1769             InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32 ((UINT32) Interval) + 3;
1770           } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
1771             Interval = EpDesc->Interval;
1772             ASSERT (Interval >= 1 && Interval <= 16);
1773             //
1774             // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1775             //
1776             InputContext->EP[Dci-1].Interval = Interval - 1;
1777           }
1778 
1779           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1780             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1781             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1782             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1783           }
1784           break;
1785 
1786         case USB_ENDPOINT_CONTROL:
1787           //
1788           // Do not support control transfer now.
1789           //
1790           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1791         default:
1792           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1793           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1794           continue;
1795       }
1796 
1797       PhyAddr = UsbHcGetPciAddrForHostAddr (
1798                   Xhc->MemPool,
1799                   ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
1800                   sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
1801                   );
1802       PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
1803       PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
1804       InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
1805       InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1806 
1807       EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
1808     }
1809     IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
1810   }
1811 
1812   InputContext->InputControlContext.Dword2 |= BIT0;
1813   InputContext->Slot.ContextEntries         = MaxDci;
1814   //
1815   // configure endpoint
1816   //
1817   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
1818   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
1819   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
1820   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
1821   CmdTrbCfgEP.CycleBit = 1;
1822   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
1823   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
1824   DEBUG ((EFI_D_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));
1825   Status = XhcPeiCmdTransfer (
1826              Xhc,
1827              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
1828              XHC_GENERIC_TIMEOUT,
1829              (TRB_TEMPLATE **) (UINTN) &EvtTrb
1830              );
1831   if (EFI_ERROR (Status)) {
1832     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
1833   }
1834   return Status;
1835 }
1836 
1837 /**
1838   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1839 
1840   @param  Xhc           The XHCI device.
1841   @param  SlotId        The slot id to be configured.
1842   @param  DeviceSpeed   The device's speed.
1843   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
1844 
1845   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
1846 
1847 **/
1848 EFI_STATUS
XhcPeiSetConfigCmd64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)1849 XhcPeiSetConfigCmd64 (
1850   IN PEI_XHC_DEV                *Xhc,
1851   IN UINT8                      SlotId,
1852   IN UINT8                      DeviceSpeed,
1853   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc
1854   )
1855 {
1856   EFI_STATUS                    Status;
1857   USB_INTERFACE_DESCRIPTOR      *IfDesc;
1858   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
1859   UINT8                         Index;
1860   UINTN                         NumEp;
1861   UINTN                         EpIndex;
1862   UINT8                         EpAddr;
1863   EFI_USB_DATA_DIRECTION        Direction;
1864   UINT8                         Dci;
1865   UINT8                         MaxDci;
1866   EFI_PHYSICAL_ADDRESS          PhyAddr;
1867   UINT8                         Interval;
1868 
1869   TRANSFER_RING                 *EndpointTransferRing;
1870   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
1871   INPUT_CONTEXT_64              *InputContext;
1872   DEVICE_CONTEXT_64             *OutputContext;
1873   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
1874   //
1875   // 4.6.6 Configure Endpoint
1876   //
1877   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
1878   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1879   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1880   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
1881 
1882   ASSERT (ConfigDesc != NULL);
1883 
1884   MaxDci = 0;
1885 
1886   IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
1887   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1888     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
1889       IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
1890     }
1891 
1892     NumEp = IfDesc->NumEndpoints;
1893 
1894     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
1895     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1896       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1897         EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
1898       }
1899 
1900       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
1901       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
1902 
1903       Dci = XhcPeiEndpointToDci (EpAddr, Direction);
1904       ASSERT (Dci < 32);
1905       if (Dci > MaxDci) {
1906         MaxDci = Dci;
1907       }
1908 
1909       InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
1910       InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
1911 
1912       if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1913         //
1914         // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1915         //
1916         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1917       } else {
1918         InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1919       }
1920 
1921       switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
1922         case USB_ENDPOINT_BULK:
1923           if (Direction == EfiUsbDataIn) {
1924             InputContext->EP[Dci-1].CErr   = 3;
1925             InputContext->EP[Dci-1].EPType = ED_BULK_IN;
1926           } else {
1927             InputContext->EP[Dci-1].CErr   = 3;
1928             InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
1929           }
1930 
1931           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1932           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1933             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1934             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1935             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1936           }
1937 
1938           break;
1939         case USB_ENDPOINT_ISO:
1940           if (Direction == EfiUsbDataIn) {
1941             InputContext->EP[Dci-1].CErr   = 0;
1942             InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
1943           } else {
1944             InputContext->EP[Dci-1].CErr   = 0;
1945             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
1946           }
1947           //
1948           // Do not support isochronous transfer now.
1949           //
1950           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1951           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1952           continue;
1953         case USB_ENDPOINT_INTERRUPT:
1954           if (Direction == EfiUsbDataIn) {
1955             InputContext->EP[Dci-1].CErr   = 3;
1956             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
1957           } else {
1958             InputContext->EP[Dci-1].CErr   = 3;
1959             InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
1960           }
1961           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1962           InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
1963           //
1964           // Get the bInterval from descriptor and init the the interval field of endpoint context
1965           //
1966           if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
1967             Interval = EpDesc->Interval;
1968             //
1969             // Calculate through the bInterval field of Endpoint descriptor.
1970             //
1971             ASSERT (Interval != 0);
1972             InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32( (UINT32) Interval) + 3;
1973           } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
1974             Interval = EpDesc->Interval;
1975             ASSERT (Interval >= 1 && Interval <= 16);
1976             //
1977             // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1978             //
1979             InputContext->EP[Dci-1].Interval = Interval - 1;
1980           }
1981 
1982           if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1983             EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1984             Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
1985             XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1986           }
1987           break;
1988 
1989         case USB_ENDPOINT_CONTROL:
1990           //
1991           // Do not support control transfer now.
1992           //
1993           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1994         default:
1995           DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
1996           EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1997           continue;
1998       }
1999 
2000       PhyAddr = UsbHcGetPciAddrForHostAddr (
2001                   Xhc->MemPool,
2002                   ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2003                   sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2004                   );
2005 
2006       PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2007       PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2008 
2009       InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2010       InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2011 
2012       EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN)EpDesc + EpDesc->Length);
2013     }
2014     IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN)IfDesc + IfDesc->Length);
2015   }
2016 
2017   InputContext->InputControlContext.Dword2 |= BIT0;
2018   InputContext->Slot.ContextEntries         = MaxDci;
2019   //
2020   // configure endpoint
2021   //
2022   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2023   PhyAddr  = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2024   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2025   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2026   CmdTrbCfgEP.CycleBit = 1;
2027   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2028   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2029   DEBUG ((EFI_D_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));
2030   Status = XhcPeiCmdTransfer (
2031              Xhc,
2032              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2033              XHC_GENERIC_TIMEOUT,
2034              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2035              );
2036   if (EFI_ERROR (Status)) {
2037     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
2038   }
2039 
2040   return Status;
2041 }
2042 
2043 
2044 /**
2045   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2046 
2047   @param  Xhc           The XHCI device.
2048   @param  SlotId        The slot id to be evaluated.
2049   @param  MaxPacketSize The max packet size supported by the device control transfer.
2050 
2051   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
2052 
2053 **/
2054 EFI_STATUS
XhcPeiEvaluateContext(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)2055 XhcPeiEvaluateContext (
2056   IN PEI_XHC_DEV                *Xhc,
2057   IN UINT8                      SlotId,
2058   IN UINT32                     MaxPacketSize
2059   )
2060 {
2061   EFI_STATUS                    Status;
2062   CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;
2063   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2064   INPUT_CONTEXT                 *InputContext;
2065   EFI_PHYSICAL_ADDRESS          PhyAddr;
2066 
2067   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2068 
2069   //
2070   // 4.6.7 Evaluate Context
2071   //
2072   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2073   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2074 
2075   InputContext->InputControlContext.Dword2 |= BIT1;
2076   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
2077 
2078   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2079   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2080   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2081   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2082   CmdTrbEvalu.CycleBit = 1;
2083   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
2084   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2085   DEBUG ((EFI_D_INFO, "XhcEvaluateContext: Evaluate context\n"));
2086   Status = XhcPeiCmdTransfer (
2087              Xhc,
2088              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2089              XHC_GENERIC_TIMEOUT,
2090              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2091              );
2092   if (EFI_ERROR (Status)) {
2093     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
2094   }
2095   return Status;
2096 }
2097 
2098 /**
2099   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2100 
2101   @param  Xhc           The XHCI device.
2102   @param  SlotId        The slot id to be evaluated.
2103   @param  MaxPacketSize The max packet size supported by the device control transfer.
2104 
2105   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
2106 
2107 **/
2108 EFI_STATUS
XhcPeiEvaluateContext64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)2109 XhcPeiEvaluateContext64 (
2110   IN PEI_XHC_DEV                *Xhc,
2111   IN UINT8                      SlotId,
2112   IN UINT32                     MaxPacketSize
2113   )
2114 {
2115   EFI_STATUS                    Status;
2116   CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;
2117   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2118   INPUT_CONTEXT_64              *InputContext;
2119   EFI_PHYSICAL_ADDRESS          PhyAddr;
2120 
2121   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2122 
2123   //
2124   // 4.6.7 Evaluate Context
2125   //
2126   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2127   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2128 
2129   InputContext->InputControlContext.Dword2 |= BIT1;
2130   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
2131 
2132   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2133   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2134   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2135   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2136   CmdTrbEvalu.CycleBit = 1;
2137   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
2138   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2139   DEBUG ((EFI_D_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));
2140   Status = XhcPeiCmdTransfer (
2141              Xhc,
2142              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2143              XHC_GENERIC_TIMEOUT,
2144              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2145              );
2146   if (EFI_ERROR (Status)) {
2147     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
2148   }
2149   return Status;
2150 }
2151 
2152 /**
2153   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2154 
2155   @param  Xhc           The XHCI device.
2156   @param  SlotId        The slot id to be configured.
2157   @param  PortNum       The total number of downstream port supported by the hub.
2158   @param  TTT           The TT think time of the hub device.
2159   @param  MTT           The multi-TT of the hub device.
2160 
2161   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
2162 
2163 **/
2164 EFI_STATUS
XhcPeiConfigHubContext(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)2165 XhcPeiConfigHubContext (
2166   IN PEI_XHC_DEV                *Xhc,
2167   IN UINT8                      SlotId,
2168   IN UINT8                      PortNum,
2169   IN UINT8                      TTT,
2170   IN UINT8                      MTT
2171   )
2172 {
2173   EFI_STATUS                    Status;
2174   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2175   INPUT_CONTEXT                 *InputContext;
2176   DEVICE_CONTEXT                *OutputContext;
2177   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
2178   EFI_PHYSICAL_ADDRESS          PhyAddr;
2179 
2180   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2181   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
2182   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2183 
2184   //
2185   // 4.6.7 Evaluate Context
2186   //
2187   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2188 
2189   InputContext->InputControlContext.Dword2 |= BIT0;
2190 
2191   //
2192   // Copy the slot context from OutputContext to Input context
2193   //
2194   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
2195   InputContext->Slot.Hub     = 1;
2196   InputContext->Slot.PortNum = PortNum;
2197   InputContext->Slot.TTT     = TTT;
2198   InputContext->Slot.MTT     = MTT;
2199 
2200   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2201   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2202   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2203   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2204   CmdTrbCfgEP.CycleBit = 1;
2205   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2206   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2207   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2208   Status = XhcPeiCmdTransfer (
2209              Xhc,
2210              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2211              XHC_GENERIC_TIMEOUT,
2212              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2213              );
2214   if (EFI_ERROR (Status)) {
2215     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
2216   }
2217   return Status;
2218 }
2219 
2220 /**
2221   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2222 
2223   @param  Xhc           The XHCI device.
2224   @param  SlotId        The slot id to be configured.
2225   @param  PortNum       The total number of downstream port supported by the hub.
2226   @param  TTT           The TT think time of the hub device.
2227   @param  MTT           The multi-TT of the hub device.
2228 
2229   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
2230 
2231 **/
2232 EFI_STATUS
XhcPeiConfigHubContext64(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)2233 XhcPeiConfigHubContext64 (
2234   IN PEI_XHC_DEV                *Xhc,
2235   IN UINT8                      SlotId,
2236   IN UINT8                      PortNum,
2237   IN UINT8                      TTT,
2238   IN UINT8                      MTT
2239   )
2240 {
2241   EFI_STATUS                    Status;
2242   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2243   INPUT_CONTEXT_64              *InputContext;
2244   DEVICE_CONTEXT_64             *OutputContext;
2245   CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;
2246   EFI_PHYSICAL_ADDRESS          PhyAddr;
2247 
2248   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2249   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
2250   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2251 
2252   //
2253   // 4.6.7 Evaluate Context
2254   //
2255   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2256 
2257   InputContext->InputControlContext.Dword2 |= BIT0;
2258 
2259   //
2260   // Copy the slot context from OutputContext to Input context
2261   //
2262   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
2263   InputContext->Slot.Hub     = 1;
2264   InputContext->Slot.PortNum = PortNum;
2265   InputContext->Slot.TTT     = TTT;
2266   InputContext->Slot.MTT     = MTT;
2267 
2268   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2269   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2270   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2271   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2272   CmdTrbCfgEP.CycleBit = 1;
2273   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2274   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2275   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context 64\n"));
2276   Status = XhcPeiCmdTransfer (
2277              Xhc,
2278              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2279              XHC_GENERIC_TIMEOUT,
2280              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2281              );
2282   if (EFI_ERROR (Status)) {
2283     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
2284   }
2285   return Status;
2286 }
2287 
2288 /**
2289   Stop endpoint through XHCI's Stop_Endpoint cmd.
2290 
2291   @param  Xhc           The XHCI device.
2292   @param  SlotId        The slot id of the target device.
2293   @param  Dci           The device context index of the target slot or endpoint.
2294 
2295   @retval EFI_SUCCESS   Stop endpoint successfully.
2296   @retval Others        Failed to stop endpoint.
2297 
2298 **/
2299 EFI_STATUS
2300 EFIAPI
XhcPeiStopEndpoint(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci)2301 XhcPeiStopEndpoint (
2302   IN PEI_XHC_DEV        *Xhc,
2303   IN UINT8              SlotId,
2304   IN UINT8              Dci
2305   )
2306 {
2307   EFI_STATUS                    Status;
2308   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
2309   CMD_TRB_STOP_ENDPOINT         CmdTrbStopED;
2310 
2311   DEBUG ((EFI_D_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
2312 
2313   //
2314   // Send stop endpoint command to transit Endpoint from running to stop state
2315   //
2316   ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
2317   CmdTrbStopED.CycleBit = 1;
2318   CmdTrbStopED.Type     = TRB_TYPE_STOP_ENDPOINT;
2319   CmdTrbStopED.EDID     = Dci;
2320   CmdTrbStopED.SlotId   = SlotId;
2321   Status = XhcPeiCmdTransfer (
2322              Xhc,
2323              (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
2324              XHC_GENERIC_TIMEOUT,
2325              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2326              );
2327   if (EFI_ERROR(Status)) {
2328     DEBUG ((EFI_D_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
2329   }
2330 
2331   return Status;
2332 }
2333 
2334 /**
2335   Reset endpoint through XHCI's Reset_Endpoint cmd.
2336 
2337   @param  Xhc           The XHCI device.
2338   @param  SlotId        The slot id of the target device.
2339   @param  Dci           The device context index of the target slot or endpoint.
2340 
2341   @retval EFI_SUCCESS   Reset endpoint successfully.
2342   @retval Others        Failed to reset endpoint.
2343 
2344 **/
2345 EFI_STATUS
2346 EFIAPI
XhcPeiResetEndpoint(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci)2347 XhcPeiResetEndpoint (
2348   IN PEI_XHC_DEV        *Xhc,
2349   IN UINT8              SlotId,
2350   IN UINT8              Dci
2351   )
2352 {
2353   EFI_STATUS                  Status;
2354   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2355   CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;
2356 
2357   DEBUG ((EFI_D_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
2358 
2359   //
2360   // Send stop endpoint command to transit Endpoint from running to stop state
2361   //
2362   ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
2363   CmdTrbResetED.CycleBit = 1;
2364   CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;
2365   CmdTrbResetED.EDID     = Dci;
2366   CmdTrbResetED.SlotId   = SlotId;
2367   Status = XhcPeiCmdTransfer (
2368              Xhc,
2369              (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
2370              XHC_GENERIC_TIMEOUT,
2371              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2372              );
2373   if (EFI_ERROR(Status)) {
2374     DEBUG ((EFI_D_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
2375   }
2376 
2377   return Status;
2378 }
2379 
2380 /**
2381   Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
2382 
2383   @param  Xhc           The XHCI device.
2384   @param  SlotId        The slot id of the target device.
2385   @param  Dci           The device context index of the target slot or endpoint.
2386   @param  Urb           The dequeue pointer of the transfer ring specified
2387                         by the urb to be updated.
2388 
2389   @retval EFI_SUCCESS   Set transfer ring dequeue pointer succeeds.
2390   @retval Others        Failed to set transfer ring dequeue pointer.
2391 
2392 **/
2393 EFI_STATUS
2394 EFIAPI
XhcPeiSetTrDequeuePointer(IN PEI_XHC_DEV * Xhc,IN UINT8 SlotId,IN UINT8 Dci,IN URB * Urb)2395 XhcPeiSetTrDequeuePointer (
2396   IN PEI_XHC_DEV        *Xhc,
2397   IN UINT8              SlotId,
2398   IN UINT8              Dci,
2399   IN URB                *Urb
2400   )
2401 {
2402   EFI_STATUS                  Status;
2403   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2404   CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;
2405   EFI_PHYSICAL_ADDRESS        PhyAddr;
2406 
2407   DEBUG ((EFI_D_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
2408 
2409   //
2410   // Send stop endpoint command to transit Endpoint from running to stop state
2411   //
2412   ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
2413   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
2414   CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
2415   CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2416   CmdSetTRDeq.CycleBit = 1;
2417   CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;
2418   CmdSetTRDeq.Endpoint = Dci;
2419   CmdSetTRDeq.SlotId   = SlotId;
2420   Status = XhcPeiCmdTransfer (
2421              Xhc,
2422              (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
2423              XHC_GENERIC_TIMEOUT,
2424              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2425              );
2426   if (EFI_ERROR(Status)) {
2427     DEBUG ((EFI_D_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
2428   }
2429 
2430   return Status;
2431 }
2432 
2433 /**
2434   Check if there is a new generated event.
2435 
2436   @param  Xhc           The XHCI device.
2437   @param  EvtRing       The event ring to check.
2438   @param  NewEvtTrb     The new event TRB found.
2439 
2440   @retval EFI_SUCCESS   Found a new event TRB at the event ring.
2441   @retval EFI_NOT_READY The event ring has no new event.
2442 
2443 **/
2444 EFI_STATUS
XhcPeiCheckNewEvent(IN PEI_XHC_DEV * Xhc,IN EVENT_RING * EvtRing,OUT TRB_TEMPLATE ** NewEvtTrb)2445 XhcPeiCheckNewEvent (
2446   IN PEI_XHC_DEV        *Xhc,
2447   IN EVENT_RING         *EvtRing,
2448   OUT TRB_TEMPLATE      **NewEvtTrb
2449   )
2450 {
2451   ASSERT (EvtRing != NULL);
2452 
2453   *NewEvtTrb = EvtRing->EventRingDequeue;
2454 
2455   if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
2456     return EFI_NOT_READY;
2457   }
2458 
2459   EvtRing->EventRingDequeue++;
2460   //
2461   // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2462   //
2463   if ((UINTN) EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2464     EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
2465   }
2466 
2467   return EFI_SUCCESS;
2468 }
2469 
2470 /**
2471   Synchronize the specified event ring to update the enqueue and dequeue pointer.
2472 
2473   @param  Xhc       The XHCI device.
2474   @param  EvtRing   The event ring to sync.
2475 
2476   @retval EFI_SUCCESS The event ring is synchronized successfully.
2477 
2478 **/
2479 EFI_STATUS
XhcPeiSyncEventRing(IN PEI_XHC_DEV * Xhc,IN EVENT_RING * EvtRing)2480 XhcPeiSyncEventRing (
2481   IN PEI_XHC_DEV    *Xhc,
2482   IN EVENT_RING     *EvtRing
2483   )
2484 {
2485   UINTN             Index;
2486   TRB_TEMPLATE      *EvtTrb;
2487 
2488   ASSERT (EvtRing != NULL);
2489 
2490   //
2491   // Calculate the EventRingEnqueue and EventRingCCS.
2492   // Note: only support single Segment
2493   //
2494   EvtTrb = EvtRing->EventRingDequeue;
2495 
2496   for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
2497     if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {
2498       break;
2499     }
2500 
2501     EvtTrb++;
2502 
2503     if ((UINTN) EvtTrb >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2504       EvtTrb = EvtRing->EventRingSeg0;
2505       EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
2506     }
2507   }
2508 
2509   if (Index < EvtRing->TrbNumber) {
2510     EvtRing->EventRingEnqueue = EvtTrb;
2511   } else {
2512     ASSERT (FALSE);
2513   }
2514 
2515   return EFI_SUCCESS;
2516 }
2517 
2518 /**
2519   Free XHCI event ring.
2520 
2521   @param  Xhc           The XHCI device.
2522   @param  EventRing     The event ring to be freed.
2523 
2524 **/
2525 VOID
XhcPeiFreeEventRing(IN PEI_XHC_DEV * Xhc,IN EVENT_RING * EventRing)2526 XhcPeiFreeEventRing (
2527   IN PEI_XHC_DEV        *Xhc,
2528   IN EVENT_RING         *EventRing
2529   )
2530 {
2531   if(EventRing->EventRingSeg0 == NULL) {
2532     return;
2533   }
2534 
2535   //
2536   // Free EventRing Segment 0
2537   //
2538   UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
2539 
2540   //
2541   // Free ERST table
2542   //
2543   UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
2544 }
2545 
2546 /**
2547   Create XHCI event ring.
2548 
2549   @param  Xhc           The XHCI device.
2550   @param  EventRing     The created event ring.
2551 
2552 **/
2553 VOID
XhcPeiCreateEventRing(IN PEI_XHC_DEV * Xhc,OUT EVENT_RING * EventRing)2554 XhcPeiCreateEventRing (
2555   IN PEI_XHC_DEV        *Xhc,
2556   OUT EVENT_RING        *EventRing
2557   )
2558 {
2559   VOID                          *Buf;
2560   EVENT_RING_SEG_TABLE_ENTRY    *ERSTBase;
2561   UINTN                         Size;
2562   EFI_PHYSICAL_ADDRESS          ERSTPhy;
2563   EFI_PHYSICAL_ADDRESS          DequeuePhy;
2564 
2565   ASSERT (EventRing != NULL);
2566 
2567   Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
2568   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
2569   ASSERT (Buf != NULL);
2570   ASSERT (((UINTN) Buf & 0x3F) == 0);
2571   ZeroMem (Buf, Size);
2572 
2573   DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
2574 
2575   EventRing->EventRingSeg0      = Buf;
2576   EventRing->TrbNumber          = EVENT_RING_TRB_NUMBER;
2577   EventRing->EventRingDequeue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
2578   EventRing->EventRingEnqueue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
2579 
2580   //
2581   // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2582   // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2583   //
2584   EventRing->EventRingCCS = 1;
2585 
2586   Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
2587   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
2588   ASSERT (Buf != NULL);
2589   ASSERT (((UINTN) Buf & 0x3F) == 0);
2590   ZeroMem (Buf, Size);
2591 
2592   ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
2593   EventRing->ERSTBase   = ERSTBase;
2594   ERSTBase->PtrLo       = XHC_LOW_32BIT (DequeuePhy);
2595   ERSTBase->PtrHi       = XHC_HIGH_32BIT (DequeuePhy);
2596   ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
2597 
2598   ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
2599 
2600   //
2601   // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2602   //
2603   XhcPeiWriteRuntimeReg (
2604     Xhc,
2605     XHC_ERSTSZ_OFFSET,
2606     ERST_NUMBER
2607     );
2608   //
2609   // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2610   //
2611   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2612   // So divide it to two 32-bytes width register access.
2613   //
2614   XhcPeiWriteRuntimeReg (
2615     Xhc,
2616     XHC_ERDP_OFFSET,
2617     XHC_LOW_32BIT ((UINT64) (UINTN) DequeuePhy)
2618     );
2619   XhcPeiWriteRuntimeReg (
2620     Xhc,
2621     XHC_ERDP_OFFSET + 4,
2622     XHC_HIGH_32BIT ((UINT64) (UINTN) DequeuePhy)
2623     );
2624   //
2625   // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2626   //
2627   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2628   // So divide it to two 32-bytes width register access.
2629   //
2630   XhcPeiWriteRuntimeReg (
2631     Xhc,
2632     XHC_ERSTBA_OFFSET,
2633     XHC_LOW_32BIT ((UINT64) (UINTN) ERSTPhy)
2634     );
2635   XhcPeiWriteRuntimeReg (
2636     Xhc,
2637     XHC_ERSTBA_OFFSET + 4,
2638     XHC_HIGH_32BIT ((UINT64) (UINTN) ERSTPhy)
2639     );
2640   //
2641   // Need set IMAN IE bit to enable the ring interrupt
2642   //
2643   XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
2644 }
2645 
2646 /**
2647   Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2648 
2649   @param  Xhc       The XHCI device.
2650   @param  TrsRing   The transfer ring to sync.
2651 
2652   @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2653 
2654 **/
2655 EFI_STATUS
XhcPeiSyncTrsRing(IN PEI_XHC_DEV * Xhc,IN TRANSFER_RING * TrsRing)2656 XhcPeiSyncTrsRing (
2657   IN PEI_XHC_DEV    *Xhc,
2658   IN TRANSFER_RING  *TrsRing
2659   )
2660 {
2661   UINTN             Index;
2662   TRB_TEMPLATE      *TrsTrb;
2663 
2664   ASSERT (TrsRing != NULL);
2665   //
2666   // Calculate the latest RingEnqueue and RingPCS
2667   //
2668   TrsTrb = TrsRing->RingEnqueue;
2669   ASSERT (TrsTrb != NULL);
2670 
2671   for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
2672     if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
2673       break;
2674     }
2675     TrsTrb++;
2676     if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
2677       ASSERT (((LINK_TRB *) TrsTrb)->TC != 0);
2678       //
2679       // set cycle bit in Link TRB as normal
2680       //
2681       ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
2682       //
2683       // Toggle PCS maintained by software
2684       //
2685       TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
2686       TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0;  // Use host address
2687     }
2688   }
2689 
2690   ASSERT (Index != TrsRing->TrbNumber);
2691 
2692   if (TrsTrb != TrsRing->RingEnqueue) {
2693     TrsRing->RingEnqueue = TrsTrb;
2694   }
2695 
2696   //
2697   // Clear the Trb context for enqueue, but reserve the PCS bit
2698   //
2699   TrsTrb->Parameter1 = 0;
2700   TrsTrb->Parameter2 = 0;
2701   TrsTrb->Status     = 0;
2702   TrsTrb->RsvdZ1     = 0;
2703   TrsTrb->Type       = 0;
2704   TrsTrb->Control    = 0;
2705 
2706   return EFI_SUCCESS;
2707 }
2708 
2709 /**
2710   Create XHCI transfer ring.
2711 
2712   @param  Xhc               The XHCI Device.
2713   @param  TrbNum            The number of TRB in the ring.
2714   @param  TransferRing      The created transfer ring.
2715 
2716 **/
2717 VOID
XhcPeiCreateTransferRing(IN PEI_XHC_DEV * Xhc,IN UINTN TrbNum,OUT TRANSFER_RING * TransferRing)2718 XhcPeiCreateTransferRing (
2719   IN PEI_XHC_DEV            *Xhc,
2720   IN UINTN                  TrbNum,
2721   OUT TRANSFER_RING         *TransferRing
2722   )
2723 {
2724   VOID                  *Buf;
2725   LINK_TRB              *EndTrb;
2726   EFI_PHYSICAL_ADDRESS  PhyAddr;
2727 
2728   Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
2729   ASSERT (Buf != NULL);
2730   ASSERT (((UINTN) Buf & 0x3F) == 0);
2731   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
2732 
2733   TransferRing->RingSeg0     = Buf;
2734   TransferRing->TrbNumber    = TrbNum;
2735   TransferRing->RingEnqueue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
2736   TransferRing->RingDequeue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
2737   TransferRing->RingPCS      = 1;
2738   //
2739   // 4.9.2 Transfer Ring Management
2740   // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2741   // point to the first TRB in the ring.
2742   //
2743   EndTrb        = (LINK_TRB *) ((UINTN) Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
2744   EndTrb->Type  = TRB_TYPE_LINK;
2745   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
2746   EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
2747   EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
2748   //
2749   // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2750   //
2751   EndTrb->TC    = 1;
2752   //
2753   // Set Cycle bit as other TRB PCS init value
2754   //
2755   EndTrb->CycleBit = 0;
2756 }
2757 
2758 /**
2759   Initialize the XHCI host controller for schedule.
2760 
2761   @param  Xhc       The XHCI device to be initialized.
2762 
2763 **/
2764 VOID
XhcPeiInitSched(IN PEI_XHC_DEV * Xhc)2765 XhcPeiInitSched (
2766   IN PEI_XHC_DEV        *Xhc
2767   )
2768 {
2769   VOID                  *Dcbaa;
2770   EFI_PHYSICAL_ADDRESS  DcbaaPhy;
2771   UINTN                 Size;
2772   EFI_PHYSICAL_ADDRESS  CmdRingPhy;
2773   UINT32                MaxScratchpadBufs;
2774   UINT64                *ScratchBuf;
2775   EFI_PHYSICAL_ADDRESS  ScratchPhy;
2776   UINT64                *ScratchEntry;
2777   EFI_PHYSICAL_ADDRESS  ScratchEntryPhy;
2778   UINT32                Index;
2779   EFI_STATUS            Status;
2780 
2781   //
2782   // Initialize memory management.
2783   //
2784   Xhc->MemPool = UsbHcInitMemPool ();
2785   ASSERT (Xhc->MemPool != NULL);
2786 
2787   //
2788   // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2789   // to enable the device slots that system software is going to use.
2790   //
2791   Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
2792   ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
2793   XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);
2794 
2795   //
2796   // The Device Context Base Address Array entry associated with each allocated Device Slot
2797   // shall contain a 64-bit pointer to the base of the associated Device Context.
2798   // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2799   // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2800   //
2801   Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);
2802   Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);
2803   ASSERT (Dcbaa != NULL);
2804 
2805   //
2806   // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2807   // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2808   // mode (Run/Stop(R/S) ='1').
2809   //
2810   MaxScratchpadBufs      = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
2811   Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
2812   ASSERT (MaxScratchpadBufs <= 1023);
2813   if (MaxScratchpadBufs != 0) {
2814     //
2815     // Allocate the buffer to record the host address for each entry
2816     //
2817     ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
2818     ASSERT (ScratchEntry != NULL);
2819     Xhc->ScratchEntry = ScratchEntry;
2820 
2821     ScratchPhy = 0;
2822     Status = UsbHcAllocateAlignedPages (
2823                EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
2824                Xhc->PageSize,
2825                (VOID **) &ScratchBuf,
2826                &ScratchPhy
2827                );
2828     ASSERT_EFI_ERROR (Status);
2829 
2830     ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
2831     Xhc->ScratchBuf = ScratchBuf;
2832 
2833     //
2834     // Allocate each scratch buffer
2835     //
2836     for (Index = 0; Index < MaxScratchpadBufs; Index++) {
2837       ScratchEntryPhy = 0;
2838       Status = UsbHcAllocateAlignedPages (
2839                  EFI_SIZE_TO_PAGES (Xhc->PageSize),
2840                  Xhc->PageSize,
2841                  (VOID **) &ScratchEntry[Index],
2842                  &ScratchEntryPhy
2843                  );
2844       ASSERT_EFI_ERROR (Status);
2845       ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);
2846       //
2847       // Fill with the PCI device address
2848       //
2849       *ScratchBuf++ = ScratchEntryPhy;
2850     }
2851     //
2852     // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2853     // Device Context Base Address Array points to the Scratchpad Buffer Array.
2854     //
2855     *(UINT64 *) Dcbaa = (UINT64) (UINTN) ScratchPhy;
2856   }
2857 
2858   //
2859   // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2860   // a 64-bit address pointing to where the Device Context Base Address Array is located.
2861   //
2862   Xhc->DCBAA = (UINT64 *) (UINTN) Dcbaa;
2863   //
2864   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2865   // So divide it to two 32-bytes width register access.
2866   //
2867   DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);
2868   XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));
2869   XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
2870 
2871   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));
2872 
2873   //
2874   // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2875   // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
2876   // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
2877   // always be '0'.
2878   //
2879   XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
2880   //
2881   // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
2882   // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
2883   // So we set RCS as inverted PCS init value to let Command Ring empty
2884   //
2885   CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
2886   ASSERT ((CmdRingPhy & 0x3F) == 0);
2887   CmdRingPhy |= XHC_CRCR_RCS;
2888   //
2889   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2890   // So divide it to two 32-bytes width register access.
2891   //
2892   XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));
2893   XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
2894 
2895   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
2896 
2897   //
2898   // Disable the 'interrupter enable' bit in USB_CMD
2899   // and clear IE & IP bit in all Interrupter X Management Registers.
2900   //
2901   XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
2902   for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
2903     XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
2904     XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
2905   }
2906 
2907   //
2908   // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
2909   //
2910   XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);
2911   DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
2912 }
2913 
2914 /**
2915   Free the resouce allocated at initializing schedule.
2916 
2917   @param  Xhc       The XHCI device.
2918 
2919 **/
2920 VOID
XhcPeiFreeSched(IN PEI_XHC_DEV * Xhc)2921 XhcPeiFreeSched (
2922   IN PEI_XHC_DEV    *Xhc
2923   )
2924 {
2925   UINT32                  Index;
2926   UINT64                  *ScratchEntry;
2927 
2928   if (Xhc->ScratchBuf != NULL) {
2929     ScratchEntry = Xhc->ScratchEntry;
2930     for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
2931       //
2932       // Free Scratchpad Buffers
2933       //
2934       UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));
2935     }
2936     //
2937     // Free Scratchpad Buffer Array
2938     //
2939     UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));
2940     FreePool (Xhc->ScratchEntry);
2941   }
2942 
2943   if (Xhc->CmdRing.RingSeg0 != NULL) {
2944     UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
2945     Xhc->CmdRing.RingSeg0 = NULL;
2946   }
2947 
2948   XhcPeiFreeEventRing (Xhc,&Xhc->EventRing);
2949 
2950   if (Xhc->DCBAA != NULL) {
2951     UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));
2952     Xhc->DCBAA = NULL;
2953   }
2954 
2955   //
2956   // Free memory pool at last
2957   //
2958   if (Xhc->MemPool != NULL) {
2959     UsbHcFreeMemPool (Xhc->MemPool);
2960     Xhc->MemPool = NULL;
2961   }
2962 }
2963 
2964