1 /** @file
2 
3   XHCI transfer scheduling routines.
4 
5 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "Xhci.h"
11 
12 /**
13   Create a command transfer TRB to support XHCI command interfaces.
14 
15   @param  Xhc       The XHCI Instance.
16   @param  CmdTrb    The cmd TRB to be executed.
17 
18   @return Created URB or NULL.
19 
20 **/
21 URB*
XhcCreateCmdTrb(IN USB_XHCI_INSTANCE * Xhc,IN TRB_TEMPLATE * CmdTrb)22 XhcCreateCmdTrb (
23   IN USB_XHCI_INSTANCE  *Xhc,
24   IN TRB_TEMPLATE       *CmdTrb
25   )
26 {
27   URB    *Urb;
28 
29   Urb = AllocateZeroPool (sizeof (URB));
30   if (Urb == NULL) {
31     return NULL;
32   }
33 
34   Urb->Signature  = XHC_URB_SIG;
35 
36   Urb->Ring       = &Xhc->CmdRing;
37   XhcSyncTrsRing (Xhc, Urb->Ring);
38   Urb->TrbNum     = 1;
39   Urb->TrbStart   = Urb->Ring->RingEnqueue;
40   CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
41   Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
42   Urb->TrbEnd             = Urb->TrbStart;
43 
44   return Urb;
45 }
46 
47 /**
48   Execute a XHCI cmd TRB pointed by CmdTrb.
49 
50   @param  Xhc                   The XHCI Instance.
51   @param  CmdTrb                The cmd TRB to be executed.
52   @param  Timeout               Indicates the maximum time, in millisecond, which the
53                                 transfer is allowed to complete.
54   @param  EvtTrb                The event TRB corresponding to the cmd TRB.
55 
56   @retval EFI_SUCCESS           The transfer was completed successfully.
57   @retval EFI_INVALID_PARAMETER Some parameters are invalid.
58   @retval EFI_TIMEOUT           The transfer failed due to timeout.
59   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
60 
61 **/
62 EFI_STATUS
63 EFIAPI
XhcCmdTransfer(IN USB_XHCI_INSTANCE * Xhc,IN TRB_TEMPLATE * CmdTrb,IN UINTN Timeout,OUT TRB_TEMPLATE ** EvtTrb)64 XhcCmdTransfer (
65   IN  USB_XHCI_INSTANCE     *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 (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
84     DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));
85     goto ON_EXIT;
86   }
87 
88   //
89   // Create a new URB, then poll the execution status.
90   //
91   Urb = XhcCreateCmdTrb (Xhc, CmdTrb);
92 
93   if (Urb == NULL) {
94     DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));
95     Status = EFI_OUT_OF_RESOURCES;
96     goto ON_EXIT;
97   }
98 
99   Status  = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);
100   *EvtTrb = Urb->EvtTrb;
101 
102   if (Urb->Result == EFI_USB_NOERROR) {
103     Status = EFI_SUCCESS;
104   }
105 
106   XhcFreeUrb (Xhc, Urb);
107 
108 ON_EXIT:
109   return Status;
110 }
111 
112 /**
113   Create a new URB for a new transaction.
114 
115   @param  Xhc       The XHCI Instance
116   @param  BusAddr   The logical device address assigned by UsbBus driver
117   @param  EpAddr    Endpoint addrress
118   @param  DevSpeed  The device speed
119   @param  MaxPacket The max packet length of the endpoint
120   @param  Type      The transaction type
121   @param  Request   The standard USB request for control transfer
122   @param  Data      The user data to transfer
123   @param  DataLen   The length of data buffer
124   @param  Callback  The function to call when data is transferred
125   @param  Context   The context to the callback
126 
127   @return Created URB or NULL
128 
129 **/
130 URB*
XhcCreateUrb(IN USB_XHCI_INSTANCE * 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)131 XhcCreateUrb (
132   IN USB_XHCI_INSTANCE                  *Xhc,
133   IN UINT8                              BusAddr,
134   IN UINT8                              EpAddr,
135   IN UINT8                              DevSpeed,
136   IN UINTN                              MaxPacket,
137   IN UINTN                              Type,
138   IN EFI_USB_DEVICE_REQUEST             *Request,
139   IN VOID                               *Data,
140   IN UINTN                              DataLen,
141   IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
142   IN VOID                               *Context
143   )
144 {
145   USB_ENDPOINT                  *Ep;
146   EFI_STATUS                    Status;
147   URB                           *Urb;
148 
149   Urb = AllocateZeroPool (sizeof (URB));
150   if (Urb == NULL) {
151     return NULL;
152   }
153 
154   Urb->Signature = XHC_URB_SIG;
155   InitializeListHead (&Urb->UrbList);
156 
157   Ep            = &Urb->Ep;
158   Ep->BusAddr   = BusAddr;
159   Ep->EpAddr    = (UINT8)(EpAddr & 0x0F);
160   Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
161   Ep->DevSpeed  = DevSpeed;
162   Ep->MaxPacket = MaxPacket;
163   Ep->Type      = Type;
164 
165   Urb->Request  = Request;
166   Urb->Data     = Data;
167   Urb->DataLen  = DataLen;
168   Urb->Callback = Callback;
169   Urb->Context  = Context;
170 
171   Status = XhcCreateTransferTrb (Xhc, Urb);
172   ASSERT_EFI_ERROR (Status);
173   if (EFI_ERROR (Status)) {
174     DEBUG ((EFI_D_ERROR, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status));
175     FreePool (Urb);
176     Urb = NULL;
177   }
178 
179   return Urb;
180 }
181 
182 /**
183   Free an allocated URB.
184 
185   @param  Xhc                   The XHCI device.
186   @param  Urb                   The URB to free.
187 
188 **/
189 VOID
XhcFreeUrb(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)190 XhcFreeUrb (
191   IN USB_XHCI_INSTANCE    *Xhc,
192   IN URB                  *Urb
193   )
194 {
195   if ((Xhc == NULL) || (Urb == NULL)) {
196     return;
197   }
198 
199   if (Urb->DataMap != NULL) {
200     Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);
201   }
202 
203   FreePool (Urb);
204 }
205 
206 /**
207   Create a transfer TRB.
208 
209   @param  Xhc     The XHCI Instance
210   @param  Urb     The urb used to construct the transfer TRB.
211 
212   @return Created TRB or NULL
213 
214 **/
215 EFI_STATUS
XhcCreateTransferTrb(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)216 XhcCreateTransferTrb (
217   IN USB_XHCI_INSTANCE          *Xhc,
218   IN URB                        *Urb
219   )
220 {
221   VOID                          *OutputContext;
222   TRANSFER_RING                 *EPRing;
223   UINT8                         EPType;
224   UINT8                         SlotId;
225   UINT8                         Dci;
226   TRB                           *TrbStart;
227   UINTN                         TotalLen;
228   UINTN                         Len;
229   UINTN                         TrbNum;
230   EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
231   EFI_PHYSICAL_ADDRESS          PhyAddr;
232   VOID                          *Map;
233   EFI_STATUS                    Status;
234 
235   SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
236   if (SlotId == 0) {
237     return EFI_DEVICE_ERROR;
238   }
239 
240   Urb->Finished  = FALSE;
241   Urb->StartDone = FALSE;
242   Urb->EndDone   = FALSE;
243   Urb->Completed = 0;
244   Urb->Result    = EFI_USB_NOERROR;
245 
246   Dci       = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
247   ASSERT (Dci < 32);
248   EPRing    = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
249   Urb->Ring = EPRing;
250   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
251   if (Xhc->HcCParams.Data.Csz == 0) {
252     EPType  = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
253   } else {
254     EPType  = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
255   }
256 
257   //
258   // No need to remap.
259   //
260   if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {
261     if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {
262       MapOp = EfiPciIoOperationBusMasterWrite;
263     } else {
264       MapOp = EfiPciIoOperationBusMasterRead;
265     }
266 
267     Len = Urb->DataLen;
268     Status  = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
269 
270     if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
271       DEBUG ((EFI_D_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
272       return EFI_OUT_OF_RESOURCES;
273     }
274 
275     Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);
276     Urb->DataMap  = Map;
277   }
278 
279   //
280   // Construct the TRB
281   //
282   XhcSyncTrsRing (Xhc, EPRing);
283   Urb->TrbStart = EPRing->RingEnqueue;
284   switch (EPType) {
285     case ED_CONTROL_BIDIR:
286       //
287       // For control transfer, create SETUP_STAGE_TRB first.
288       //
289       TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
290       TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
291       TrbStart->TrbCtrSetup.bRequest      = Urb->Request->Request;
292       TrbStart->TrbCtrSetup.wValue        = Urb->Request->Value;
293       TrbStart->TrbCtrSetup.wIndex        = Urb->Request->Index;
294       TrbStart->TrbCtrSetup.wLength       = Urb->Request->Length;
295       TrbStart->TrbCtrSetup.Length        = 8;
296       TrbStart->TrbCtrSetup.IntTarget     = 0;
297       TrbStart->TrbCtrSetup.IOC           = 1;
298       TrbStart->TrbCtrSetup.IDT           = 1;
299       TrbStart->TrbCtrSetup.Type          = TRB_TYPE_SETUP_STAGE;
300       if (Urb->Ep.Direction == EfiUsbDataIn) {
301         TrbStart->TrbCtrSetup.TRT = 3;
302       } else if (Urb->Ep.Direction == EfiUsbDataOut) {
303         TrbStart->TrbCtrSetup.TRT = 2;
304       } else {
305         TrbStart->TrbCtrSetup.TRT = 0;
306       }
307       //
308       // Update the cycle bit
309       //
310       TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
311       Urb->TrbNum++;
312 
313       //
314       // For control transfer, create DATA_STAGE_TRB.
315       //
316       if (Urb->DataLen > 0) {
317         XhcSyncTrsRing (Xhc, EPRing);
318         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
319         TrbStart->TrbCtrData.TRBPtrLo  = XHC_LOW_32BIT(Urb->DataPhy);
320         TrbStart->TrbCtrData.TRBPtrHi  = XHC_HIGH_32BIT(Urb->DataPhy);
321         TrbStart->TrbCtrData.Length    = (UINT32) Urb->DataLen;
322         TrbStart->TrbCtrData.TDSize    = 0;
323         TrbStart->TrbCtrData.IntTarget = 0;
324         TrbStart->TrbCtrData.ISP       = 1;
325         TrbStart->TrbCtrData.IOC       = 1;
326         TrbStart->TrbCtrData.IDT       = 0;
327         TrbStart->TrbCtrData.CH        = 0;
328         TrbStart->TrbCtrData.Type      = TRB_TYPE_DATA_STAGE;
329         if (Urb->Ep.Direction == EfiUsbDataIn) {
330           TrbStart->TrbCtrData.DIR = 1;
331         } else if (Urb->Ep.Direction == EfiUsbDataOut) {
332           TrbStart->TrbCtrData.DIR = 0;
333         } else {
334           TrbStart->TrbCtrData.DIR = 0;
335         }
336         //
337         // Update the cycle bit
338         //
339         TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
340         Urb->TrbNum++;
341       }
342       //
343       // For control transfer, create STATUS_STAGE_TRB.
344       // Get the pointer to next TRB for status stage use
345       //
346       XhcSyncTrsRing (Xhc, EPRing);
347       TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
348       TrbStart->TrbCtrStatus.IntTarget = 0;
349       TrbStart->TrbCtrStatus.IOC       = 1;
350       TrbStart->TrbCtrStatus.CH        = 0;
351       TrbStart->TrbCtrStatus.Type      = TRB_TYPE_STATUS_STAGE;
352       if (Urb->Ep.Direction == EfiUsbDataIn) {
353         TrbStart->TrbCtrStatus.DIR = 0;
354       } else if (Urb->Ep.Direction == EfiUsbDataOut) {
355         TrbStart->TrbCtrStatus.DIR = 1;
356       } else {
357         TrbStart->TrbCtrStatus.DIR = 0;
358       }
359       //
360       // Update the cycle bit
361       //
362       TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
363       //
364       // Update the enqueue pointer
365       //
366       XhcSyncTrsRing (Xhc, EPRing);
367       Urb->TrbNum++;
368       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
369 
370       break;
371 
372     case ED_BULK_OUT:
373     case ED_BULK_IN:
374       TotalLen = 0;
375       Len      = 0;
376       TrbNum   = 0;
377       TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
378       while (TotalLen < Urb->DataLen) {
379         if ((TotalLen + 0x10000) >= Urb->DataLen) {
380           Len = Urb->DataLen - TotalLen;
381         } else {
382           Len = 0x10000;
383         }
384         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
385         TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
386         TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
387         TrbStart->TrbNormal.Length    = (UINT32) Len;
388         TrbStart->TrbNormal.TDSize    = 0;
389         TrbStart->TrbNormal.IntTarget = 0;
390         TrbStart->TrbNormal.ISP       = 1;
391         TrbStart->TrbNormal.IOC       = 1;
392         TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;
393         //
394         // Update the cycle bit
395         //
396         TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
397 
398         XhcSyncTrsRing (Xhc, EPRing);
399         TrbNum++;
400         TotalLen += Len;
401       }
402 
403       Urb->TrbNum = TrbNum;
404       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
405       break;
406 
407     case ED_INTERRUPT_OUT:
408     case ED_INTERRUPT_IN:
409       TotalLen = 0;
410       Len      = 0;
411       TrbNum   = 0;
412       TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
413       while (TotalLen < Urb->DataLen) {
414         if ((TotalLen + 0x10000) >= Urb->DataLen) {
415           Len = Urb->DataLen - TotalLen;
416         } else {
417           Len = 0x10000;
418         }
419         TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
420         TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
421         TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
422         TrbStart->TrbNormal.Length    = (UINT32) Len;
423         TrbStart->TrbNormal.TDSize    = 0;
424         TrbStart->TrbNormal.IntTarget = 0;
425         TrbStart->TrbNormal.ISP       = 1;
426         TrbStart->TrbNormal.IOC       = 1;
427         TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;
428         //
429         // Update the cycle bit
430         //
431         TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
432 
433         XhcSyncTrsRing (Xhc, EPRing);
434         TrbNum++;
435         TotalLen += Len;
436       }
437 
438       Urb->TrbNum = TrbNum;
439       Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
440       break;
441 
442     default:
443       DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
444       ASSERT (FALSE);
445       break;
446   }
447 
448   return EFI_SUCCESS;
449 }
450 
451 
452 /**
453   Initialize the XHCI host controller for schedule.
454 
455   @param  Xhc        The XHCI Instance to be initialized.
456 
457 **/
458 VOID
XhcInitSched(IN USB_XHCI_INSTANCE * Xhc)459 XhcInitSched (
460   IN USB_XHCI_INSTANCE    *Xhc
461   )
462 {
463   VOID                  *Dcbaa;
464   EFI_PHYSICAL_ADDRESS  DcbaaPhy;
465   UINT64                CmdRing;
466   EFI_PHYSICAL_ADDRESS  CmdRingPhy;
467   UINTN                 Entries;
468   UINT32                MaxScratchpadBufs;
469   UINT64                *ScratchBuf;
470   EFI_PHYSICAL_ADDRESS  ScratchPhy;
471   UINT64                *ScratchEntry;
472   EFI_PHYSICAL_ADDRESS  ScratchEntryPhy;
473   UINT32                Index;
474   UINTN                 *ScratchEntryMap;
475   EFI_STATUS            Status;
476 
477   //
478   // Initialize memory management.
479   //
480   Xhc->MemPool = UsbHcInitMemPool (Xhc->PciIo);
481   ASSERT (Xhc->MemPool != NULL);
482 
483   //
484   // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
485   // to enable the device slots that system software is going to use.
486   //
487   Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
488   ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
489   XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);
490 
491   //
492   // The Device Context Base Address Array entry associated with each allocated Device Slot
493   // shall contain a 64-bit pointer to the base of the associated Device Context.
494   // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
495   // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
496   //
497   Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);
498   Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries);
499   ASSERT (Dcbaa != NULL);
500   ZeroMem (Dcbaa, Entries);
501 
502   //
503   // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
504   // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
505   // mode (Run/Stop(R/S) ='1').
506   //
507   MaxScratchpadBufs      = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
508   Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
509   ASSERT (MaxScratchpadBufs <= 1023);
510   if (MaxScratchpadBufs != 0) {
511     //
512     // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
513     //
514     ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);
515     ASSERT (ScratchEntryMap != NULL);
516     Xhc->ScratchEntryMap = ScratchEntryMap;
517 
518     //
519     // Allocate the buffer to record the host address for each entry
520     //
521     ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
522     ASSERT (ScratchEntry != NULL);
523     Xhc->ScratchEntry = ScratchEntry;
524 
525     ScratchPhy = 0;
526     Status = UsbHcAllocateAlignedPages (
527                Xhc->PciIo,
528                EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
529                Xhc->PageSize,
530                (VOID **) &ScratchBuf,
531                &ScratchPhy,
532                &Xhc->ScratchMap
533                );
534     ASSERT_EFI_ERROR (Status);
535 
536     ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
537     Xhc->ScratchBuf = ScratchBuf;
538 
539     //
540     // Allocate each scratch buffer
541     //
542     for (Index = 0; Index < MaxScratchpadBufs; Index++) {
543       ScratchEntryPhy = 0;
544       Status = UsbHcAllocateAlignedPages (
545                  Xhc->PciIo,
546                  EFI_SIZE_TO_PAGES (Xhc->PageSize),
547                  Xhc->PageSize,
548                  (VOID **) &ScratchEntry[Index],
549                  &ScratchEntryPhy,
550                  (VOID **) &ScratchEntryMap[Index]
551                  );
552       ASSERT_EFI_ERROR (Status);
553       ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);
554       //
555       // Fill with the PCI device address
556       //
557       *ScratchBuf++ = ScratchEntryPhy;
558     }
559     //
560     // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
561     // Device Context Base Address Array points to the Scratchpad Buffer Array.
562     //
563     *(UINT64 *)Dcbaa = (UINT64)(UINTN) ScratchPhy;
564   }
565 
566   //
567   // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
568   // a 64-bit address pointing to where the Device Context Base Address Array is located.
569   //
570   Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;
571   //
572   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
573   // So divide it to two 32-bytes width register access.
574   //
575   DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);
576   XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(DcbaaPhy));
577   XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
578 
579   DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));
580 
581   //
582   // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
583   // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
584   // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
585   // always be '0'.
586   //
587   CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
588   //
589   // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
590   // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
591   // So we set RCS as inverted PCS init value to let Command Ring empty
592   //
593   CmdRing  = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;
594   CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN) CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
595   ASSERT ((CmdRingPhy & 0x3F) == 0);
596   CmdRingPhy |= XHC_CRCR_RCS;
597   //
598   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
599   // So divide it to two 32-bytes width register access.
600   //
601   XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));
602   XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
603 
604   //
605   // Disable the 'interrupter enable' bit in USB_CMD
606   // and clear IE & IP bit in all Interrupter X Management Registers.
607   //
608   XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
609   for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
610     XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
611     XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
612   }
613 
614   //
615   // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
616   //
617   CreateEventRing (Xhc, &Xhc->EventRing);
618   DEBUG ((DEBUG_INFO, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",
619     Xhc->CmdRing.RingSeg0,        (UINTN)Xhc->CmdRing.RingSeg0 + sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER,
620     Xhc->EventRing.EventRingSeg0, (UINTN)Xhc->EventRing.EventRingSeg0 + sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
621     ));
622 }
623 
624 /**
625   System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
626   condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
627   Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
628   reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
629   Stopped to the Running state.
630 
631   @param  Xhc                   The XHCI Instance.
632   @param  Urb                   The urb which makes the endpoint halted.
633 
634   @retval EFI_SUCCESS           The recovery is successful.
635   @retval Others                Failed to recovery halted endpoint.
636 
637 **/
638 EFI_STATUS
639 EFIAPI
XhcRecoverHaltedEndpoint(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)640 XhcRecoverHaltedEndpoint (
641   IN  USB_XHCI_INSTANCE   *Xhc,
642   IN  URB                 *Urb
643   )
644 {
645   EFI_STATUS                  Status;
646   UINT8                       Dci;
647   UINT8                       SlotId;
648 
649   Status = EFI_SUCCESS;
650   SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
651   if (SlotId == 0) {
652     return EFI_DEVICE_ERROR;
653   }
654   Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
655   ASSERT (Dci < 32);
656 
657   DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));
658 
659   //
660   // 1) Send Reset endpoint command to transit from halt to stop state
661   //
662   Status = XhcResetEndpoint(Xhc, SlotId, Dci);
663   if (EFI_ERROR(Status)) {
664     DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
665     goto Done;
666   }
667 
668   //
669   // 2)Set dequeue pointer
670   //
671   Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);
672   if (EFI_ERROR(Status)) {
673     DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));
674     goto Done;
675   }
676 
677   //
678   // 3)Ring the doorbell to transit from stop to active
679   //
680   XhcRingDoorBell (Xhc, SlotId, Dci);
681 
682 Done:
683   return Status;
684 }
685 
686 /**
687   System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
688   Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
689   the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
690   state.
691 
692   @param  Xhc                   The XHCI Instance.
693   @param  Urb                   The urb which doesn't get completed in a specified timeout range.
694 
695   @retval EFI_SUCCESS           The dequeuing of the TDs is successful.
696   @retval EFI_ALREADY_STARTED   The Urb is finished so no deque is needed.
697   @retval Others                Failed to stop the endpoint and dequeue the TDs.
698 
699 **/
700 EFI_STATUS
701 EFIAPI
XhcDequeueTrbFromEndpoint(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)702 XhcDequeueTrbFromEndpoint (
703   IN  USB_XHCI_INSTANCE   *Xhc,
704   IN  URB                 *Urb
705   )
706 {
707   EFI_STATUS                  Status;
708   UINT8                       Dci;
709   UINT8                       SlotId;
710 
711   Status = EFI_SUCCESS;
712   SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
713   if (SlotId == 0) {
714     return EFI_DEVICE_ERROR;
715   }
716   Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
717   ASSERT (Dci < 32);
718 
719   DEBUG ((EFI_D_INFO, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));
720 
721   //
722   // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
723   //
724   Status = XhcStopEndpoint(Xhc, SlotId, Dci, Urb);
725   if (EFI_ERROR(Status)) {
726     DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
727     goto Done;
728   }
729 
730   //
731   // 2)Set dequeue pointer
732   //
733   if (Urb->Finished && Urb->Result == EFI_USB_NOERROR) {
734     //
735     // Return Already Started to indicate the pending URB is finished.
736     // This fixes BULK data loss when transfer is detected as timeout
737     // but finished just before stopping endpoint.
738     //
739     Status = EFI_ALREADY_STARTED;
740     DEBUG ((DEBUG_INFO, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb->Completed, Urb->DataLen));
741   } else {
742     Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);
743     if (EFI_ERROR (Status)) {
744       DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));
745       goto Done;
746     }
747   }
748 
749   //
750   // 3)Ring the doorbell to transit from stop to active
751   //
752   XhcRingDoorBell (Xhc, SlotId, Dci);
753 
754 Done:
755   return Status;
756 }
757 
758 /**
759   Create XHCI event ring.
760 
761   @param  Xhc                 The XHCI Instance.
762   @param  EventRing           The created event ring.
763 
764 **/
765 VOID
CreateEventRing(IN USB_XHCI_INSTANCE * Xhc,OUT EVENT_RING * EventRing)766 CreateEventRing (
767   IN  USB_XHCI_INSTANCE     *Xhc,
768   OUT EVENT_RING            *EventRing
769   )
770 {
771   VOID                        *Buf;
772   EVENT_RING_SEG_TABLE_ENTRY  *ERSTBase;
773   UINTN                       Size;
774   EFI_PHYSICAL_ADDRESS        ERSTPhy;
775   EFI_PHYSICAL_ADDRESS        DequeuePhy;
776 
777   ASSERT (EventRing != NULL);
778 
779   Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
780   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
781   ASSERT (Buf != NULL);
782   ASSERT (((UINTN) Buf & 0x3F) == 0);
783   ZeroMem (Buf, Size);
784 
785   EventRing->EventRingSeg0    = Buf;
786   EventRing->TrbNumber        = EVENT_RING_TRB_NUMBER;
787   EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
788   EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
789 
790   DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
791 
792   //
793   // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
794   // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
795   //
796   EventRing->EventRingCCS = 1;
797 
798   Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
799   Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
800   ASSERT (Buf != NULL);
801   ASSERT (((UINTN) Buf & 0x3F) == 0);
802   ZeroMem (Buf, Size);
803 
804   ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
805   EventRing->ERSTBase   = ERSTBase;
806   ERSTBase->PtrLo       = XHC_LOW_32BIT (DequeuePhy);
807   ERSTBase->PtrHi       = XHC_HIGH_32BIT (DequeuePhy);
808   ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
809 
810   ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);
811 
812   //
813   // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
814   //
815   XhcWriteRuntimeReg (
816     Xhc,
817     XHC_ERSTSZ_OFFSET,
818     ERST_NUMBER
819     );
820   //
821   // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
822   //
823   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
824   // So divide it to two 32-bytes width register access.
825   //
826   XhcWriteRuntimeReg (
827     Xhc,
828     XHC_ERDP_OFFSET,
829     XHC_LOW_32BIT((UINT64)(UINTN)DequeuePhy)
830     );
831   XhcWriteRuntimeReg (
832     Xhc,
833     XHC_ERDP_OFFSET + 4,
834     XHC_HIGH_32BIT((UINT64)(UINTN)DequeuePhy)
835     );
836   //
837   // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
838   //
839   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
840   // So divide it to two 32-bytes width register access.
841   //
842   XhcWriteRuntimeReg (
843     Xhc,
844     XHC_ERSTBA_OFFSET,
845     XHC_LOW_32BIT((UINT64)(UINTN)ERSTPhy)
846     );
847   XhcWriteRuntimeReg (
848     Xhc,
849     XHC_ERSTBA_OFFSET + 4,
850     XHC_HIGH_32BIT((UINT64)(UINTN)ERSTPhy)
851     );
852   //
853   // Need set IMAN IE bit to enble the ring interrupt
854   //
855   XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
856 }
857 
858 /**
859   Create XHCI transfer ring.
860 
861   @param  Xhc               The XHCI Instance.
862   @param  TrbNum            The number of TRB in the ring.
863   @param  TransferRing           The created transfer ring.
864 
865 **/
866 VOID
CreateTransferRing(IN USB_XHCI_INSTANCE * Xhc,IN UINTN TrbNum,OUT TRANSFER_RING * TransferRing)867 CreateTransferRing (
868   IN  USB_XHCI_INSTANCE     *Xhc,
869   IN  UINTN                 TrbNum,
870   OUT TRANSFER_RING         *TransferRing
871   )
872 {
873   VOID                  *Buf;
874   LINK_TRB              *EndTrb;
875   EFI_PHYSICAL_ADDRESS  PhyAddr;
876 
877   Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
878   ASSERT (Buf != NULL);
879   ASSERT (((UINTN) Buf & 0x3F) == 0);
880   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
881 
882   TransferRing->RingSeg0     = Buf;
883   TransferRing->TrbNumber    = TrbNum;
884   TransferRing->RingEnqueue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
885   TransferRing->RingDequeue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;
886   TransferRing->RingPCS      = 1;
887   //
888   // 4.9.2 Transfer Ring Management
889   // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
890   // point to the first TRB in the ring.
891   //
892   EndTrb        = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
893   EndTrb->Type  = TRB_TYPE_LINK;
894   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
895   EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
896   EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
897   //
898   // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
899   //
900   EndTrb->TC    = 1;
901   //
902   // Set Cycle bit as other TRB PCS init value
903   //
904   EndTrb->CycleBit = 0;
905 }
906 
907 /**
908   Free XHCI event ring.
909 
910   @param  Xhc                 The XHCI Instance.
911   @param  EventRing           The event ring to be freed.
912 
913 **/
914 EFI_STATUS
915 EFIAPI
XhcFreeEventRing(IN USB_XHCI_INSTANCE * Xhc,IN EVENT_RING * EventRing)916 XhcFreeEventRing (
917   IN  USB_XHCI_INSTANCE   *Xhc,
918   IN  EVENT_RING          *EventRing
919 )
920 {
921   if(EventRing->EventRingSeg0 == NULL) {
922     return EFI_SUCCESS;
923   }
924 
925   //
926   // Free EventRing Segment 0
927   //
928   UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
929 
930   //
931   // Free ESRT table
932   //
933   UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
934   return EFI_SUCCESS;
935 }
936 
937 /**
938   Free the resouce allocated at initializing schedule.
939 
940   @param  Xhc        The XHCI Instance.
941 
942 **/
943 VOID
XhcFreeSched(IN USB_XHCI_INSTANCE * Xhc)944 XhcFreeSched (
945   IN USB_XHCI_INSTANCE    *Xhc
946   )
947 {
948   UINT32                  Index;
949   UINT64                  *ScratchEntry;
950 
951   if (Xhc->ScratchBuf != NULL) {
952     ScratchEntry = Xhc->ScratchEntry;
953     for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
954       //
955       // Free Scratchpad Buffers
956       //
957       UsbHcFreeAlignedPages (Xhc->PciIo, (VOID*)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);
958     }
959     //
960     // Free Scratchpad Buffer Array
961     //
962     UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);
963     FreePool (Xhc->ScratchEntryMap);
964     FreePool (Xhc->ScratchEntry);
965   }
966 
967   if (Xhc->CmdRing.RingSeg0 != NULL) {
968     UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
969     Xhc->CmdRing.RingSeg0 = NULL;
970   }
971 
972   XhcFreeEventRing (Xhc,&Xhc->EventRing);
973 
974   if (Xhc->DCBAA != NULL) {
975     UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));
976     Xhc->DCBAA = NULL;
977   }
978 
979   //
980   // Free memory pool at last
981   //
982   if (Xhc->MemPool != NULL) {
983     UsbHcFreeMemPool (Xhc->MemPool);
984     Xhc->MemPool = NULL;
985   }
986 }
987 
988 /**
989   Check if the Trb is a transaction of the URB.
990 
991   @param Xhc    The XHCI Instance.
992   @param Trb    The TRB to be checked
993   @param Urb    The URB to be checked.
994 
995   @retval TRUE  It is a transaction of the URB.
996   @retval FALSE It is not any transaction of the URB.
997 
998 **/
999 BOOLEAN
IsTransferRingTrb(IN USB_XHCI_INSTANCE * Xhc,IN TRB_TEMPLATE * Trb,IN URB * Urb)1000 IsTransferRingTrb (
1001   IN  USB_XHCI_INSTANCE   *Xhc,
1002   IN  TRB_TEMPLATE        *Trb,
1003   IN  URB                 *Urb
1004   )
1005 {
1006   LINK_TRB      *LinkTrb;
1007   TRB_TEMPLATE  *CheckedTrb;
1008   UINTN         Index;
1009   EFI_PHYSICAL_ADDRESS PhyAddr;
1010 
1011   CheckedTrb = Urb->TrbStart;
1012   for (Index = 0; Index < Urb->TrbNum; Index++) {
1013     if (Trb == CheckedTrb) {
1014       return TRUE;
1015     }
1016     CheckedTrb++;
1017     //
1018     // If the checked TRB is the link TRB at the end of the transfer ring,
1019     // recircle it to the head of the ring.
1020     //
1021     if (CheckedTrb->Type == TRB_TYPE_LINK) {
1022       LinkTrb = (LINK_TRB *) CheckedTrb;
1023       PhyAddr = (EFI_PHYSICAL_ADDRESS)(LinkTrb->PtrLo | LShiftU64 ((UINT64) LinkTrb->PtrHi, 32));
1024       CheckedTrb = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
1025       ASSERT (CheckedTrb == Urb->Ring->RingSeg0);
1026     }
1027   }
1028 
1029   return FALSE;
1030 }
1031 
1032 /**
1033   Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
1034 
1035   @param Xhc    The XHCI Instance.
1036   @param Trb    The TRB to be checked.
1037   @param Urb    The pointer to the matched Urb.
1038 
1039   @retval TRUE  The Trb is matched with a transaction of the URBs in the async list.
1040   @retval FALSE The Trb is not matched with any URBs in the async list.
1041 
1042 **/
1043 BOOLEAN
IsAsyncIntTrb(IN USB_XHCI_INSTANCE * Xhc,IN TRB_TEMPLATE * Trb,OUT URB ** Urb)1044 IsAsyncIntTrb (
1045   IN  USB_XHCI_INSTANCE   *Xhc,
1046   IN  TRB_TEMPLATE        *Trb,
1047   OUT URB                 **Urb
1048   )
1049 {
1050   LIST_ENTRY              *Entry;
1051   LIST_ENTRY              *Next;
1052   URB                     *CheckedUrb;
1053 
1054   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1055     CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1056     if (IsTransferRingTrb (Xhc, Trb, CheckedUrb)) {
1057       *Urb = CheckedUrb;
1058       return TRUE;
1059     }
1060   }
1061 
1062   return FALSE;
1063 }
1064 
1065 
1066 /**
1067   Check the URB's execution result and update the URB's
1068   result accordingly.
1069 
1070   @param  Xhc             The XHCI Instance.
1071   @param  Urb             The URB to check result.
1072 
1073   @return Whether the result of URB transfer is finialized.
1074 
1075 **/
1076 BOOLEAN
XhcCheckUrbResult(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1077 XhcCheckUrbResult (
1078   IN  USB_XHCI_INSTANCE   *Xhc,
1079   IN  URB                 *Urb
1080   )
1081 {
1082   EVT_TRB_TRANSFER        *EvtTrb;
1083   TRB_TEMPLATE            *TRBPtr;
1084   UINTN                   Index;
1085   UINT8                   TRBType;
1086   EFI_STATUS              Status;
1087   URB                     *AsyncUrb;
1088   URB                     *CheckedUrb;
1089   UINT64                  XhcDequeue;
1090   UINT32                  High;
1091   UINT32                  Low;
1092   EFI_PHYSICAL_ADDRESS    PhyAddr;
1093 
1094   ASSERT ((Xhc != NULL) && (Urb != NULL));
1095 
1096   Status   = EFI_SUCCESS;
1097   AsyncUrb = NULL;
1098 
1099   if (Urb->Finished) {
1100     goto EXIT;
1101   }
1102 
1103   EvtTrb = NULL;
1104 
1105   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1106     Urb->Result |= EFI_USB_ERR_SYSTEM;
1107     goto EXIT;
1108   }
1109 
1110   //
1111   // Traverse the event ring to find out all new events from the previous check.
1112   //
1113   XhcSyncEventRing (Xhc, &Xhc->EventRing);
1114   for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
1115     Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
1116     if (Status == EFI_NOT_READY) {
1117       //
1118       // All new events are handled, return directly.
1119       //
1120       goto EXIT;
1121     }
1122 
1123     //
1124     // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1125     //
1126     if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
1127       continue;
1128     }
1129 
1130     //
1131     // Need convert pci device address to host address
1132     //
1133     PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
1134     TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
1135 
1136     //
1137     // Update the status of URB including the pending URB, the URB that is currently checked,
1138     // and URBs in the XHCI's async interrupt transfer list.
1139     // This way is used to avoid that those completed async transfer events don't get
1140     // handled in time and are flushed by newer coming events.
1141     //
1142     if (Xhc->PendingUrb != NULL && IsTransferRingTrb (Xhc, TRBPtr, Xhc->PendingUrb)) {
1143       CheckedUrb = Xhc->PendingUrb;
1144     } else if (IsTransferRingTrb (Xhc, TRBPtr, Urb)) {
1145       CheckedUrb = Urb;
1146     } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
1147       CheckedUrb = AsyncUrb;
1148     } else {
1149       continue;
1150     }
1151 
1152     switch (EvtTrb->Completecode) {
1153       case TRB_COMPLETION_STALL_ERROR:
1154         CheckedUrb->Result  |= EFI_USB_ERR_STALL;
1155         CheckedUrb->Finished = TRUE;
1156         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1157         goto EXIT;
1158 
1159       case TRB_COMPLETION_BABBLE_ERROR:
1160         CheckedUrb->Result  |= EFI_USB_ERR_BABBLE;
1161         CheckedUrb->Finished = TRUE;
1162         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1163         goto EXIT;
1164 
1165       case TRB_COMPLETION_DATA_BUFFER_ERROR:
1166         CheckedUrb->Result  |= EFI_USB_ERR_BUFFER;
1167         CheckedUrb->Finished = TRUE;
1168         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
1169         goto EXIT;
1170 
1171       case TRB_COMPLETION_USB_TRANSACTION_ERROR:
1172         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
1173         CheckedUrb->Finished = TRUE;
1174         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1175         goto EXIT;
1176 
1177       case TRB_COMPLETION_STOPPED:
1178       case TRB_COMPLETION_STOPPED_LENGTH_INVALID:
1179         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
1180         CheckedUrb->Finished = TRUE;
1181         //
1182         // The pending URB is timeout and force stopped when stopping endpoint.
1183         // Continue the loop to receive the Command Complete Event for stopping endpoint.
1184         //
1185         continue;
1186 
1187       case TRB_COMPLETION_SHORT_PACKET:
1188       case TRB_COMPLETION_SUCCESS:
1189         if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
1190           DEBUG ((EFI_D_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));
1191         }
1192 
1193         TRBType = (UINT8) (TRBPtr->Type);
1194         if ((TRBType == TRB_TYPE_DATA_STAGE) ||
1195             (TRBType == TRB_TYPE_NORMAL) ||
1196             (TRBType == TRB_TYPE_ISOCH)) {
1197           CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
1198         }
1199 
1200         break;
1201 
1202       default:
1203         DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
1204         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
1205         CheckedUrb->Finished = TRUE;
1206         goto EXIT;
1207     }
1208 
1209     //
1210     // Only check first and end Trb event address
1211     //
1212     if (TRBPtr == CheckedUrb->TrbStart) {
1213       CheckedUrb->StartDone = TRUE;
1214     }
1215 
1216     if (TRBPtr == CheckedUrb->TrbEnd) {
1217       CheckedUrb->EndDone = TRUE;
1218     }
1219 
1220     if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
1221       CheckedUrb->Finished = TRUE;
1222       CheckedUrb->EvtTrb   = (TRB_TEMPLATE *)EvtTrb;
1223     }
1224   }
1225 
1226 EXIT:
1227 
1228   //
1229   // Advance event ring to last available entry
1230   //
1231   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1232   // So divide it to two 32-bytes width register access.
1233   //
1234   Low  = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
1235   High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
1236   XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
1237 
1238   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
1239 
1240   if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
1241     //
1242     // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1243     // So divide it to two 32-bytes width register access.
1244     //
1245     XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
1246     XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
1247   }
1248 
1249   return Urb->Finished;
1250 }
1251 
1252 
1253 /**
1254   Execute the transfer by polling the URB. This is a synchronous operation.
1255 
1256   @param  Xhc               The XHCI Instance.
1257   @param  CmdTransfer       The executed URB is for cmd transfer or not.
1258   @param  Urb               The URB to execute.
1259   @param  Timeout           The time to wait before abort, in millisecond.
1260 
1261   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
1262   @return EFI_TIMEOUT       The transfer failed due to time out.
1263   @return EFI_SUCCESS       The transfer finished OK.
1264 
1265 **/
1266 EFI_STATUS
XhcExecTransfer(IN USB_XHCI_INSTANCE * Xhc,IN BOOLEAN CmdTransfer,IN URB * Urb,IN UINTN Timeout)1267 XhcExecTransfer (
1268   IN  USB_XHCI_INSTANCE   *Xhc,
1269   IN  BOOLEAN             CmdTransfer,
1270   IN  URB                 *Urb,
1271   IN  UINTN               Timeout
1272   )
1273 {
1274   EFI_STATUS              Status;
1275   UINTN                   Index;
1276   UINT64                  Loop;
1277   UINT8                   SlotId;
1278   UINT8                   Dci;
1279   BOOLEAN                 Finished;
1280 
1281   if (CmdTransfer) {
1282     SlotId = 0;
1283     Dci    = 0;
1284   } else {
1285     SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1286     if (SlotId == 0) {
1287       return EFI_DEVICE_ERROR;
1288     }
1289     Dci  = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1290     ASSERT (Dci < 32);
1291   }
1292 
1293   Status = EFI_SUCCESS;
1294   Loop   = Timeout * XHC_1_MILLISECOND;
1295   if (Timeout == 0) {
1296     Loop = 0xFFFFFFFF;
1297   }
1298 
1299   XhcRingDoorBell (Xhc, SlotId, Dci);
1300 
1301   for (Index = 0; Index < Loop; Index++) {
1302     Finished = XhcCheckUrbResult (Xhc, Urb);
1303     if (Finished) {
1304       break;
1305     }
1306     gBS->Stall (XHC_1_MICROSECOND);
1307   }
1308 
1309   if (Index == Loop) {
1310     Urb->Result = EFI_USB_ERR_TIMEOUT;
1311     Status      = EFI_TIMEOUT;
1312   } else if (Urb->Result != EFI_USB_NOERROR) {
1313     Status      = EFI_DEVICE_ERROR;
1314   }
1315 
1316   return Status;
1317 }
1318 
1319 /**
1320   Delete a single asynchronous interrupt transfer for
1321   the device and endpoint.
1322 
1323   @param  Xhc                   The XHCI Instance.
1324   @param  BusAddr               The logical device address assigned by UsbBus driver.
1325   @param  EpNum                 The endpoint of the target.
1326 
1327   @retval EFI_SUCCESS           An asynchronous transfer is removed.
1328   @retval EFI_NOT_FOUND         No transfer for the device is found.
1329 
1330 **/
1331 EFI_STATUS
XhciDelAsyncIntTransfer(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 BusAddr,IN UINT8 EpNum)1332 XhciDelAsyncIntTransfer (
1333   IN  USB_XHCI_INSTANCE   *Xhc,
1334   IN  UINT8               BusAddr,
1335   IN  UINT8               EpNum
1336   )
1337 {
1338   LIST_ENTRY              *Entry;
1339   LIST_ENTRY              *Next;
1340   URB                     *Urb;
1341   EFI_USB_DATA_DIRECTION  Direction;
1342   EFI_STATUS              Status;
1343 
1344   Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
1345   EpNum    &= 0x0F;
1346 
1347   Urb = NULL;
1348 
1349   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1350     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1351     if ((Urb->Ep.BusAddr == BusAddr) &&
1352         (Urb->Ep.EpAddr == EpNum) &&
1353         (Urb->Ep.Direction == Direction)) {
1354       //
1355       // Device doesn't finish the IntTransfer until real data comes
1356       // So the TRB should be removed as well.
1357       //
1358       Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);
1359       if (EFI_ERROR (Status)) {
1360         DEBUG ((EFI_D_ERROR, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1361       }
1362 
1363       RemoveEntryList (&Urb->UrbList);
1364       FreePool (Urb->Data);
1365       XhcFreeUrb (Xhc, Urb);
1366       return EFI_SUCCESS;
1367     }
1368   }
1369 
1370   return EFI_NOT_FOUND;
1371 }
1372 
1373 /**
1374   Remove all the asynchronous interrutp transfers.
1375 
1376   @param  Xhc    The XHCI Instance.
1377 
1378 **/
1379 VOID
XhciDelAllAsyncIntTransfers(IN USB_XHCI_INSTANCE * Xhc)1380 XhciDelAllAsyncIntTransfers (
1381   IN USB_XHCI_INSTANCE    *Xhc
1382   )
1383 {
1384   LIST_ENTRY              *Entry;
1385   LIST_ENTRY              *Next;
1386   URB                     *Urb;
1387   EFI_STATUS              Status;
1388 
1389   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1390     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1391 
1392     //
1393     // Device doesn't finish the IntTransfer until real data comes
1394     // So the TRB should be removed as well.
1395     //
1396     Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);
1397     if (EFI_ERROR (Status)) {
1398       DEBUG ((EFI_D_ERROR, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
1399     }
1400 
1401     RemoveEntryList (&Urb->UrbList);
1402     FreePool (Urb->Data);
1403     XhcFreeUrb (Xhc, Urb);
1404   }
1405 }
1406 
1407 /**
1408   Insert a single asynchronous interrupt transfer for
1409   the device and endpoint.
1410 
1411   @param Xhc            The XHCI Instance
1412   @param BusAddr        The logical device address assigned by UsbBus driver
1413   @param EpAddr         Endpoint addrress
1414   @param DevSpeed       The device speed
1415   @param MaxPacket      The max packet length of the endpoint
1416   @param DataLen        The length of data buffer
1417   @param Callback       The function to call when data is transferred
1418   @param Context        The context to the callback
1419 
1420   @return Created URB or NULL
1421 
1422 **/
1423 URB *
XhciInsertAsyncIntTransfer(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 BusAddr,IN UINT8 EpAddr,IN UINT8 DevSpeed,IN UINTN MaxPacket,IN UINTN DataLen,IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,IN VOID * Context)1424 XhciInsertAsyncIntTransfer (
1425   IN USB_XHCI_INSTANCE                  *Xhc,
1426   IN UINT8                              BusAddr,
1427   IN UINT8                              EpAddr,
1428   IN UINT8                              DevSpeed,
1429   IN UINTN                              MaxPacket,
1430   IN UINTN                              DataLen,
1431   IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
1432   IN VOID                               *Context
1433   )
1434 {
1435   VOID      *Data;
1436   URB       *Urb;
1437 
1438   Data = AllocateZeroPool (DataLen);
1439   if (Data == NULL) {
1440     DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));
1441     return NULL;
1442   }
1443 
1444   Urb = XhcCreateUrb (
1445           Xhc,
1446           BusAddr,
1447           EpAddr,
1448           DevSpeed,
1449           MaxPacket,
1450           XHC_INT_TRANSFER_ASYNC,
1451           NULL,
1452           Data,
1453           DataLen,
1454           Callback,
1455           Context
1456           );
1457   if (Urb == NULL) {
1458     DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));
1459     FreePool (Data);
1460     return NULL;
1461   }
1462 
1463   //
1464   // New asynchronous transfer must inserted to the head.
1465   // Check the comments in XhcMoniteAsyncRequests
1466   //
1467   InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);
1468 
1469   return Urb;
1470 }
1471 
1472 /**
1473   Update the queue head for next round of asynchronous transfer
1474 
1475   @param  Xhc     The XHCI Instance.
1476   @param  Urb     The URB to update
1477 
1478 **/
1479 VOID
XhcUpdateAsyncRequest(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1480 XhcUpdateAsyncRequest (
1481   IN USB_XHCI_INSTANCE        *Xhc,
1482   IN URB                      *Urb
1483   )
1484 {
1485   EFI_STATUS    Status;
1486 
1487   if (Urb->Result == EFI_USB_NOERROR) {
1488     Status = XhcCreateTransferTrb (Xhc, Urb);
1489     if (EFI_ERROR (Status)) {
1490       return;
1491     }
1492     Status = RingIntTransferDoorBell (Xhc, Urb);
1493     if (EFI_ERROR (Status)) {
1494       return;
1495     }
1496   }
1497 }
1498 
1499 /**
1500   Flush data from PCI controller specific address to mapped system
1501   memory address.
1502 
1503   @param  Xhc                The XHCI device.
1504   @param  Urb                The URB to unmap.
1505 
1506   @retval EFI_SUCCESS        Success to flush data to mapped system memory.
1507   @retval EFI_DEVICE_ERROR   Fail to flush data to mapped system memory.
1508 
1509 **/
1510 EFI_STATUS
XhcFlushAsyncIntMap(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1511 XhcFlushAsyncIntMap (
1512   IN  USB_XHCI_INSTANCE   *Xhc,
1513   IN  URB                 *Urb
1514   )
1515 {
1516   EFI_STATUS                    Status;
1517   EFI_PHYSICAL_ADDRESS          PhyAddr;
1518   EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
1519   EFI_PCI_IO_PROTOCOL           *PciIo;
1520   UINTN                         Len;
1521   VOID                          *Map;
1522 
1523   PciIo = Xhc->PciIo;
1524   Len   = Urb->DataLen;
1525 
1526   if (Urb->Ep.Direction == EfiUsbDataIn) {
1527     MapOp = EfiPciIoOperationBusMasterWrite;
1528   } else {
1529     MapOp = EfiPciIoOperationBusMasterRead;
1530   }
1531 
1532   if (Urb->DataMap != NULL) {
1533     Status = PciIo->Unmap (PciIo, Urb->DataMap);
1534     if (EFI_ERROR (Status)) {
1535       goto ON_ERROR;
1536     }
1537   }
1538 
1539   Urb->DataMap = NULL;
1540 
1541   Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
1542   if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
1543     goto ON_ERROR;
1544   }
1545 
1546   Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);
1547   Urb->DataMap  = Map;
1548   return EFI_SUCCESS;
1549 
1550 ON_ERROR:
1551   return EFI_DEVICE_ERROR;
1552 }
1553 
1554 /**
1555   Interrupt transfer periodic check handler.
1556 
1557   @param  Event                 Interrupt event.
1558   @param  Context               Pointer to USB_XHCI_INSTANCE.
1559 
1560 **/
1561 VOID
1562 EFIAPI
XhcMonitorAsyncRequests(IN EFI_EVENT Event,IN VOID * Context)1563 XhcMonitorAsyncRequests (
1564   IN EFI_EVENT            Event,
1565   IN VOID                 *Context
1566   )
1567 {
1568   USB_XHCI_INSTANCE       *Xhc;
1569   LIST_ENTRY              *Entry;
1570   LIST_ENTRY              *Next;
1571   UINT8                   *ProcBuf;
1572   URB                     *Urb;
1573   UINT8                   SlotId;
1574   EFI_STATUS              Status;
1575   EFI_TPL                 OldTpl;
1576 
1577   OldTpl = gBS->RaiseTPL (XHC_TPL);
1578 
1579   Xhc    = (USB_XHCI_INSTANCE*) Context;
1580 
1581   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1582     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1583 
1584     //
1585     // Make sure that the device is available before every check.
1586     //
1587     SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1588     if (SlotId == 0) {
1589       continue;
1590     }
1591 
1592     //
1593     // Check the result of URB execution. If it is still
1594     // active, check the next one.
1595     //
1596     XhcCheckUrbResult (Xhc, Urb);
1597 
1598     if (!Urb->Finished) {
1599       continue;
1600     }
1601 
1602     //
1603     // Flush any PCI posted write transactions from a PCI host
1604     // bridge to system memory.
1605     //
1606     Status = XhcFlushAsyncIntMap (Xhc, Urb);
1607     if (EFI_ERROR (Status)) {
1608       DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1609     }
1610 
1611     //
1612     // Allocate a buffer then copy the transferred data for user.
1613     // If failed to allocate the buffer, update the URB for next
1614     // round of transfer. Ignore the data of this round.
1615     //
1616     ProcBuf = NULL;
1617     if (Urb->Result == EFI_USB_NOERROR) {
1618       //
1619       // Make sure the data received from HW is no more than expected.
1620       //
1621       if (Urb->Completed <= Urb->DataLen) {
1622         ProcBuf = AllocateZeroPool (Urb->Completed);
1623       }
1624 
1625       if (ProcBuf == NULL) {
1626         XhcUpdateAsyncRequest (Xhc, Urb);
1627         continue;
1628       }
1629 
1630       CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1631     }
1632 
1633     //
1634     // Leave error recovery to its related device driver. A
1635     // common case of the error recovery is to re-submit the
1636     // interrupt transfer which is linked to the head of the
1637     // list. This function scans from head to tail. So the
1638     // re-submitted interrupt transfer's callback function
1639     // will not be called again in this round. Don't touch this
1640     // URB after the callback, it may have been removed by the
1641     // callback.
1642     //
1643     if (Urb->Callback != NULL) {
1644       //
1645       // Restore the old TPL, USB bus maybe connect device in
1646       // his callback. Some drivers may has a lower TPL restriction.
1647       //
1648       gBS->RestoreTPL (OldTpl);
1649       (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1650       OldTpl = gBS->RaiseTPL (XHC_TPL);
1651     }
1652 
1653     if (ProcBuf != NULL) {
1654       gBS->FreePool (ProcBuf);
1655     }
1656 
1657     XhcUpdateAsyncRequest (Xhc, Urb);
1658   }
1659   gBS->RestoreTPL (OldTpl);
1660 }
1661 
1662 /**
1663   Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1664 
1665   @param  Xhc                   The XHCI Instance.
1666   @param  ParentRouteChart      The route string pointed to the parent device if it exists.
1667   @param  Port                  The port to be polled.
1668   @param  PortState             The port state.
1669 
1670   @retval EFI_SUCCESS           Successfully enable/disable device slot according to port state.
1671   @retval Others                Should not appear.
1672 
1673 **/
1674 EFI_STATUS
1675 EFIAPI
XhcPollPortStatusChange(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT8 Port,IN EFI_USB_PORT_STATUS * PortState)1676 XhcPollPortStatusChange (
1677   IN  USB_XHCI_INSTANCE     *Xhc,
1678   IN  USB_DEV_ROUTE         ParentRouteChart,
1679   IN  UINT8                 Port,
1680   IN  EFI_USB_PORT_STATUS   *PortState
1681   )
1682 {
1683   EFI_STATUS        Status;
1684   UINT8             Speed;
1685   UINT8             SlotId;
1686   USB_DEV_ROUTE     RouteChart;
1687 
1688   Status = EFI_SUCCESS;
1689 
1690   if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
1691     return EFI_SUCCESS;
1692   }
1693 
1694   if (ParentRouteChart.Dword == 0) {
1695     RouteChart.Route.RouteString = 0;
1696     RouteChart.Route.RootPortNum = Port + 1;
1697     RouteChart.Route.TierNum     = 1;
1698   } else {
1699     if(Port < 14) {
1700       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
1701     } else {
1702       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
1703     }
1704     RouteChart.Route.RootPortNum   = ParentRouteChart.Route.RootPortNum;
1705     RouteChart.Route.TierNum       = ParentRouteChart.Route.TierNum + 1;
1706   }
1707 
1708   SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1709   if (SlotId != 0) {
1710     if (Xhc->HcCParams.Data.Csz == 0) {
1711       Status = XhcDisableSlotCmd (Xhc, SlotId);
1712     } else {
1713       Status = XhcDisableSlotCmd64 (Xhc, SlotId);
1714     }
1715   }
1716 
1717   if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
1718       ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
1719     //
1720     // Has a device attached, Identify device speed after port is enabled.
1721     //
1722     Speed = EFI_USB_SPEED_FULL;
1723     if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
1724       Speed = EFI_USB_SPEED_LOW;
1725     } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
1726       Speed = EFI_USB_SPEED_HIGH;
1727     } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
1728       Speed = EFI_USB_SPEED_SUPER;
1729     }
1730     //
1731     // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1732     //
1733     SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1734     if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
1735       if (Xhc->HcCParams.Data.Csz == 0) {
1736         Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1737       } else {
1738         Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1739       }
1740     }
1741   }
1742 
1743   return Status;
1744 }
1745 
1746 
1747 /**
1748   Calculate the device context index by endpoint address and direction.
1749 
1750   @param  EpAddr              The target endpoint number.
1751   @param  Direction           The direction of the target endpoint.
1752 
1753   @return The device context index of endpoint.
1754 
1755 **/
1756 UINT8
XhcEndpointToDci(IN UINT8 EpAddr,IN UINT8 Direction)1757 XhcEndpointToDci (
1758   IN  UINT8                   EpAddr,
1759   IN  UINT8                   Direction
1760   )
1761 {
1762   UINT8 Index;
1763 
1764   if (EpAddr == 0) {
1765     return 1;
1766   } else {
1767     Index = (UINT8) (2 * EpAddr);
1768     if (Direction == EfiUsbDataIn) {
1769       Index += 1;
1770     }
1771     return Index;
1772   }
1773 }
1774 
1775 /**
1776   Find out the actual device address according to the requested device address from UsbBus.
1777 
1778   @param  Xhc             The XHCI Instance.
1779   @param  BusDevAddr      The requested device address by UsbBus upper driver.
1780 
1781   @return The actual device address assigned to the device.
1782 
1783 **/
1784 UINT8
1785 EFIAPI
XhcBusDevAddrToSlotId(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 BusDevAddr)1786 XhcBusDevAddrToSlotId (
1787   IN  USB_XHCI_INSTANCE  *Xhc,
1788   IN  UINT8              BusDevAddr
1789   )
1790 {
1791   UINT8  Index;
1792 
1793   for (Index = 0; Index < 255; Index++) {
1794     if (Xhc->UsbDevContext[Index + 1].Enabled &&
1795         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1796         (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
1797       break;
1798     }
1799   }
1800 
1801   if (Index == 255) {
1802     return 0;
1803   }
1804 
1805   return Xhc->UsbDevContext[Index + 1].SlotId;
1806 }
1807 
1808 /**
1809   Find out the slot id according to the device's route string.
1810 
1811   @param  Xhc             The XHCI Instance.
1812   @param  RouteString     The route string described the device location.
1813 
1814   @return The slot id used by the device.
1815 
1816 **/
1817 UINT8
1818 EFIAPI
XhcRouteStringToSlotId(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE RouteString)1819 XhcRouteStringToSlotId (
1820   IN  USB_XHCI_INSTANCE  *Xhc,
1821   IN  USB_DEV_ROUTE      RouteString
1822   )
1823 {
1824   UINT8  Index;
1825 
1826   for (Index = 0; Index < 255; Index++) {
1827     if (Xhc->UsbDevContext[Index + 1].Enabled &&
1828         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1829         (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
1830       break;
1831     }
1832   }
1833 
1834   if (Index == 255) {
1835     return 0;
1836   }
1837 
1838   return Xhc->UsbDevContext[Index + 1].SlotId;
1839 }
1840 
1841 /**
1842   Synchronize the specified event ring to update the enqueue and dequeue pointer.
1843 
1844   @param  Xhc         The XHCI Instance.
1845   @param  EvtRing     The event ring to sync.
1846 
1847   @retval EFI_SUCCESS The event ring is synchronized successfully.
1848 
1849 **/
1850 EFI_STATUS
1851 EFIAPI
XhcSyncEventRing(IN USB_XHCI_INSTANCE * Xhc,IN EVENT_RING * EvtRing)1852 XhcSyncEventRing (
1853   IN USB_XHCI_INSTANCE    *Xhc,
1854   IN EVENT_RING           *EvtRing
1855   )
1856 {
1857   UINTN               Index;
1858   TRB_TEMPLATE        *EvtTrb1;
1859 
1860   ASSERT (EvtRing != NULL);
1861 
1862   //
1863   // Calculate the EventRingEnqueue and EventRingCCS.
1864   // Note: only support single Segment
1865   //
1866   EvtTrb1 = EvtRing->EventRingDequeue;
1867 
1868   for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
1869     if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
1870       break;
1871     }
1872 
1873     EvtTrb1++;
1874 
1875     if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1876       EvtTrb1 = EvtRing->EventRingSeg0;
1877       EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
1878     }
1879   }
1880 
1881   if (Index < EvtRing->TrbNumber) {
1882     EvtRing->EventRingEnqueue = EvtTrb1;
1883   } else {
1884     ASSERT (FALSE);
1885   }
1886 
1887   return EFI_SUCCESS;
1888 }
1889 
1890 /**
1891   Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1892 
1893   @param  Xhc         The XHCI Instance.
1894   @param  TrsRing     The transfer ring to sync.
1895 
1896   @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1897 
1898 **/
1899 EFI_STATUS
1900 EFIAPI
XhcSyncTrsRing(IN USB_XHCI_INSTANCE * Xhc,IN TRANSFER_RING * TrsRing)1901 XhcSyncTrsRing (
1902   IN USB_XHCI_INSTANCE    *Xhc,
1903   IN TRANSFER_RING        *TrsRing
1904   )
1905 {
1906   UINTN               Index;
1907   TRB_TEMPLATE        *TrsTrb;
1908 
1909   ASSERT (TrsRing != NULL);
1910   //
1911   // Calculate the latest RingEnqueue and RingPCS
1912   //
1913   TrsTrb = TrsRing->RingEnqueue;
1914   ASSERT (TrsTrb != NULL);
1915 
1916   for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
1917     if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
1918       break;
1919     }
1920     TrsTrb++;
1921     if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
1922       ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
1923       //
1924       // set cycle bit in Link TRB as normal
1925       //
1926       ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
1927       //
1928       // Toggle PCS maintained by software
1929       //
1930       TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
1931       TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0;  // Use host address
1932     }
1933   }
1934 
1935   ASSERT (Index != TrsRing->TrbNumber);
1936 
1937   if (TrsTrb != TrsRing->RingEnqueue) {
1938     TrsRing->RingEnqueue = TrsTrb;
1939   }
1940 
1941   //
1942   // Clear the Trb context for enqueue, but reserve the PCS bit
1943   //
1944   TrsTrb->Parameter1 = 0;
1945   TrsTrb->Parameter2 = 0;
1946   TrsTrb->Status     = 0;
1947   TrsTrb->RsvdZ1     = 0;
1948   TrsTrb->Type       = 0;
1949   TrsTrb->Control    = 0;
1950 
1951   return EFI_SUCCESS;
1952 }
1953 
1954 /**
1955   Check if there is a new generated event.
1956 
1957   @param  Xhc           The XHCI Instance.
1958   @param  EvtRing       The event ring to check.
1959   @param  NewEvtTrb     The new event TRB found.
1960 
1961   @retval EFI_SUCCESS   Found a new event TRB at the event ring.
1962   @retval EFI_NOT_READY The event ring has no new event.
1963 
1964 **/
1965 EFI_STATUS
1966 EFIAPI
XhcCheckNewEvent(IN USB_XHCI_INSTANCE * Xhc,IN EVENT_RING * EvtRing,OUT TRB_TEMPLATE ** NewEvtTrb)1967 XhcCheckNewEvent (
1968   IN  USB_XHCI_INSTANCE       *Xhc,
1969   IN  EVENT_RING              *EvtRing,
1970   OUT TRB_TEMPLATE            **NewEvtTrb
1971   )
1972 {
1973   ASSERT (EvtRing != NULL);
1974 
1975   *NewEvtTrb = EvtRing->EventRingDequeue;
1976 
1977   if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
1978     return EFI_NOT_READY;
1979   }
1980 
1981   EvtRing->EventRingDequeue++;
1982   //
1983   // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1984   //
1985   if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1986     EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
1987   }
1988 
1989   return EFI_SUCCESS;
1990 }
1991 
1992 /**
1993   Ring the door bell to notify XHCI there is a transaction to be executed.
1994 
1995   @param  Xhc           The XHCI Instance.
1996   @param  SlotId        The slot id of the target device.
1997   @param  Dci           The device context index of the target slot or endpoint.
1998 
1999   @retval EFI_SUCCESS   Successfully ring the door bell.
2000 
2001 **/
2002 EFI_STATUS
2003 EFIAPI
XhcRingDoorBell(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci)2004 XhcRingDoorBell (
2005   IN USB_XHCI_INSTANCE    *Xhc,
2006   IN UINT8                SlotId,
2007   IN UINT8                Dci
2008   )
2009 {
2010   if (SlotId == 0) {
2011     XhcWriteDoorBellReg (Xhc, 0, 0);
2012   } else {
2013     XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
2014   }
2015 
2016   return EFI_SUCCESS;
2017 }
2018 
2019 /**
2020   Ring the door bell to notify XHCI there is a transaction to be executed through URB.
2021 
2022   @param  Xhc           The XHCI Instance.
2023   @param  Urb           The URB to be rung.
2024 
2025   @retval EFI_SUCCESS   Successfully ring the door bell.
2026 
2027 **/
2028 EFI_STATUS
RingIntTransferDoorBell(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)2029 RingIntTransferDoorBell (
2030   IN  USB_XHCI_INSTANCE   *Xhc,
2031   IN  URB                 *Urb
2032   )
2033 {
2034   UINT8                SlotId;
2035   UINT8                Dci;
2036 
2037   SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
2038   Dci    = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
2039   XhcRingDoorBell (Xhc, SlotId, Dci);
2040   return EFI_SUCCESS;
2041 }
2042 
2043 /**
2044   Assign and initialize the device slot for a new device.
2045 
2046   @param  Xhc                 The XHCI Instance.
2047   @param  ParentRouteChart    The route string pointed to the parent device.
2048   @param  ParentPort          The port at which the device is located.
2049   @param  RouteChart          The route string pointed to the device.
2050   @param  DeviceSpeed         The device speed.
2051 
2052   @retval EFI_SUCCESS   Successfully assign a slot to the device and assign an address to it.
2053 
2054 **/
2055 EFI_STATUS
2056 EFIAPI
XhcInitializeDeviceSlot(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)2057 XhcInitializeDeviceSlot (
2058   IN  USB_XHCI_INSTANCE         *Xhc,
2059   IN  USB_DEV_ROUTE             ParentRouteChart,
2060   IN  UINT16                    ParentPort,
2061   IN  USB_DEV_ROUTE             RouteChart,
2062   IN  UINT8                     DeviceSpeed
2063   )
2064 {
2065   EFI_STATUS                  Status;
2066   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2067   INPUT_CONTEXT               *InputContext;
2068   DEVICE_CONTEXT              *OutputContext;
2069   TRANSFER_RING               *EndpointTransferRing;
2070   CMD_TRB_ADDRESS_DEVICE      CmdTrbAddr;
2071   UINT8                       DeviceAddress;
2072   CMD_TRB_ENABLE_SLOT         CmdTrb;
2073   UINT8                       SlotId;
2074   UINT8                       ParentSlotId;
2075   DEVICE_CONTEXT              *ParentDeviceContext;
2076   EFI_PHYSICAL_ADDRESS        PhyAddr;
2077 
2078   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2079   CmdTrb.CycleBit = 1;
2080   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
2081 
2082   Status = XhcCmdTransfer (
2083               Xhc,
2084               (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2085               XHC_GENERIC_TIMEOUT,
2086               (TRB_TEMPLATE **) (UINTN) &EvtTrb
2087               );
2088   if (EFI_ERROR (Status)) {
2089     DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
2090     return Status;
2091   }
2092   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2093   DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2094   SlotId = (UINT8)EvtTrb->SlotId;
2095   ASSERT (SlotId != 0);
2096 
2097   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2098   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
2099   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
2100   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
2101   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2102 
2103   //
2104   // 4.3.3 Device Slot Initialization
2105   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2106   //
2107   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
2108   ASSERT (InputContext != NULL);
2109   ASSERT (((UINTN) InputContext & 0x3F) == 0);
2110   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2111 
2112   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2113 
2114   //
2115   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2116   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2117   //    Context are affected by the command.
2118   //
2119   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2120 
2121   //
2122   // 3) Initialize the Input Slot Context data structure
2123   //
2124   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
2125   InputContext->Slot.Speed          = DeviceSpeed + 1;
2126   InputContext->Slot.ContextEntries = 1;
2127   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2128 
2129   if (RouteChart.Route.RouteString) {
2130     //
2131     // The device is behind of hub device.
2132     //
2133     ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2134     ASSERT (ParentSlotId != 0);
2135     //
2136     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2137     //
2138     ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2139     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2140         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2141       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2142         //
2143         // Full/Low device attached to High speed hub port that isolates the high speed signaling
2144         // environment from Full/Low speed signaling environment for a device
2145         //
2146         InputContext->Slot.TTPortNum   = ParentPort;
2147         InputContext->Slot.TTHubSlotId = ParentSlotId;
2148       }
2149     } else {
2150       //
2151       // Inherit the TT parameters from parent device.
2152       //
2153       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
2154       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2155       //
2156       // If the device is a High speed device then down the speed to be the same as its parent Hub
2157       //
2158       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2159         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2160       }
2161     }
2162   }
2163 
2164   //
2165   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2166   //
2167   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2168   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2169   CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2170   //
2171   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2172   //
2173   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2174 
2175   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2176     InputContext->EP[0].MaxPacketSize = 512;
2177   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2178     InputContext->EP[0].MaxPacketSize = 64;
2179   } else {
2180     InputContext->EP[0].MaxPacketSize = 8;
2181   }
2182   //
2183   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2184   // 1KB, and Bulk and Isoch endpoints 3KB.
2185   //
2186   InputContext->EP[0].AverageTRBLength = 8;
2187   InputContext->EP[0].MaxBurstSize     = 0;
2188   InputContext->EP[0].Interval         = 0;
2189   InputContext->EP[0].MaxPStreams      = 0;
2190   InputContext->EP[0].Mult             = 0;
2191   InputContext->EP[0].CErr             = 3;
2192 
2193   //
2194   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2195   //
2196   PhyAddr = UsbHcGetPciAddrForHostAddr (
2197               Xhc->MemPool,
2198               ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2199               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2200               );
2201   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2202   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2203 
2204   //
2205   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2206   //
2207   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
2208   ASSERT (OutputContext != NULL);
2209   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2210   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
2211 
2212   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2213   //
2214   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2215   //    a pointer to the Output Device Context data structure (6.2.1).
2216   //
2217   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
2218   //
2219   // Fill DCBAA with PCI device address
2220   //
2221   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2222 
2223   //
2224   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2225   //    Context data structure described above.
2226   //
2227   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2228   // to device.
2229   //
2230   gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2231   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2232   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2233   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2234   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2235   CmdTrbAddr.CycleBit = 1;
2236   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
2237   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2238   Status = XhcCmdTransfer (
2239              Xhc,
2240              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2241              XHC_GENERIC_TIMEOUT,
2242              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2243              );
2244   if (!EFI_ERROR (Status)) {
2245     DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
2246     DEBUG ((EFI_D_INFO, "    Address %d assigned successfully\n", DeviceAddress));
2247     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2248   }
2249 
2250   return Status;
2251 }
2252 
2253 /**
2254   Assign and initialize the device slot for a new device.
2255 
2256   @param  Xhc                 The XHCI Instance.
2257   @param  ParentRouteChart    The route string pointed to the parent device.
2258   @param  ParentPort          The port at which the device is located.
2259   @param  RouteChart          The route string pointed to the device.
2260   @param  DeviceSpeed         The device speed.
2261 
2262   @retval EFI_SUCCESS   Successfully assign a slot to the device and assign an address to it.
2263 
2264 **/
2265 EFI_STATUS
2266 EFIAPI
XhcInitializeDeviceSlot64(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)2267 XhcInitializeDeviceSlot64 (
2268   IN  USB_XHCI_INSTANCE         *Xhc,
2269   IN  USB_DEV_ROUTE             ParentRouteChart,
2270   IN  UINT16                    ParentPort,
2271   IN  USB_DEV_ROUTE             RouteChart,
2272   IN  UINT8                     DeviceSpeed
2273   )
2274 {
2275   EFI_STATUS                  Status;
2276   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2277   INPUT_CONTEXT_64            *InputContext;
2278   DEVICE_CONTEXT_64           *OutputContext;
2279   TRANSFER_RING               *EndpointTransferRing;
2280   CMD_TRB_ADDRESS_DEVICE      CmdTrbAddr;
2281   UINT8                       DeviceAddress;
2282   CMD_TRB_ENABLE_SLOT         CmdTrb;
2283   UINT8                       SlotId;
2284   UINT8                       ParentSlotId;
2285   DEVICE_CONTEXT_64           *ParentDeviceContext;
2286   EFI_PHYSICAL_ADDRESS        PhyAddr;
2287 
2288   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2289   CmdTrb.CycleBit = 1;
2290   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
2291 
2292   Status = XhcCmdTransfer (
2293               Xhc,
2294               (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2295               XHC_GENERIC_TIMEOUT,
2296               (TRB_TEMPLATE **) (UINTN) &EvtTrb
2297               );
2298   if (EFI_ERROR (Status)) {
2299     DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
2300     return Status;
2301   }
2302   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2303   DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2304   SlotId = (UINT8)EvtTrb->SlotId;
2305   ASSERT (SlotId != 0);
2306 
2307   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2308   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
2309   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
2310   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
2311   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2312 
2313   //
2314   // 4.3.3 Device Slot Initialization
2315   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2316   //
2317   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
2318   ASSERT (InputContext != NULL);
2319   ASSERT (((UINTN) InputContext & 0x3F) == 0);
2320   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2321 
2322   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2323 
2324   //
2325   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2326   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2327   //    Context are affected by the command.
2328   //
2329   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2330 
2331   //
2332   // 3) Initialize the Input Slot Context data structure
2333   //
2334   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
2335   InputContext->Slot.Speed          = DeviceSpeed + 1;
2336   InputContext->Slot.ContextEntries = 1;
2337   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2338 
2339   if (RouteChart.Route.RouteString) {
2340     //
2341     // The device is behind of hub device.
2342     //
2343     ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2344     ASSERT (ParentSlotId != 0);
2345     //
2346     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2347     //
2348     ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2349     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2350         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2351       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2352         //
2353         // Full/Low device attached to High speed hub port that isolates the high speed signaling
2354         // environment from Full/Low speed signaling environment for a device
2355         //
2356         InputContext->Slot.TTPortNum   = ParentPort;
2357         InputContext->Slot.TTHubSlotId = ParentSlotId;
2358       }
2359     } else {
2360       //
2361       // Inherit the TT parameters from parent device.
2362       //
2363       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
2364       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2365       //
2366       // If the device is a High speed device then down the speed to be the same as its parent Hub
2367       //
2368       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2369         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2370       }
2371     }
2372   }
2373 
2374   //
2375   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2376   //
2377   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2378   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2379   CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2380   //
2381   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2382   //
2383   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2384 
2385   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2386     InputContext->EP[0].MaxPacketSize = 512;
2387   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2388     InputContext->EP[0].MaxPacketSize = 64;
2389   } else {
2390     InputContext->EP[0].MaxPacketSize = 8;
2391   }
2392   //
2393   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2394   // 1KB, and Bulk and Isoch endpoints 3KB.
2395   //
2396   InputContext->EP[0].AverageTRBLength = 8;
2397   InputContext->EP[0].MaxBurstSize     = 0;
2398   InputContext->EP[0].Interval         = 0;
2399   InputContext->EP[0].MaxPStreams      = 0;
2400   InputContext->EP[0].Mult             = 0;
2401   InputContext->EP[0].CErr             = 3;
2402 
2403   //
2404   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2405   //
2406   PhyAddr = UsbHcGetPciAddrForHostAddr (
2407               Xhc->MemPool,
2408               ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2409               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2410               );
2411   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2412   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2413 
2414   //
2415   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2416   //
2417   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
2418   ASSERT (OutputContext != NULL);
2419   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2420   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2421 
2422   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2423   //
2424   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2425   //    a pointer to the Output Device Context data structure (6.2.1).
2426   //
2427   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
2428   //
2429   // Fill DCBAA with PCI device address
2430   //
2431   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2432 
2433   //
2434   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2435   //    Context data structure described above.
2436   //
2437   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2438   // to device.
2439   //
2440   gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2441   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2442   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2443   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2444   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2445   CmdTrbAddr.CycleBit = 1;
2446   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
2447   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2448   Status = XhcCmdTransfer (
2449              Xhc,
2450              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2451              XHC_GENERIC_TIMEOUT,
2452              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2453              );
2454   if (!EFI_ERROR (Status)) {
2455     DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2456     DEBUG ((EFI_D_INFO, "    Address %d assigned successfully\n", DeviceAddress));
2457     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2458   }
2459   return Status;
2460 }
2461 
2462 
2463 /**
2464   Disable the specified device slot.
2465 
2466   @param  Xhc           The XHCI Instance.
2467   @param  SlotId        The slot id to be disabled.
2468 
2469   @retval EFI_SUCCESS   Successfully disable the device slot.
2470 
2471 **/
2472 EFI_STATUS
2473 EFIAPI
XhcDisableSlotCmd(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId)2474 XhcDisableSlotCmd (
2475   IN USB_XHCI_INSTANCE         *Xhc,
2476   IN UINT8                     SlotId
2477   )
2478 {
2479   EFI_STATUS            Status;
2480   TRB_TEMPLATE          *EvtTrb;
2481   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
2482   UINT8                 Index;
2483   VOID                  *RingSeg;
2484 
2485   //
2486   // Disable the device slots occupied by these devices on its downstream ports.
2487   // Entry 0 is reserved.
2488   //
2489   for (Index = 0; Index < 255; Index++) {
2490     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2491         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2492         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2493       continue;
2494     }
2495 
2496     Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2497 
2498     if (EFI_ERROR (Status)) {
2499       DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2500       Xhc->UsbDevContext[Index + 1].SlotId = 0;
2501     }
2502   }
2503 
2504   //
2505   // Construct the disable slot command
2506   //
2507   DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2508 
2509   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2510   CmdTrbDisSlot.CycleBit = 1;
2511   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
2512   CmdTrbDisSlot.SlotId   = SlotId;
2513   Status = XhcCmdTransfer (
2514              Xhc,
2515              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2516              XHC_GENERIC_TIMEOUT,
2517              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2518              );
2519   if (EFI_ERROR (Status)) {
2520     DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2521     return Status;
2522   }
2523   //
2524   // Free the slot's device context entry
2525   //
2526   Xhc->DCBAA[SlotId] = 0;
2527 
2528   //
2529   // Free the slot related data structure
2530   //
2531   for (Index = 0; Index < 31; Index++) {
2532     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2533       RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2534       if (RingSeg != NULL) {
2535         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2536       }
2537       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2538       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2539     }
2540   }
2541 
2542   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2543     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2544       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2545     }
2546   }
2547 
2548   if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2549     FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2550   }
2551 
2552   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2553     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2554   }
2555 
2556   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2557     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
2558   }
2559   //
2560   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2561   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2562   // remove urb from XHCI's asynchronous transfer list.
2563   //
2564   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2565   Xhc->UsbDevContext[SlotId].SlotId  = 0;
2566 
2567   return Status;
2568 }
2569 
2570 /**
2571   Disable the specified device slot.
2572 
2573   @param  Xhc           The XHCI Instance.
2574   @param  SlotId        The slot id to be disabled.
2575 
2576   @retval EFI_SUCCESS   Successfully disable the device slot.
2577 
2578 **/
2579 EFI_STATUS
2580 EFIAPI
XhcDisableSlotCmd64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId)2581 XhcDisableSlotCmd64 (
2582   IN USB_XHCI_INSTANCE         *Xhc,
2583   IN UINT8                     SlotId
2584   )
2585 {
2586   EFI_STATUS            Status;
2587   TRB_TEMPLATE          *EvtTrb;
2588   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
2589   UINT8                 Index;
2590   VOID                  *RingSeg;
2591 
2592   //
2593   // Disable the device slots occupied by these devices on its downstream ports.
2594   // Entry 0 is reserved.
2595   //
2596   for (Index = 0; Index < 255; Index++) {
2597     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2598         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2599         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2600       continue;
2601     }
2602 
2603     Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2604 
2605     if (EFI_ERROR (Status)) {
2606       DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2607       Xhc->UsbDevContext[Index + 1].SlotId = 0;
2608     }
2609   }
2610 
2611   //
2612   // Construct the disable slot command
2613   //
2614   DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2615 
2616   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2617   CmdTrbDisSlot.CycleBit = 1;
2618   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
2619   CmdTrbDisSlot.SlotId   = SlotId;
2620   Status = XhcCmdTransfer (
2621              Xhc,
2622              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2623              XHC_GENERIC_TIMEOUT,
2624              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2625              );
2626   if (EFI_ERROR (Status)) {
2627     DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2628     return Status;
2629   }
2630   //
2631   // Free the slot's device context entry
2632   //
2633   Xhc->DCBAA[SlotId] = 0;
2634 
2635   //
2636   // Free the slot related data structure
2637   //
2638   for (Index = 0; Index < 31; Index++) {
2639     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2640       RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2641       if (RingSeg != NULL) {
2642         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2643       }
2644       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2645       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2646     }
2647   }
2648 
2649   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2650     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2651       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2652     }
2653   }
2654 
2655   if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2656     FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2657   }
2658 
2659   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2660     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2661   }
2662 
2663   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2664      UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
2665   }
2666   //
2667   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2668   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2669   // remove urb from XHCI's asynchronous transfer list.
2670   //
2671   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2672   Xhc->UsbDevContext[SlotId].SlotId  = 0;
2673 
2674   return Status;
2675 }
2676 
2677 /**
2678   Initialize endpoint context in input context.
2679 
2680   @param Xhc            The XHCI Instance.
2681   @param SlotId         The slot id to be configured.
2682   @param DeviceSpeed    The device's speed.
2683   @param InputContext   The pointer to the input context.
2684   @param IfDesc         The pointer to the usb device interface descriptor.
2685 
2686   @return The maximum device context index of endpoint.
2687 
2688 **/
2689 UINT8
2690 EFIAPI
XhcInitializeEndpointContext(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN INPUT_CONTEXT * InputContext,IN USB_INTERFACE_DESCRIPTOR * IfDesc)2691 XhcInitializeEndpointContext (
2692   IN USB_XHCI_INSTANCE          *Xhc,
2693   IN UINT8                      SlotId,
2694   IN UINT8                      DeviceSpeed,
2695   IN INPUT_CONTEXT              *InputContext,
2696   IN USB_INTERFACE_DESCRIPTOR   *IfDesc
2697   )
2698 {
2699   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
2700   UINTN                         NumEp;
2701   UINTN                         EpIndex;
2702   UINT8                         EpAddr;
2703   UINT8                         Direction;
2704   UINT8                         Dci;
2705   UINT8                         MaxDci;
2706   EFI_PHYSICAL_ADDRESS          PhyAddr;
2707   UINT8                         Interval;
2708   TRANSFER_RING                 *EndpointTransferRing;
2709 
2710   MaxDci = 0;
2711 
2712   NumEp = IfDesc->NumEndpoints;
2713 
2714   EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2715   for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2716     while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2717       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2718     }
2719 
2720     if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2721       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2722       continue;
2723     }
2724 
2725     EpAddr    = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2726     Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2727 
2728     Dci = XhcEndpointToDci (EpAddr, Direction);
2729     ASSERT (Dci < 32);
2730     if (Dci > MaxDci) {
2731       MaxDci = Dci;
2732     }
2733 
2734     InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2735     InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
2736 
2737     if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2738       //
2739       // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2740       //
2741       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2742     } else {
2743       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2744     }
2745 
2746     switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2747       case USB_ENDPOINT_BULK:
2748         if (Direction == EfiUsbDataIn) {
2749           InputContext->EP[Dci-1].CErr   = 3;
2750           InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2751         } else {
2752           InputContext->EP[Dci-1].CErr   = 3;
2753           InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2754         }
2755 
2756         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2757         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2758           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2759           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2760           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2761           DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2762                   EpDesc->EndpointAddress,
2763                   EndpointTransferRing->RingSeg0,
2764                   (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2765                   ));
2766         }
2767 
2768         break;
2769       case USB_ENDPOINT_ISO:
2770         if (Direction == EfiUsbDataIn) {
2771           InputContext->EP[Dci-1].CErr   = 0;
2772           InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2773         } else {
2774           InputContext->EP[Dci-1].CErr   = 0;
2775           InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2776         }
2777         //
2778         // Get the bInterval from descriptor and init the the interval field of endpoint context.
2779         // Refer to XHCI 1.1 spec section 6.2.3.6.
2780         //
2781         if (DeviceSpeed == EFI_USB_SPEED_FULL) {
2782           Interval = EpDesc->Interval;
2783           ASSERT (Interval >= 1 && Interval <= 16);
2784           InputContext->EP[Dci-1].Interval = Interval + 2;
2785         } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2786           Interval = EpDesc->Interval;
2787           ASSERT (Interval >= 1 && Interval <= 16);
2788           InputContext->EP[Dci-1].Interval = Interval - 1;
2789         }
2790 
2791         //
2792         // Do not support isochronous transfer now.
2793         //
2794         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2795         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2796         continue;
2797       case USB_ENDPOINT_INTERRUPT:
2798         if (Direction == EfiUsbDataIn) {
2799           InputContext->EP[Dci-1].CErr   = 3;
2800           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2801         } else {
2802           InputContext->EP[Dci-1].CErr   = 3;
2803           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2804         }
2805         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2806         InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
2807         //
2808         // Get the bInterval from descriptor and init the the interval field of endpoint context
2809         //
2810         if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2811           Interval = EpDesc->Interval;
2812           //
2813           // Calculate through the bInterval field of Endpoint descriptor.
2814           //
2815           ASSERT (Interval != 0);
2816           InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
2817         } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2818           Interval = EpDesc->Interval;
2819           ASSERT (Interval >= 1 && Interval <= 16);
2820           //
2821           // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2822           //
2823           InputContext->EP[Dci-1].Interval         = Interval - 1;
2824           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2825           InputContext->EP[Dci-1].MaxESITPayload   = 0x0002;
2826           InputContext->EP[Dci-1].MaxBurstSize     = 0x0;
2827           InputContext->EP[Dci-1].CErr             = 3;
2828         }
2829 
2830         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2831           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2832           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2833           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2834           DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2835                   EpDesc->EndpointAddress,
2836                   EndpointTransferRing->RingSeg0,
2837                   (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2838                   ));
2839         }
2840         break;
2841 
2842       case USB_ENDPOINT_CONTROL:
2843         //
2844         // Do not support control transfer now.
2845         //
2846         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2847       default:
2848         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2849         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2850         continue;
2851     }
2852 
2853     PhyAddr = UsbHcGetPciAddrForHostAddr (
2854                 Xhc->MemPool,
2855                 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2856                 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2857                 );
2858     PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2859     PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2860     InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2861     InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2862 
2863     EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2864   }
2865 
2866   return MaxDci;
2867 }
2868 
2869 /**
2870   Initialize endpoint context in input context.
2871 
2872   @param Xhc            The XHCI Instance.
2873   @param SlotId         The slot id to be configured.
2874   @param DeviceSpeed    The device's speed.
2875   @param InputContext   The pointer to the input context.
2876   @param IfDesc         The pointer to the usb device interface descriptor.
2877 
2878   @return The maximum device context index of endpoint.
2879 
2880 **/
2881 UINT8
2882 EFIAPI
XhcInitializeEndpointContext64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN INPUT_CONTEXT_64 * InputContext,IN USB_INTERFACE_DESCRIPTOR * IfDesc)2883 XhcInitializeEndpointContext64 (
2884   IN USB_XHCI_INSTANCE          *Xhc,
2885   IN UINT8                      SlotId,
2886   IN UINT8                      DeviceSpeed,
2887   IN INPUT_CONTEXT_64           *InputContext,
2888   IN USB_INTERFACE_DESCRIPTOR   *IfDesc
2889   )
2890 {
2891   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
2892   UINTN                         NumEp;
2893   UINTN                         EpIndex;
2894   UINT8                         EpAddr;
2895   UINT8                         Direction;
2896   UINT8                         Dci;
2897   UINT8                         MaxDci;
2898   EFI_PHYSICAL_ADDRESS          PhyAddr;
2899   UINT8                         Interval;
2900   TRANSFER_RING                 *EndpointTransferRing;
2901 
2902   MaxDci = 0;
2903 
2904   NumEp = IfDesc->NumEndpoints;
2905 
2906   EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2907   for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2908     while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2909       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2910     }
2911 
2912     if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2913       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2914       continue;
2915     }
2916 
2917     EpAddr    = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2918     Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2919 
2920     Dci = XhcEndpointToDci (EpAddr, Direction);
2921     ASSERT (Dci < 32);
2922     if (Dci > MaxDci) {
2923       MaxDci = Dci;
2924     }
2925 
2926     InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2927     InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
2928 
2929     if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2930       //
2931       // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2932       //
2933       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2934     } else {
2935       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2936     }
2937 
2938     switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2939       case USB_ENDPOINT_BULK:
2940         if (Direction == EfiUsbDataIn) {
2941           InputContext->EP[Dci-1].CErr   = 3;
2942           InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2943         } else {
2944           InputContext->EP[Dci-1].CErr   = 3;
2945           InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2946         }
2947 
2948         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2949         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2950           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2951           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2952           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2953           DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
2954                   EpDesc->EndpointAddress,
2955                   EndpointTransferRing->RingSeg0,
2956                   (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2957                   ));
2958         }
2959 
2960         break;
2961       case USB_ENDPOINT_ISO:
2962         if (Direction == EfiUsbDataIn) {
2963           InputContext->EP[Dci-1].CErr   = 0;
2964           InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2965         } else {
2966           InputContext->EP[Dci-1].CErr   = 0;
2967           InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2968         }
2969         //
2970         // Get the bInterval from descriptor and init the the interval field of endpoint context.
2971         // Refer to XHCI 1.1 spec section 6.2.3.6.
2972         //
2973         if (DeviceSpeed == EFI_USB_SPEED_FULL) {
2974           Interval = EpDesc->Interval;
2975           ASSERT (Interval >= 1 && Interval <= 16);
2976           InputContext->EP[Dci-1].Interval = Interval + 2;
2977         } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2978           Interval = EpDesc->Interval;
2979           ASSERT (Interval >= 1 && Interval <= 16);
2980           InputContext->EP[Dci-1].Interval = Interval - 1;
2981         }
2982 
2983         //
2984         // Do not support isochronous transfer now.
2985         //
2986         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2987         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2988         continue;
2989       case USB_ENDPOINT_INTERRUPT:
2990         if (Direction == EfiUsbDataIn) {
2991           InputContext->EP[Dci-1].CErr   = 3;
2992           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2993         } else {
2994           InputContext->EP[Dci-1].CErr   = 3;
2995           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2996         }
2997         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2998         InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
2999         //
3000         // Get the bInterval from descriptor and init the the interval field of endpoint context
3001         //
3002         if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
3003           Interval = EpDesc->Interval;
3004           //
3005           // Calculate through the bInterval field of Endpoint descriptor.
3006           //
3007           ASSERT (Interval != 0);
3008           InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
3009         } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
3010           Interval = EpDesc->Interval;
3011           ASSERT (Interval >= 1 && Interval <= 16);
3012           //
3013           // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
3014           //
3015           InputContext->EP[Dci-1].Interval         = Interval - 1;
3016           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
3017           InputContext->EP[Dci-1].MaxESITPayload   = 0x0002;
3018           InputContext->EP[Dci-1].MaxBurstSize     = 0x0;
3019           InputContext->EP[Dci-1].CErr             = 3;
3020         }
3021 
3022         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
3023           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
3024           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
3025           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
3026           DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
3027                   EpDesc->EndpointAddress,
3028                   EndpointTransferRing->RingSeg0,
3029                   (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
3030                   ));
3031         }
3032         break;
3033 
3034       case USB_ENDPOINT_CONTROL:
3035         //
3036         // Do not support control transfer now.
3037         //
3038         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
3039       default:
3040         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
3041         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3042         continue;
3043     }
3044 
3045     PhyAddr = UsbHcGetPciAddrForHostAddr (
3046                 Xhc->MemPool,
3047                 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
3048                 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
3049                 );
3050     PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
3051     PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
3052     InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
3053     InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
3054 
3055     EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3056   }
3057 
3058   return MaxDci;
3059 }
3060 
3061 /**
3062   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3063 
3064   @param  Xhc           The XHCI Instance.
3065   @param  SlotId        The slot id to be configured.
3066   @param  DeviceSpeed   The device's speed.
3067   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3068 
3069   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
3070 
3071 **/
3072 EFI_STATUS
3073 EFIAPI
XhcSetConfigCmd(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)3074 XhcSetConfigCmd (
3075   IN USB_XHCI_INSTANCE        *Xhc,
3076   IN UINT8                    SlotId,
3077   IN UINT8                    DeviceSpeed,
3078   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc
3079   )
3080 {
3081   EFI_STATUS                  Status;
3082   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3083   UINT8                       Index;
3084   UINT8                       Dci;
3085   UINT8                       MaxDci;
3086   EFI_PHYSICAL_ADDRESS        PhyAddr;
3087 
3088   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3089   INPUT_CONTEXT               *InputContext;
3090   DEVICE_CONTEXT              *OutputContext;
3091   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3092   //
3093   // 4.6.6 Configure Endpoint
3094   //
3095   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3096   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3097   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3098   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3099 
3100   ASSERT (ConfigDesc != NULL);
3101 
3102   MaxDci = 0;
3103 
3104   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3105   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3106     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3107       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3108     }
3109 
3110     if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3111       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3112       continue;
3113     }
3114 
3115     Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3116     if (Dci > MaxDci) {
3117       MaxDci = Dci;
3118     }
3119 
3120     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3121   }
3122 
3123   InputContext->InputControlContext.Dword2 |= BIT0;
3124   InputContext->Slot.ContextEntries         = MaxDci;
3125   //
3126   // configure endpoint
3127   //
3128   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3129   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3130   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3131   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3132   CmdTrbCfgEP.CycleBit = 1;
3133   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3134   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3135   DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3136   Status = XhcCmdTransfer (
3137              Xhc,
3138              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3139              XHC_GENERIC_TIMEOUT,
3140              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3141              );
3142   if (EFI_ERROR (Status)) {
3143     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
3144   } else {
3145     Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3146   }
3147 
3148   return Status;
3149 }
3150 
3151 /**
3152   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3153 
3154   @param  Xhc           The XHCI Instance.
3155   @param  SlotId        The slot id to be configured.
3156   @param  DeviceSpeed   The device's speed.
3157   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3158 
3159   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
3160 
3161 **/
3162 EFI_STATUS
3163 EFIAPI
XhcSetConfigCmd64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)3164 XhcSetConfigCmd64 (
3165   IN USB_XHCI_INSTANCE        *Xhc,
3166   IN UINT8                    SlotId,
3167   IN UINT8                    DeviceSpeed,
3168   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc
3169   )
3170 {
3171   EFI_STATUS                  Status;
3172   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3173   UINT8                       Index;
3174   UINT8                       Dci;
3175   UINT8                       MaxDci;
3176   EFI_PHYSICAL_ADDRESS        PhyAddr;
3177 
3178   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3179   INPUT_CONTEXT_64            *InputContext;
3180   DEVICE_CONTEXT_64           *OutputContext;
3181   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3182   //
3183   // 4.6.6 Configure Endpoint
3184   //
3185   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3186   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3187   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3188   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3189 
3190   ASSERT (ConfigDesc != NULL);
3191 
3192   MaxDci = 0;
3193 
3194   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3195   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3196     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3197       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3198     }
3199 
3200     if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3201       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3202       continue;
3203     }
3204 
3205     Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3206     if (Dci > MaxDci) {
3207       MaxDci = Dci;
3208     }
3209 
3210     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3211   }
3212 
3213   InputContext->InputControlContext.Dword2 |= BIT0;
3214   InputContext->Slot.ContextEntries         = MaxDci;
3215   //
3216   // configure endpoint
3217   //
3218   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3219   PhyAddr  = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3220   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3221   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3222   CmdTrbCfgEP.CycleBit = 1;
3223   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3224   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3225   DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3226   Status = XhcCmdTransfer (
3227              Xhc,
3228              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3229              XHC_GENERIC_TIMEOUT,
3230              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3231              );
3232   if (EFI_ERROR (Status)) {
3233     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
3234   } else {
3235     Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3236   }
3237 
3238   return Status;
3239 }
3240 
3241 /**
3242   Stop endpoint through XHCI's Stop_Endpoint cmd.
3243 
3244   @param  Xhc                   The XHCI Instance.
3245   @param  SlotId                The slot id to be configured.
3246   @param  Dci                   The device context index of endpoint.
3247   @param  PendingUrb            The pending URB to check completion status when stopping the end point.
3248 
3249   @retval EFI_SUCCESS           Stop endpoint successfully.
3250   @retval Others                Failed to stop endpoint.
3251 
3252 **/
3253 EFI_STATUS
3254 EFIAPI
XhcStopEndpoint(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci,IN URB * PendingUrb OPTIONAL)3255 XhcStopEndpoint (
3256   IN USB_XHCI_INSTANCE      *Xhc,
3257   IN UINT8                  SlotId,
3258   IN UINT8                  Dci,
3259   IN URB                    *PendingUrb  OPTIONAL
3260   )
3261 {
3262   EFI_STATUS                    Status;
3263   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
3264   CMD_TRB_STOP_ENDPOINT         CmdTrbStopED;
3265 
3266   DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3267 
3268   //
3269   // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
3270   // the PendingUrb completion status, because it's possible that the PendingUrb is
3271   // finished just before stopping the end point, but after the looping check.
3272   //
3273   // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
3274   // through function parameter, but That will cause every consumer of XhcCmdTransfer,
3275   // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
3276   // But actually only XhcCheckUrbResult is aware of the PendingUrb.
3277   // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
3278   //
3279   ASSERT (Xhc->PendingUrb == NULL);
3280   Xhc->PendingUrb = PendingUrb;
3281   //
3282   // Reset the URB result from Timeout to NoError.
3283   // The USB result will be:
3284   //   changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
3285   //   remain NoError when Success/ShortPacket Transfer Event is received.
3286   //
3287   if (PendingUrb != NULL) {
3288     PendingUrb->Result = EFI_USB_NOERROR;
3289   }
3290 
3291   //
3292   // Send stop endpoint command to transit Endpoint from running to stop state
3293   //
3294   ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
3295   CmdTrbStopED.CycleBit = 1;
3296   CmdTrbStopED.Type     = TRB_TYPE_STOP_ENDPOINT;
3297   CmdTrbStopED.EDID     = Dci;
3298   CmdTrbStopED.SlotId   = SlotId;
3299   Status = XhcCmdTransfer (
3300              Xhc,
3301              (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
3302              XHC_GENERIC_TIMEOUT,
3303              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3304              );
3305   if (EFI_ERROR(Status)) {
3306     DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
3307   }
3308 
3309   Xhc->PendingUrb = NULL;
3310 
3311   return Status;
3312 }
3313 
3314 /**
3315   Reset endpoint through XHCI's Reset_Endpoint cmd.
3316 
3317   @param  Xhc                   The XHCI Instance.
3318   @param  SlotId                The slot id to be configured.
3319   @param  Dci                   The device context index of endpoint.
3320 
3321   @retval EFI_SUCCESS           Reset endpoint successfully.
3322   @retval Others                Failed to reset endpoint.
3323 
3324 **/
3325 EFI_STATUS
3326 EFIAPI
XhcResetEndpoint(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci)3327 XhcResetEndpoint (
3328   IN USB_XHCI_INSTANCE      *Xhc,
3329   IN UINT8                  SlotId,
3330   IN UINT8                  Dci
3331   )
3332 {
3333   EFI_STATUS                  Status;
3334   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3335   CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;
3336 
3337   DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3338 
3339   //
3340   // Send stop endpoint command to transit Endpoint from running to stop state
3341   //
3342   ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
3343   CmdTrbResetED.CycleBit = 1;
3344   CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;
3345   CmdTrbResetED.EDID     = Dci;
3346   CmdTrbResetED.SlotId   = SlotId;
3347   Status = XhcCmdTransfer (
3348              Xhc,
3349              (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
3350              XHC_GENERIC_TIMEOUT,
3351              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3352              );
3353   if (EFI_ERROR(Status)) {
3354     DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
3355   }
3356 
3357   return Status;
3358 }
3359 
3360 /**
3361   Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3362 
3363   @param  Xhc                   The XHCI Instance.
3364   @param  SlotId                The slot id to be configured.
3365   @param  Dci                   The device context index of endpoint.
3366   @param  Urb                   The dequeue pointer of the transfer ring specified
3367                                 by the urb to be updated.
3368 
3369   @retval EFI_SUCCESS           Set transfer ring dequeue pointer succeeds.
3370   @retval Others                Failed to set transfer ring dequeue pointer.
3371 
3372 **/
3373 EFI_STATUS
3374 EFIAPI
XhcSetTrDequeuePointer(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci,IN URB * Urb)3375 XhcSetTrDequeuePointer (
3376   IN USB_XHCI_INSTANCE      *Xhc,
3377   IN UINT8                  SlotId,
3378   IN UINT8                  Dci,
3379   IN URB                    *Urb
3380   )
3381 {
3382   EFI_STATUS                  Status;
3383   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3384   CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;
3385   EFI_PHYSICAL_ADDRESS        PhyAddr;
3386 
3387   DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
3388 
3389   //
3390   // Send stop endpoint command to transit Endpoint from running to stop state
3391   //
3392   ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
3393   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
3394   CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
3395   CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3396   CmdSetTRDeq.CycleBit = 1;
3397   CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;
3398   CmdSetTRDeq.Endpoint = Dci;
3399   CmdSetTRDeq.SlotId   = SlotId;
3400   Status = XhcCmdTransfer (
3401              Xhc,
3402              (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
3403              XHC_GENERIC_TIMEOUT,
3404              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3405              );
3406   if (EFI_ERROR(Status)) {
3407     DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
3408   }
3409 
3410   return Status;
3411 }
3412 
3413 /**
3414   Set interface through XHCI's Configure_Endpoint cmd.
3415 
3416   @param  Xhc           The XHCI Instance.
3417   @param  SlotId        The slot id to be configured.
3418   @param  DeviceSpeed   The device's speed.
3419   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3420   @param  Request       USB device request to send.
3421 
3422   @retval EFI_SUCCESS   Successfully set interface.
3423 
3424 **/
3425 EFI_STATUS
3426 EFIAPI
XhcSetInterface(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc,IN EFI_USB_DEVICE_REQUEST * Request)3427 XhcSetInterface (
3428   IN USB_XHCI_INSTANCE        *Xhc,
3429   IN UINT8                    SlotId,
3430   IN UINT8                    DeviceSpeed,
3431   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc,
3432   IN EFI_USB_DEVICE_REQUEST   *Request
3433   )
3434 {
3435   EFI_STATUS                  Status;
3436   USB_INTERFACE_DESCRIPTOR    *IfDescActive;
3437   USB_INTERFACE_DESCRIPTOR    *IfDescSet;
3438   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3439   USB_ENDPOINT_DESCRIPTOR     *EpDesc;
3440   UINTN                       NumEp;
3441   UINTN                       EpIndex;
3442   UINT8                       EpAddr;
3443   UINT8                       Direction;
3444   UINT8                       Dci;
3445   UINT8                       MaxDci;
3446   EFI_PHYSICAL_ADDRESS        PhyAddr;
3447   VOID                        *RingSeg;
3448 
3449   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3450   INPUT_CONTEXT               *InputContext;
3451   DEVICE_CONTEXT              *OutputContext;
3452   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3453 
3454   Status = EFI_SUCCESS;
3455 
3456   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3457   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3458   //
3459   // XHCI 4.6.6 Configure Endpoint
3460   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3461   // Context and Add Context flags as follows:
3462   // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3463   // Context and Add Context flags to '0'.
3464   //
3465   // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3466   // So the default Drop Context and Add Context flags can be '0' to cover 1).
3467   //
3468   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3469   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3470 
3471   ASSERT (ConfigDesc != NULL);
3472 
3473   MaxDci = 0;
3474 
3475   IfDescActive = NULL;
3476   IfDescSet = NULL;
3477 
3478   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3479   while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3480     if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3481       if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3482         if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3483           //
3484           // Find out the active interface descriptor.
3485           //
3486           IfDescActive = IfDesc;
3487         } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3488           //
3489           // Find out the interface descriptor to set.
3490           //
3491           IfDescSet = IfDesc;
3492         }
3493       }
3494     }
3495     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3496   }
3497 
3498   //
3499   // XHCI 4.6.6 Configure Endpoint
3500   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3501   // Context and Add Context flags as follows:
3502   // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3503   // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3504   // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3505   // the Drop Context flag to '1' and Add Context flag to '0'.
3506   // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3507   // and Add Context flags shall be set to '1'.
3508   //
3509   // Below codes are to cover 2), 3) and 4).
3510   //
3511 
3512   if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3513     NumEp = IfDescActive->NumEndpoints;
3514     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3515     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3516       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3517         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3518       }
3519 
3520       if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3521         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3522         continue;
3523       }
3524 
3525       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3526       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3527 
3528       Dci = XhcEndpointToDci (EpAddr, Direction);
3529       ASSERT (Dci < 32);
3530       if (Dci > MaxDci) {
3531         MaxDci = Dci;
3532       }
3533       //
3534       // XHCI 4.3.6 - Setting Alternate Interfaces
3535       // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3536       //
3537       Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
3538       if (EFI_ERROR (Status)) {
3539         return Status;
3540       }
3541       //
3542       // XHCI 4.3.6 - Setting Alternate Interfaces
3543       // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3544       //
3545       if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3546         RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3547         if (RingSeg != NULL) {
3548           UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3549         }
3550         FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3551         Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3552       }
3553 
3554       //
3555       // Set the Drop Context flag to '1'.
3556       //
3557       InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3558 
3559       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3560     }
3561 
3562     //
3563     // XHCI 4.3.6 - Setting Alternate Interfaces
3564     // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3565     // Interface setting, to '0'.
3566     //
3567     // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3568     //
3569 
3570     //
3571     // XHCI 4.3.6 - Setting Alternate Interfaces
3572     // 4) For each endpoint enabled by the Configure Endpoint Command:
3573     //   a. Allocate a Transfer Ring.
3574     //   b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3575     //   c. Initialize the Endpoint Context data structure.
3576     //
3577     Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3578     if (Dci > MaxDci) {
3579       MaxDci = Dci;
3580     }
3581 
3582     InputContext->InputControlContext.Dword2 |= BIT0;
3583     InputContext->Slot.ContextEntries         = MaxDci;
3584     //
3585     // XHCI 4.3.6 - Setting Alternate Interfaces
3586     // 5) Issue and successfully complete a Configure Endpoint Command.
3587     //
3588     ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3589     PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3590     CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3591     CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3592     CmdTrbCfgEP.CycleBit = 1;
3593     CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3594     CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3595     DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));
3596     Status = XhcCmdTransfer (
3597                Xhc,
3598                (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3599                XHC_GENERIC_TIMEOUT,
3600                (TRB_TEMPLATE **) (UINTN) &EvtTrb
3601                );
3602     if (EFI_ERROR (Status)) {
3603       DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));
3604     } else {
3605       //
3606       // Update the active AlternateSetting.
3607       //
3608       Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3609     }
3610   }
3611 
3612   return Status;
3613 }
3614 
3615 /**
3616   Set interface through XHCI's Configure_Endpoint cmd.
3617 
3618   @param  Xhc           The XHCI Instance.
3619   @param  SlotId        The slot id to be configured.
3620   @param  DeviceSpeed   The device's speed.
3621   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3622   @param  Request       USB device request to send.
3623 
3624   @retval EFI_SUCCESS   Successfully set interface.
3625 
3626 **/
3627 EFI_STATUS
3628 EFIAPI
XhcSetInterface64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc,IN EFI_USB_DEVICE_REQUEST * Request)3629 XhcSetInterface64 (
3630   IN USB_XHCI_INSTANCE        *Xhc,
3631   IN UINT8                    SlotId,
3632   IN UINT8                    DeviceSpeed,
3633   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc,
3634   IN EFI_USB_DEVICE_REQUEST   *Request
3635   )
3636 {
3637   EFI_STATUS                  Status;
3638   USB_INTERFACE_DESCRIPTOR    *IfDescActive;
3639   USB_INTERFACE_DESCRIPTOR    *IfDescSet;
3640   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3641   USB_ENDPOINT_DESCRIPTOR     *EpDesc;
3642   UINTN                       NumEp;
3643   UINTN                       EpIndex;
3644   UINT8                       EpAddr;
3645   UINT8                       Direction;
3646   UINT8                       Dci;
3647   UINT8                       MaxDci;
3648   EFI_PHYSICAL_ADDRESS        PhyAddr;
3649   VOID                        *RingSeg;
3650 
3651   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3652   INPUT_CONTEXT_64            *InputContext;
3653   DEVICE_CONTEXT_64           *OutputContext;
3654   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3655 
3656   Status = EFI_SUCCESS;
3657 
3658   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3659   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3660   //
3661   // XHCI 4.6.6 Configure Endpoint
3662   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3663   // Context and Add Context flags as follows:
3664   // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3665   // Context and Add Context flags to '0'.
3666   //
3667   // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3668   // So the default Drop Context and Add Context flags can be '0' to cover 1).
3669   //
3670   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3671   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3672 
3673   ASSERT (ConfigDesc != NULL);
3674 
3675   MaxDci = 0;
3676 
3677   IfDescActive = NULL;
3678   IfDescSet = NULL;
3679 
3680   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3681   while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3682     if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3683       if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3684         if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3685           //
3686           // Find out the active interface descriptor.
3687           //
3688           IfDescActive = IfDesc;
3689         } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3690           //
3691           // Find out the interface descriptor to set.
3692           //
3693           IfDescSet = IfDesc;
3694         }
3695       }
3696     }
3697     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3698   }
3699 
3700   //
3701   // XHCI 4.6.6 Configure Endpoint
3702   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3703   // Context and Add Context flags as follows:
3704   // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3705   // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3706   // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3707   // the Drop Context flag to '1' and Add Context flag to '0'.
3708   // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3709   // and Add Context flags shall be set to '1'.
3710   //
3711   // Below codes are to cover 2), 3) and 4).
3712   //
3713 
3714   if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3715     NumEp = IfDescActive->NumEndpoints;
3716     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3717     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3718       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3719         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3720       }
3721 
3722       if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3723         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3724         continue;
3725       }
3726 
3727       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3728       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3729 
3730       Dci = XhcEndpointToDci (EpAddr, Direction);
3731       ASSERT (Dci < 32);
3732       if (Dci > MaxDci) {
3733         MaxDci = Dci;
3734       }
3735       //
3736       // XHCI 4.3.6 - Setting Alternate Interfaces
3737       // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3738       //
3739       Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
3740       if (EFI_ERROR (Status)) {
3741         return Status;
3742       }
3743       //
3744       // XHCI 4.3.6 - Setting Alternate Interfaces
3745       // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3746       //
3747       if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3748         RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3749         if (RingSeg != NULL) {
3750           UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3751         }
3752         FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3753         Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3754       }
3755 
3756       //
3757       // Set the Drop Context flag to '1'.
3758       //
3759       InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3760 
3761       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3762     }
3763 
3764     //
3765     // XHCI 4.3.6 - Setting Alternate Interfaces
3766     // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3767     // Interface setting, to '0'.
3768     //
3769     // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3770     //
3771 
3772     //
3773     // XHCI 4.3.6 - Setting Alternate Interfaces
3774     // 4) For each endpoint enabled by the Configure Endpoint Command:
3775     //   a. Allocate a Transfer Ring.
3776     //   b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3777     //   c. Initialize the Endpoint Context data structure.
3778     //
3779     Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3780     if (Dci > MaxDci) {
3781       MaxDci = Dci;
3782     }
3783 
3784     InputContext->InputControlContext.Dword2 |= BIT0;
3785     InputContext->Slot.ContextEntries         = MaxDci;
3786     //
3787     // XHCI 4.3.6 - Setting Alternate Interfaces
3788     // 5) Issue and successfully complete a Configure Endpoint Command.
3789     //
3790     ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3791     PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3792     CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3793     CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3794     CmdTrbCfgEP.CycleBit = 1;
3795     CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3796     CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3797     DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));
3798     Status = XhcCmdTransfer (
3799                Xhc,
3800                (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3801                XHC_GENERIC_TIMEOUT,
3802                (TRB_TEMPLATE **) (UINTN) &EvtTrb
3803                );
3804     if (EFI_ERROR (Status)) {
3805       DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));
3806     } else {
3807       //
3808       // Update the active AlternateSetting.
3809       //
3810       Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3811     }
3812   }
3813 
3814   return Status;
3815 }
3816 
3817 /**
3818   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3819 
3820   @param  Xhc           The XHCI Instance.
3821   @param  SlotId        The slot id to be evaluated.
3822   @param  MaxPacketSize The max packet size supported by the device control transfer.
3823 
3824   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
3825 
3826 **/
3827 EFI_STATUS
3828 EFIAPI
XhcEvaluateContext(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)3829 XhcEvaluateContext (
3830   IN USB_XHCI_INSTANCE        *Xhc,
3831   IN UINT8                    SlotId,
3832   IN UINT32                   MaxPacketSize
3833   )
3834 {
3835   EFI_STATUS                  Status;
3836   CMD_TRB_EVALUATE_CONTEXT    CmdTrbEvalu;
3837   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3838   INPUT_CONTEXT               *InputContext;
3839   EFI_PHYSICAL_ADDRESS        PhyAddr;
3840 
3841   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3842 
3843   //
3844   // 4.6.7 Evaluate Context
3845   //
3846   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3847   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3848 
3849   InputContext->InputControlContext.Dword2 |= BIT1;
3850   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
3851 
3852   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3853   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3854   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3855   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3856   CmdTrbEvalu.CycleBit = 1;
3857   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
3858   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3859   DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3860   Status = XhcCmdTransfer (
3861              Xhc,
3862              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3863              XHC_GENERIC_TIMEOUT,
3864              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3865              );
3866   if (EFI_ERROR (Status)) {
3867     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
3868   }
3869   return Status;
3870 }
3871 
3872 /**
3873   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3874 
3875   @param  Xhc           The XHCI Instance.
3876   @param  SlotId        The slot id to be evaluated.
3877   @param  MaxPacketSize The max packet size supported by the device control transfer.
3878 
3879   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
3880 
3881 **/
3882 EFI_STATUS
3883 EFIAPI
XhcEvaluateContext64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)3884 XhcEvaluateContext64 (
3885   IN USB_XHCI_INSTANCE        *Xhc,
3886   IN UINT8                    SlotId,
3887   IN UINT32                   MaxPacketSize
3888   )
3889 {
3890   EFI_STATUS                  Status;
3891   CMD_TRB_EVALUATE_CONTEXT    CmdTrbEvalu;
3892   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3893   INPUT_CONTEXT_64            *InputContext;
3894   EFI_PHYSICAL_ADDRESS        PhyAddr;
3895 
3896   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3897 
3898   //
3899   // 4.6.7 Evaluate Context
3900   //
3901   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3902   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3903 
3904   InputContext->InputControlContext.Dword2 |= BIT1;
3905   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
3906 
3907   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3908   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3909   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3910   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3911   CmdTrbEvalu.CycleBit = 1;
3912   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
3913   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3914   DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3915   Status = XhcCmdTransfer (
3916              Xhc,
3917              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3918              XHC_GENERIC_TIMEOUT,
3919              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3920              );
3921   if (EFI_ERROR (Status)) {
3922     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
3923   }
3924   return Status;
3925 }
3926 
3927 
3928 /**
3929   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3930 
3931   @param  Xhc           The XHCI Instance.
3932   @param  SlotId        The slot id to be configured.
3933   @param  PortNum       The total number of downstream port supported by the hub.
3934   @param  TTT           The TT think time of the hub device.
3935   @param  MTT           The multi-TT of the hub device.
3936 
3937   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
3938 
3939 **/
3940 EFI_STATUS
XhcConfigHubContext(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)3941 XhcConfigHubContext (
3942   IN USB_XHCI_INSTANCE        *Xhc,
3943   IN UINT8                    SlotId,
3944   IN UINT8                    PortNum,
3945   IN UINT8                    TTT,
3946   IN UINT8                    MTT
3947   )
3948 {
3949   EFI_STATUS                  Status;
3950   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3951   INPUT_CONTEXT               *InputContext;
3952   DEVICE_CONTEXT              *OutputContext;
3953   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3954   EFI_PHYSICAL_ADDRESS        PhyAddr;
3955 
3956   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3957   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3958   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3959 
3960   //
3961   // 4.6.7 Evaluate Context
3962   //
3963   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3964 
3965   InputContext->InputControlContext.Dword2 |= BIT0;
3966 
3967   //
3968   // Copy the slot context from OutputContext to Input context
3969   //
3970   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
3971   InputContext->Slot.Hub     = 1;
3972   InputContext->Slot.PortNum = PortNum;
3973   InputContext->Slot.TTT     = TTT;
3974   InputContext->Slot.MTT     = MTT;
3975 
3976   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3977   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3978   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3979   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3980   CmdTrbCfgEP.CycleBit = 1;
3981   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3982   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3983   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
3984   Status = XhcCmdTransfer (
3985               Xhc,
3986               (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3987               XHC_GENERIC_TIMEOUT,
3988               (TRB_TEMPLATE **) (UINTN) &EvtTrb
3989               );
3990   if (EFI_ERROR (Status)) {
3991     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
3992   }
3993   return Status;
3994 }
3995 
3996 /**
3997   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3998 
3999   @param  Xhc           The XHCI Instance.
4000   @param  SlotId        The slot id to be configured.
4001   @param  PortNum       The total number of downstream port supported by the hub.
4002   @param  TTT           The TT think time of the hub device.
4003   @param  MTT           The multi-TT of the hub device.
4004 
4005   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
4006 
4007 **/
4008 EFI_STATUS
XhcConfigHubContext64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)4009 XhcConfigHubContext64 (
4010   IN USB_XHCI_INSTANCE        *Xhc,
4011   IN UINT8                    SlotId,
4012   IN UINT8                    PortNum,
4013   IN UINT8                    TTT,
4014   IN UINT8                    MTT
4015   )
4016 {
4017   EFI_STATUS                  Status;
4018   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
4019   INPUT_CONTEXT_64            *InputContext;
4020   DEVICE_CONTEXT_64           *OutputContext;
4021   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
4022   EFI_PHYSICAL_ADDRESS        PhyAddr;
4023 
4024   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
4025   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
4026   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
4027 
4028   //
4029   // 4.6.7 Evaluate Context
4030   //
4031   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
4032 
4033   InputContext->InputControlContext.Dword2 |= BIT0;
4034 
4035   //
4036   // Copy the slot context from OutputContext to Input context
4037   //
4038   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
4039   InputContext->Slot.Hub     = 1;
4040   InputContext->Slot.PortNum = PortNum;
4041   InputContext->Slot.TTT     = TTT;
4042   InputContext->Slot.MTT     = MTT;
4043 
4044   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
4045   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
4046   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
4047   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
4048   CmdTrbCfgEP.CycleBit = 1;
4049   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
4050   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
4051   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
4052   Status = XhcCmdTransfer (
4053               Xhc,
4054               (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
4055               XHC_GENERIC_TIMEOUT,
4056               (TRB_TEMPLATE **) (UINTN) &EvtTrb
4057               );
4058   if (EFI_ERROR (Status)) {
4059     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
4060   }
4061   return Status;
4062 }
4063 
4064 
4065