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