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