1 /** @file
2 
3   XHCI transfer scheduling routines.
4 
5 Copyright (c) 2011 - 2016, 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       //
1013       // If the checked TRB is the link TRB at the end of the transfer ring,
1014       // recircle it to the head of the ring.
1015       //
1016       if (CheckedTrb->Type == TRB_TYPE_LINK) {
1017         CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;
1018       }
1019     }
1020   }
1021 
1022   return FALSE;
1023 }
1024 
1025 /**
1026   Check if the Trb is a transaction of the URB.
1027 
1028   @param Trb    The TRB to be checked
1029   @param Urb    The transfer ring to be checked.
1030 
1031   @retval TRUE  It is a transaction of the URB.
1032   @retval FALSE It is not any transaction of the URB.
1033 
1034 **/
1035 BOOLEAN
IsTransferRingTrb(IN TRB_TEMPLATE * Trb,IN URB * Urb)1036 IsTransferRingTrb (
1037   IN  TRB_TEMPLATE        *Trb,
1038   IN  URB                 *Urb
1039   )
1040 {
1041   TRB_TEMPLATE  *CheckedTrb;
1042   UINTN         Index;
1043 
1044   CheckedTrb = Urb->Ring->RingSeg0;
1045 
1046   ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
1047 
1048   for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
1049     if (Trb == CheckedTrb) {
1050       return TRUE;
1051     }
1052     CheckedTrb++;
1053   }
1054 
1055   return FALSE;
1056 }
1057 
1058 /**
1059   Check the URB's execution result and update the URB's
1060   result accordingly.
1061 
1062   @param  Xhc             The XHCI Instance.
1063   @param  Urb             The URB to check result.
1064 
1065   @return Whether the result of URB transfer is finialized.
1066 
1067 **/
1068 BOOLEAN
XhcCheckUrbResult(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1069 XhcCheckUrbResult (
1070   IN  USB_XHCI_INSTANCE   *Xhc,
1071   IN  URB                 *Urb
1072   )
1073 {
1074   EVT_TRB_TRANSFER        *EvtTrb;
1075   TRB_TEMPLATE            *TRBPtr;
1076   UINTN                   Index;
1077   UINT8                   TRBType;
1078   EFI_STATUS              Status;
1079   URB                     *AsyncUrb;
1080   URB                     *CheckedUrb;
1081   UINT64                  XhcDequeue;
1082   UINT32                  High;
1083   UINT32                  Low;
1084   EFI_PHYSICAL_ADDRESS    PhyAddr;
1085 
1086   ASSERT ((Xhc != NULL) && (Urb != NULL));
1087 
1088   Status   = EFI_SUCCESS;
1089   AsyncUrb = NULL;
1090 
1091   if (Urb->Finished) {
1092     goto EXIT;
1093   }
1094 
1095   EvtTrb = NULL;
1096 
1097   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1098     Urb->Result |= EFI_USB_ERR_SYSTEM;
1099     goto EXIT;
1100   }
1101 
1102   //
1103   // Traverse the event ring to find out all new events from the previous check.
1104   //
1105   XhcSyncEventRing (Xhc, &Xhc->EventRing);
1106   for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
1107     Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
1108     if (Status == EFI_NOT_READY) {
1109       //
1110       // All new events are handled, return directly.
1111       //
1112       goto EXIT;
1113     }
1114 
1115     //
1116     // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1117     //
1118     if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
1119       continue;
1120     }
1121 
1122     //
1123     // Need convert pci device address to host address
1124     //
1125     PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
1126     TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
1127 
1128     //
1129     // Update the status of Urb according to the finished event regardless of whether
1130     // the urb is current checked one or in the XHCI's async transfer list.
1131     // This way is used to avoid that those completed async transfer events don't get
1132     // handled in time and are flushed by newer coming events.
1133     //
1134     if (IsTransferRingTrb (TRBPtr, Urb)) {
1135       CheckedUrb = Urb;
1136     } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
1137       CheckedUrb = AsyncUrb;
1138     } else {
1139       continue;
1140     }
1141 
1142     switch (EvtTrb->Completecode) {
1143       case TRB_COMPLETION_STALL_ERROR:
1144         CheckedUrb->Result  |= EFI_USB_ERR_STALL;
1145         CheckedUrb->Finished = TRUE;
1146         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1147         goto EXIT;
1148 
1149       case TRB_COMPLETION_BABBLE_ERROR:
1150         CheckedUrb->Result  |= EFI_USB_ERR_BABBLE;
1151         CheckedUrb->Finished = TRUE;
1152         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1153         goto EXIT;
1154 
1155       case TRB_COMPLETION_DATA_BUFFER_ERROR:
1156         CheckedUrb->Result  |= EFI_USB_ERR_BUFFER;
1157         CheckedUrb->Finished = TRUE;
1158         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
1159         goto EXIT;
1160 
1161       case TRB_COMPLETION_USB_TRANSACTION_ERROR:
1162         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
1163         CheckedUrb->Finished = TRUE;
1164         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1165         goto EXIT;
1166 
1167       case TRB_COMPLETION_SHORT_PACKET:
1168       case TRB_COMPLETION_SUCCESS:
1169         if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
1170           DEBUG ((EFI_D_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));
1171         }
1172 
1173         TRBType = (UINT8) (TRBPtr->Type);
1174         if ((TRBType == TRB_TYPE_DATA_STAGE) ||
1175             (TRBType == TRB_TYPE_NORMAL) ||
1176             (TRBType == TRB_TYPE_ISOCH)) {
1177           CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
1178         }
1179 
1180         break;
1181 
1182       default:
1183         DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
1184         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
1185         CheckedUrb->Finished = TRUE;
1186         goto EXIT;
1187     }
1188 
1189     //
1190     // Only check first and end Trb event address
1191     //
1192     if (TRBPtr == CheckedUrb->TrbStart) {
1193       CheckedUrb->StartDone = TRUE;
1194     }
1195 
1196     if (TRBPtr == CheckedUrb->TrbEnd) {
1197       CheckedUrb->EndDone = TRUE;
1198     }
1199 
1200     if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
1201       CheckedUrb->Finished = TRUE;
1202       CheckedUrb->EvtTrb   = (TRB_TEMPLATE *)EvtTrb;
1203     }
1204   }
1205 
1206 EXIT:
1207 
1208   //
1209   // Advance event ring to last available entry
1210   //
1211   // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1212   // So divide it to two 32-bytes width register access.
1213   //
1214   Low  = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
1215   High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
1216   XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
1217 
1218   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
1219 
1220   if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
1221     //
1222     // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1223     // So divide it to two 32-bytes width register access.
1224     //
1225     XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
1226     XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
1227   }
1228 
1229   return Urb->Finished;
1230 }
1231 
1232 
1233 /**
1234   Execute the transfer by polling the URB. This is a synchronous operation.
1235 
1236   @param  Xhc               The XHCI Instance.
1237   @param  CmdTransfer       The executed URB is for cmd transfer or not.
1238   @param  Urb               The URB to execute.
1239   @param  Timeout           The time to wait before abort, in millisecond.
1240 
1241   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
1242   @return EFI_TIMEOUT       The transfer failed due to time out.
1243   @return EFI_SUCCESS       The transfer finished OK.
1244 
1245 **/
1246 EFI_STATUS
XhcExecTransfer(IN USB_XHCI_INSTANCE * Xhc,IN BOOLEAN CmdTransfer,IN URB * Urb,IN UINTN Timeout)1247 XhcExecTransfer (
1248   IN  USB_XHCI_INSTANCE   *Xhc,
1249   IN  BOOLEAN             CmdTransfer,
1250   IN  URB                 *Urb,
1251   IN  UINTN               Timeout
1252   )
1253 {
1254   EFI_STATUS              Status;
1255   UINTN                   Index;
1256   UINT64                  Loop;
1257   UINT8                   SlotId;
1258   UINT8                   Dci;
1259   BOOLEAN                 Finished;
1260 
1261   if (CmdTransfer) {
1262     SlotId = 0;
1263     Dci    = 0;
1264   } else {
1265     SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1266     if (SlotId == 0) {
1267       return EFI_DEVICE_ERROR;
1268     }
1269     Dci  = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1270     ASSERT (Dci < 32);
1271   }
1272 
1273   Status = EFI_SUCCESS;
1274   Loop   = Timeout * XHC_1_MILLISECOND;
1275   if (Timeout == 0) {
1276     Loop = 0xFFFFFFFF;
1277   }
1278 
1279   XhcRingDoorBell (Xhc, SlotId, Dci);
1280 
1281   for (Index = 0; Index < Loop; Index++) {
1282     Finished = XhcCheckUrbResult (Xhc, Urb);
1283     if (Finished) {
1284       break;
1285     }
1286     gBS->Stall (XHC_1_MICROSECOND);
1287   }
1288 
1289   if (Index == Loop) {
1290     Urb->Result = EFI_USB_ERR_TIMEOUT;
1291     Status      = EFI_TIMEOUT;
1292   } else if (Urb->Result != EFI_USB_NOERROR) {
1293     Status      = EFI_DEVICE_ERROR;
1294   }
1295 
1296   return Status;
1297 }
1298 
1299 /**
1300   Delete a single asynchronous interrupt transfer for
1301   the device and endpoint.
1302 
1303   @param  Xhc                   The XHCI Instance.
1304   @param  BusAddr               The logical device address assigned by UsbBus driver.
1305   @param  EpNum                 The endpoint of the target.
1306 
1307   @retval EFI_SUCCESS           An asynchronous transfer is removed.
1308   @retval EFI_NOT_FOUND         No transfer for the device is found.
1309 
1310 **/
1311 EFI_STATUS
XhciDelAsyncIntTransfer(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 BusAddr,IN UINT8 EpNum)1312 XhciDelAsyncIntTransfer (
1313   IN  USB_XHCI_INSTANCE   *Xhc,
1314   IN  UINT8               BusAddr,
1315   IN  UINT8               EpNum
1316   )
1317 {
1318   LIST_ENTRY              *Entry;
1319   LIST_ENTRY              *Next;
1320   URB                     *Urb;
1321   EFI_USB_DATA_DIRECTION  Direction;
1322 
1323   Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
1324   EpNum    &= 0x0F;
1325 
1326   Urb = NULL;
1327 
1328   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1329     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1330     if ((Urb->Ep.BusAddr == BusAddr) &&
1331         (Urb->Ep.EpAddr == EpNum) &&
1332         (Urb->Ep.Direction == Direction)) {
1333       RemoveEntryList (&Urb->UrbList);
1334       FreePool (Urb->Data);
1335       XhcFreeUrb (Xhc, Urb);
1336       return EFI_SUCCESS;
1337     }
1338   }
1339 
1340   return EFI_NOT_FOUND;
1341 }
1342 
1343 /**
1344   Remove all the asynchronous interrutp transfers.
1345 
1346   @param  Xhc    The XHCI Instance.
1347 
1348 **/
1349 VOID
XhciDelAllAsyncIntTransfers(IN USB_XHCI_INSTANCE * Xhc)1350 XhciDelAllAsyncIntTransfers (
1351   IN USB_XHCI_INSTANCE    *Xhc
1352   )
1353 {
1354   LIST_ENTRY              *Entry;
1355   LIST_ENTRY              *Next;
1356   URB                     *Urb;
1357 
1358   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1359     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1360     RemoveEntryList (&Urb->UrbList);
1361     FreePool (Urb->Data);
1362     XhcFreeUrb (Xhc, Urb);
1363   }
1364 }
1365 
1366 /**
1367   Update the queue head for next round of asynchronous transfer
1368 
1369   @param  Xhc     The XHCI Instance.
1370   @param  Urb     The URB to update
1371 
1372 **/
1373 VOID
XhcUpdateAsyncRequest(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1374 XhcUpdateAsyncRequest (
1375   IN USB_XHCI_INSTANCE        *Xhc,
1376   IN URB                      *Urb
1377   )
1378 {
1379   EFI_STATUS    Status;
1380 
1381   if (Urb->Result == EFI_USB_NOERROR) {
1382     Status = XhcCreateTransferTrb (Xhc, Urb);
1383     if (EFI_ERROR (Status)) {
1384       return;
1385     }
1386     Status = RingIntTransferDoorBell (Xhc, Urb);
1387     if (EFI_ERROR (Status)) {
1388       return;
1389     }
1390   }
1391 }
1392 
1393 /**
1394   Flush data from PCI controller specific address to mapped system
1395   memory address.
1396 
1397   @param  Xhc                The XHCI device.
1398   @param  Urb                The URB to unmap.
1399 
1400   @retval EFI_SUCCESS        Success to flush data to mapped system memory.
1401   @retval EFI_DEVICE_ERROR   Fail to flush data to mapped system memory.
1402 
1403 **/
1404 EFI_STATUS
XhcFlushAsyncIntMap(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1405 XhcFlushAsyncIntMap (
1406   IN  USB_XHCI_INSTANCE   *Xhc,
1407   IN  URB                 *Urb
1408   )
1409 {
1410   EFI_STATUS                    Status;
1411   EFI_PHYSICAL_ADDRESS          PhyAddr;
1412   EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
1413   EFI_PCI_IO_PROTOCOL           *PciIo;
1414   UINTN                         Len;
1415   VOID                          *Map;
1416 
1417   PciIo = Xhc->PciIo;
1418   Len   = Urb->DataLen;
1419 
1420   if (Urb->Ep.Direction == EfiUsbDataIn) {
1421     MapOp = EfiPciIoOperationBusMasterWrite;
1422   } else {
1423     MapOp = EfiPciIoOperationBusMasterRead;
1424   }
1425 
1426   if (Urb->DataMap != NULL) {
1427     Status = PciIo->Unmap (PciIo, Urb->DataMap);
1428     if (EFI_ERROR (Status)) {
1429       goto ON_ERROR;
1430     }
1431   }
1432 
1433   Urb->DataMap = NULL;
1434 
1435   Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
1436   if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
1437     goto ON_ERROR;
1438   }
1439 
1440   Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);
1441   Urb->DataMap  = Map;
1442   return EFI_SUCCESS;
1443 
1444 ON_ERROR:
1445   return EFI_DEVICE_ERROR;
1446 }
1447 
1448 /**
1449   Interrupt transfer periodic check handler.
1450 
1451   @param  Event                 Interrupt event.
1452   @param  Context               Pointer to USB_XHCI_INSTANCE.
1453 
1454 **/
1455 VOID
1456 EFIAPI
XhcMonitorAsyncRequests(IN EFI_EVENT Event,IN VOID * Context)1457 XhcMonitorAsyncRequests (
1458   IN EFI_EVENT            Event,
1459   IN VOID                 *Context
1460   )
1461 {
1462   USB_XHCI_INSTANCE       *Xhc;
1463   LIST_ENTRY              *Entry;
1464   LIST_ENTRY              *Next;
1465   UINT8                   *ProcBuf;
1466   URB                     *Urb;
1467   UINT8                   SlotId;
1468   EFI_STATUS              Status;
1469   EFI_TPL                 OldTpl;
1470 
1471   OldTpl = gBS->RaiseTPL (XHC_TPL);
1472 
1473   Xhc    = (USB_XHCI_INSTANCE*) Context;
1474 
1475   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1476     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1477 
1478     //
1479     // Make sure that the device is available before every check.
1480     //
1481     SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1482     if (SlotId == 0) {
1483       continue;
1484     }
1485 
1486     //
1487     // Check the result of URB execution. If it is still
1488     // active, check the next one.
1489     //
1490     XhcCheckUrbResult (Xhc, Urb);
1491 
1492     if (!Urb->Finished) {
1493       continue;
1494     }
1495 
1496     //
1497     // Flush any PCI posted write transactions from a PCI host
1498     // bridge to system memory.
1499     //
1500     Status = XhcFlushAsyncIntMap (Xhc, Urb);
1501     if (EFI_ERROR (Status)) {
1502       DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1503     }
1504 
1505     //
1506     // Allocate a buffer then copy the transferred data for user.
1507     // If failed to allocate the buffer, update the URB for next
1508     // round of transfer. Ignore the data of this round.
1509     //
1510     ProcBuf = NULL;
1511     if (Urb->Result == EFI_USB_NOERROR) {
1512       ASSERT (Urb->Completed <= Urb->DataLen);
1513 
1514       ProcBuf = AllocateZeroPool (Urb->Completed);
1515 
1516       if (ProcBuf == NULL) {
1517         XhcUpdateAsyncRequest (Xhc, Urb);
1518         continue;
1519       }
1520 
1521       CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1522     }
1523 
1524     //
1525     // Leave error recovery to its related device driver. A
1526     // common case of the error recovery is to re-submit the
1527     // interrupt transfer which is linked to the head of the
1528     // list. This function scans from head to tail. So the
1529     // re-submitted interrupt transfer's callback function
1530     // will not be called again in this round. Don't touch this
1531     // URB after the callback, it may have been removed by the
1532     // callback.
1533     //
1534     if (Urb->Callback != NULL) {
1535       //
1536       // Restore the old TPL, USB bus maybe connect device in
1537       // his callback. Some drivers may has a lower TPL restriction.
1538       //
1539       gBS->RestoreTPL (OldTpl);
1540       (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1541       OldTpl = gBS->RaiseTPL (XHC_TPL);
1542     }
1543 
1544     if (ProcBuf != NULL) {
1545       gBS->FreePool (ProcBuf);
1546     }
1547 
1548     XhcUpdateAsyncRequest (Xhc, Urb);
1549   }
1550   gBS->RestoreTPL (OldTpl);
1551 }
1552 
1553 /**
1554   Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1555 
1556   @param  Xhc                   The XHCI Instance.
1557   @param  ParentRouteChart      The route string pointed to the parent device if it exists.
1558   @param  Port                  The port to be polled.
1559   @param  PortState             The port state.
1560 
1561   @retval EFI_SUCCESS           Successfully enable/disable device slot according to port state.
1562   @retval Others                Should not appear.
1563 
1564 **/
1565 EFI_STATUS
1566 EFIAPI
XhcPollPortStatusChange(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT8 Port,IN EFI_USB_PORT_STATUS * PortState)1567 XhcPollPortStatusChange (
1568   IN  USB_XHCI_INSTANCE     *Xhc,
1569   IN  USB_DEV_ROUTE         ParentRouteChart,
1570   IN  UINT8                 Port,
1571   IN  EFI_USB_PORT_STATUS   *PortState
1572   )
1573 {
1574   EFI_STATUS        Status;
1575   UINT8             Speed;
1576   UINT8             SlotId;
1577   USB_DEV_ROUTE     RouteChart;
1578 
1579   Status = EFI_SUCCESS;
1580 
1581   if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
1582     return EFI_SUCCESS;
1583   }
1584 
1585   if (ParentRouteChart.Dword == 0) {
1586     RouteChart.Route.RouteString = 0;
1587     RouteChart.Route.RootPortNum = Port + 1;
1588     RouteChart.Route.TierNum     = 1;
1589   } else {
1590     if(Port < 14) {
1591       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
1592     } else {
1593       RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
1594     }
1595     RouteChart.Route.RootPortNum   = ParentRouteChart.Route.RootPortNum;
1596     RouteChart.Route.TierNum       = ParentRouteChart.Route.TierNum + 1;
1597   }
1598 
1599   SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1600   if (SlotId != 0) {
1601     if (Xhc->HcCParams.Data.Csz == 0) {
1602       Status = XhcDisableSlotCmd (Xhc, SlotId);
1603     } else {
1604       Status = XhcDisableSlotCmd64 (Xhc, SlotId);
1605     }
1606   }
1607 
1608   if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
1609       ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
1610     //
1611     // Has a device attached, Identify device speed after port is enabled.
1612     //
1613     Speed = EFI_USB_SPEED_FULL;
1614     if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
1615       Speed = EFI_USB_SPEED_LOW;
1616     } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
1617       Speed = EFI_USB_SPEED_HIGH;
1618     } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
1619       Speed = EFI_USB_SPEED_SUPER;
1620     }
1621     //
1622     // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1623     //
1624     SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1625     if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
1626       if (Xhc->HcCParams.Data.Csz == 0) {
1627         Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1628       } else {
1629         Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1630       }
1631     }
1632   }
1633 
1634   return Status;
1635 }
1636 
1637 
1638 /**
1639   Calculate the device context index by endpoint address and direction.
1640 
1641   @param  EpAddr              The target endpoint number.
1642   @param  Direction           The direction of the target endpoint.
1643 
1644   @return The device context index of endpoint.
1645 
1646 **/
1647 UINT8
XhcEndpointToDci(IN UINT8 EpAddr,IN UINT8 Direction)1648 XhcEndpointToDci (
1649   IN  UINT8                   EpAddr,
1650   IN  UINT8                   Direction
1651   )
1652 {
1653   UINT8 Index;
1654 
1655   if (EpAddr == 0) {
1656     return 1;
1657   } else {
1658     Index = (UINT8) (2 * EpAddr);
1659     if (Direction == EfiUsbDataIn) {
1660       Index += 1;
1661     }
1662     return Index;
1663   }
1664 }
1665 
1666 /**
1667   Find out the actual device address according to the requested device address from UsbBus.
1668 
1669   @param  Xhc             The XHCI Instance.
1670   @param  BusDevAddr      The requested device address by UsbBus upper driver.
1671 
1672   @return The actual device address assigned to the device.
1673 
1674 **/
1675 UINT8
1676 EFIAPI
XhcBusDevAddrToSlotId(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 BusDevAddr)1677 XhcBusDevAddrToSlotId (
1678   IN  USB_XHCI_INSTANCE  *Xhc,
1679   IN  UINT8              BusDevAddr
1680   )
1681 {
1682   UINT8  Index;
1683 
1684   for (Index = 0; Index < 255; Index++) {
1685     if (Xhc->UsbDevContext[Index + 1].Enabled &&
1686         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1687         (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
1688       break;
1689     }
1690   }
1691 
1692   if (Index == 255) {
1693     return 0;
1694   }
1695 
1696   return Xhc->UsbDevContext[Index + 1].SlotId;
1697 }
1698 
1699 /**
1700   Find out the slot id according to the device's route string.
1701 
1702   @param  Xhc             The XHCI Instance.
1703   @param  RouteString     The route string described the device location.
1704 
1705   @return The slot id used by the device.
1706 
1707 **/
1708 UINT8
1709 EFIAPI
XhcRouteStringToSlotId(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE RouteString)1710 XhcRouteStringToSlotId (
1711   IN  USB_XHCI_INSTANCE  *Xhc,
1712   IN  USB_DEV_ROUTE      RouteString
1713   )
1714 {
1715   UINT8  Index;
1716 
1717   for (Index = 0; Index < 255; Index++) {
1718     if (Xhc->UsbDevContext[Index + 1].Enabled &&
1719         (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1720         (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
1721       break;
1722     }
1723   }
1724 
1725   if (Index == 255) {
1726     return 0;
1727   }
1728 
1729   return Xhc->UsbDevContext[Index + 1].SlotId;
1730 }
1731 
1732 /**
1733   Synchronize the specified event ring to update the enqueue and dequeue pointer.
1734 
1735   @param  Xhc         The XHCI Instance.
1736   @param  EvtRing     The event ring to sync.
1737 
1738   @retval EFI_SUCCESS The event ring is synchronized successfully.
1739 
1740 **/
1741 EFI_STATUS
1742 EFIAPI
XhcSyncEventRing(IN USB_XHCI_INSTANCE * Xhc,IN EVENT_RING * EvtRing)1743 XhcSyncEventRing (
1744   IN USB_XHCI_INSTANCE    *Xhc,
1745   IN EVENT_RING           *EvtRing
1746   )
1747 {
1748   UINTN               Index;
1749   TRB_TEMPLATE        *EvtTrb1;
1750 
1751   ASSERT (EvtRing != NULL);
1752 
1753   //
1754   // Calculate the EventRingEnqueue and EventRingCCS.
1755   // Note: only support single Segment
1756   //
1757   EvtTrb1 = EvtRing->EventRingDequeue;
1758 
1759   for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
1760     if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
1761       break;
1762     }
1763 
1764     EvtTrb1++;
1765 
1766     if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1767       EvtTrb1 = EvtRing->EventRingSeg0;
1768       EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
1769     }
1770   }
1771 
1772   if (Index < EvtRing->TrbNumber) {
1773     EvtRing->EventRingEnqueue = EvtTrb1;
1774   } else {
1775     ASSERT (FALSE);
1776   }
1777 
1778   return EFI_SUCCESS;
1779 }
1780 
1781 /**
1782   Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1783 
1784   @param  Xhc         The XHCI Instance.
1785   @param  TrsRing     The transfer ring to sync.
1786 
1787   @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1788 
1789 **/
1790 EFI_STATUS
1791 EFIAPI
XhcSyncTrsRing(IN USB_XHCI_INSTANCE * Xhc,IN TRANSFER_RING * TrsRing)1792 XhcSyncTrsRing (
1793   IN USB_XHCI_INSTANCE    *Xhc,
1794   IN TRANSFER_RING        *TrsRing
1795   )
1796 {
1797   UINTN               Index;
1798   TRB_TEMPLATE        *TrsTrb;
1799 
1800   ASSERT (TrsRing != NULL);
1801   //
1802   // Calculate the latest RingEnqueue and RingPCS
1803   //
1804   TrsTrb = TrsRing->RingEnqueue;
1805   ASSERT (TrsTrb != NULL);
1806 
1807   for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
1808     if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
1809       break;
1810     }
1811     TrsTrb++;
1812     if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
1813       ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
1814       //
1815       // set cycle bit in Link TRB as normal
1816       //
1817       ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
1818       //
1819       // Toggle PCS maintained by software
1820       //
1821       TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
1822       TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0;  // Use host address
1823     }
1824   }
1825 
1826   ASSERT (Index != TrsRing->TrbNumber);
1827 
1828   if (TrsTrb != TrsRing->RingEnqueue) {
1829     TrsRing->RingEnqueue = TrsTrb;
1830   }
1831 
1832   //
1833   // Clear the Trb context for enqueue, but reserve the PCS bit
1834   //
1835   TrsTrb->Parameter1 = 0;
1836   TrsTrb->Parameter2 = 0;
1837   TrsTrb->Status     = 0;
1838   TrsTrb->RsvdZ1     = 0;
1839   TrsTrb->Type       = 0;
1840   TrsTrb->Control    = 0;
1841 
1842   return EFI_SUCCESS;
1843 }
1844 
1845 /**
1846   Check if there is a new generated event.
1847 
1848   @param  Xhc           The XHCI Instance.
1849   @param  EvtRing       The event ring to check.
1850   @param  NewEvtTrb     The new event TRB found.
1851 
1852   @retval EFI_SUCCESS   Found a new event TRB at the event ring.
1853   @retval EFI_NOT_READY The event ring has no new event.
1854 
1855 **/
1856 EFI_STATUS
1857 EFIAPI
XhcCheckNewEvent(IN USB_XHCI_INSTANCE * Xhc,IN EVENT_RING * EvtRing,OUT TRB_TEMPLATE ** NewEvtTrb)1858 XhcCheckNewEvent (
1859   IN  USB_XHCI_INSTANCE       *Xhc,
1860   IN  EVENT_RING              *EvtRing,
1861   OUT TRB_TEMPLATE            **NewEvtTrb
1862   )
1863 {
1864   ASSERT (EvtRing != NULL);
1865 
1866   *NewEvtTrb = EvtRing->EventRingDequeue;
1867 
1868   if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
1869     return EFI_NOT_READY;
1870   }
1871 
1872   EvtRing->EventRingDequeue++;
1873   //
1874   // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1875   //
1876   if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1877     EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
1878   }
1879 
1880   return EFI_SUCCESS;
1881 }
1882 
1883 /**
1884   Ring the door bell to notify XHCI there is a transaction to be executed.
1885 
1886   @param  Xhc           The XHCI Instance.
1887   @param  SlotId        The slot id of the target device.
1888   @param  Dci           The device context index of the target slot or endpoint.
1889 
1890   @retval EFI_SUCCESS   Successfully ring the door bell.
1891 
1892 **/
1893 EFI_STATUS
1894 EFIAPI
XhcRingDoorBell(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci)1895 XhcRingDoorBell (
1896   IN USB_XHCI_INSTANCE    *Xhc,
1897   IN UINT8                SlotId,
1898   IN UINT8                Dci
1899   )
1900 {
1901   if (SlotId == 0) {
1902     XhcWriteDoorBellReg (Xhc, 0, 0);
1903   } else {
1904     XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1905   }
1906 
1907   return EFI_SUCCESS;
1908 }
1909 
1910 /**
1911   Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1912 
1913   @param  Xhc           The XHCI Instance.
1914   @param  Urb           The URB to be rung.
1915 
1916   @retval EFI_SUCCESS   Successfully ring the door bell.
1917 
1918 **/
1919 EFI_STATUS
RingIntTransferDoorBell(IN USB_XHCI_INSTANCE * Xhc,IN URB * Urb)1920 RingIntTransferDoorBell (
1921   IN  USB_XHCI_INSTANCE   *Xhc,
1922   IN  URB                 *Urb
1923   )
1924 {
1925   UINT8                SlotId;
1926   UINT8                Dci;
1927 
1928   SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1929   Dci    = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1930   XhcRingDoorBell (Xhc, SlotId, Dci);
1931   return EFI_SUCCESS;
1932 }
1933 
1934 /**
1935   Assign and initialize the device slot for a new device.
1936 
1937   @param  Xhc                 The XHCI Instance.
1938   @param  ParentRouteChart    The route string pointed to the parent device.
1939   @param  ParentPort          The port at which the device is located.
1940   @param  RouteChart          The route string pointed to the device.
1941   @param  DeviceSpeed         The device speed.
1942 
1943   @retval EFI_SUCCESS   Successfully assign a slot to the device and assign an address to it.
1944 
1945 **/
1946 EFI_STATUS
1947 EFIAPI
XhcInitializeDeviceSlot(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)1948 XhcInitializeDeviceSlot (
1949   IN  USB_XHCI_INSTANCE         *Xhc,
1950   IN  USB_DEV_ROUTE             ParentRouteChart,
1951   IN  UINT16                    ParentPort,
1952   IN  USB_DEV_ROUTE             RouteChart,
1953   IN  UINT8                     DeviceSpeed
1954   )
1955 {
1956   EFI_STATUS                  Status;
1957   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
1958   INPUT_CONTEXT               *InputContext;
1959   DEVICE_CONTEXT              *OutputContext;
1960   TRANSFER_RING               *EndpointTransferRing;
1961   CMD_TRB_ADDRESS_DEVICE      CmdTrbAddr;
1962   UINT8                       DeviceAddress;
1963   CMD_TRB_ENABLE_SLOT         CmdTrb;
1964   UINT8                       SlotId;
1965   UINT8                       ParentSlotId;
1966   DEVICE_CONTEXT              *ParentDeviceContext;
1967   EFI_PHYSICAL_ADDRESS        PhyAddr;
1968 
1969   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1970   CmdTrb.CycleBit = 1;
1971   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
1972 
1973   Status = XhcCmdTransfer (
1974               Xhc,
1975               (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1976               XHC_GENERIC_TIMEOUT,
1977               (TRB_TEMPLATE **) (UINTN) &EvtTrb
1978               );
1979   if (EFI_ERROR (Status)) {
1980     DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
1981     return Status;
1982   }
1983   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1984   DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1985   SlotId = (UINT8)EvtTrb->SlotId;
1986   ASSERT (SlotId != 0);
1987 
1988   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1989   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
1990   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
1991   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
1992   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1993 
1994   //
1995   // 4.3.3 Device Slot Initialization
1996   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1997   //
1998   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
1999   ASSERT (InputContext != NULL);
2000   ASSERT (((UINTN) InputContext & 0x3F) == 0);
2001   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2002 
2003   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2004 
2005   //
2006   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2007   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2008   //    Context are affected by the command.
2009   //
2010   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2011 
2012   //
2013   // 3) Initialize the Input Slot Context data structure
2014   //
2015   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
2016   InputContext->Slot.Speed          = DeviceSpeed + 1;
2017   InputContext->Slot.ContextEntries = 1;
2018   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2019 
2020   if (RouteChart.Route.RouteString) {
2021     //
2022     // The device is behind of hub device.
2023     //
2024     ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2025     ASSERT (ParentSlotId != 0);
2026     //
2027     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2028     //
2029     ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2030     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2031         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2032       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2033         //
2034         // Full/Low device attached to High speed hub port that isolates the high speed signaling
2035         // environment from Full/Low speed signaling environment for a device
2036         //
2037         InputContext->Slot.TTPortNum   = ParentPort;
2038         InputContext->Slot.TTHubSlotId = ParentSlotId;
2039       }
2040     } else {
2041       //
2042       // Inherit the TT parameters from parent device.
2043       //
2044       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
2045       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2046       //
2047       // If the device is a High speed device then down the speed to be the same as its parent Hub
2048       //
2049       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2050         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2051       }
2052     }
2053   }
2054 
2055   //
2056   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2057   //
2058   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2059   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2060   CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2061   //
2062   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2063   //
2064   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2065 
2066   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2067     InputContext->EP[0].MaxPacketSize = 512;
2068   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2069     InputContext->EP[0].MaxPacketSize = 64;
2070   } else {
2071     InputContext->EP[0].MaxPacketSize = 8;
2072   }
2073   //
2074   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2075   // 1KB, and Bulk and Isoch endpoints 3KB.
2076   //
2077   InputContext->EP[0].AverageTRBLength = 8;
2078   InputContext->EP[0].MaxBurstSize     = 0;
2079   InputContext->EP[0].Interval         = 0;
2080   InputContext->EP[0].MaxPStreams      = 0;
2081   InputContext->EP[0].Mult             = 0;
2082   InputContext->EP[0].CErr             = 3;
2083 
2084   //
2085   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2086   //
2087   PhyAddr = UsbHcGetPciAddrForHostAddr (
2088               Xhc->MemPool,
2089               ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2090               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2091               );
2092   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2093   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2094 
2095   //
2096   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2097   //
2098   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
2099   ASSERT (OutputContext != NULL);
2100   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2101   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
2102 
2103   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2104   //
2105   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2106   //    a pointer to the Output Device Context data structure (6.2.1).
2107   //
2108   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
2109   //
2110   // Fill DCBAA with PCI device address
2111   //
2112   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2113 
2114   //
2115   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2116   //    Context data structure described above.
2117   //
2118   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2119   // to device.
2120   //
2121   gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2122   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2123   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2124   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2125   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2126   CmdTrbAddr.CycleBit = 1;
2127   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
2128   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2129   Status = XhcCmdTransfer (
2130              Xhc,
2131              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2132              XHC_GENERIC_TIMEOUT,
2133              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2134              );
2135   if (!EFI_ERROR (Status)) {
2136     DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
2137     DEBUG ((EFI_D_INFO, "    Address %d assigned successfully\n", DeviceAddress));
2138     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2139   }
2140 
2141   return Status;
2142 }
2143 
2144 /**
2145   Assign and initialize the device slot for a new device.
2146 
2147   @param  Xhc                 The XHCI Instance.
2148   @param  ParentRouteChart    The route string pointed to the parent device.
2149   @param  ParentPort          The port at which the device is located.
2150   @param  RouteChart          The route string pointed to the device.
2151   @param  DeviceSpeed         The device speed.
2152 
2153   @retval EFI_SUCCESS   Successfully assign a slot to the device and assign an address to it.
2154 
2155 **/
2156 EFI_STATUS
2157 EFIAPI
XhcInitializeDeviceSlot64(IN USB_XHCI_INSTANCE * Xhc,IN USB_DEV_ROUTE ParentRouteChart,IN UINT16 ParentPort,IN USB_DEV_ROUTE RouteChart,IN UINT8 DeviceSpeed)2158 XhcInitializeDeviceSlot64 (
2159   IN  USB_XHCI_INSTANCE         *Xhc,
2160   IN  USB_DEV_ROUTE             ParentRouteChart,
2161   IN  UINT16                    ParentPort,
2162   IN  USB_DEV_ROUTE             RouteChart,
2163   IN  UINT8                     DeviceSpeed
2164   )
2165 {
2166   EFI_STATUS                  Status;
2167   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2168   INPUT_CONTEXT_64            *InputContext;
2169   DEVICE_CONTEXT_64           *OutputContext;
2170   TRANSFER_RING               *EndpointTransferRing;
2171   CMD_TRB_ADDRESS_DEVICE      CmdTrbAddr;
2172   UINT8                       DeviceAddress;
2173   CMD_TRB_ENABLE_SLOT         CmdTrb;
2174   UINT8                       SlotId;
2175   UINT8                       ParentSlotId;
2176   DEVICE_CONTEXT_64           *ParentDeviceContext;
2177   EFI_PHYSICAL_ADDRESS        PhyAddr;
2178 
2179   ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2180   CmdTrb.CycleBit = 1;
2181   CmdTrb.Type     = TRB_TYPE_EN_SLOT;
2182 
2183   Status = XhcCmdTransfer (
2184               Xhc,
2185               (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2186               XHC_GENERIC_TIMEOUT,
2187               (TRB_TEMPLATE **) (UINTN) &EvtTrb
2188               );
2189   if (EFI_ERROR (Status)) {
2190     DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
2191     return Status;
2192   }
2193   ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2194   DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2195   SlotId = (UINT8)EvtTrb->SlotId;
2196   ASSERT (SlotId != 0);
2197 
2198   ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2199   Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;
2200   Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;
2201   Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;
2202   Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2203 
2204   //
2205   // 4.3.3 Device Slot Initialization
2206   // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2207   //
2208   InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
2209   ASSERT (InputContext != NULL);
2210   ASSERT (((UINTN) InputContext & 0x3F) == 0);
2211   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2212 
2213   Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2214 
2215   //
2216   // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2217   //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2218   //    Context are affected by the command.
2219   //
2220   InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2221 
2222   //
2223   // 3) Initialize the Input Slot Context data structure
2224   //
2225   InputContext->Slot.RouteString    = RouteChart.Route.RouteString;
2226   InputContext->Slot.Speed          = DeviceSpeed + 1;
2227   InputContext->Slot.ContextEntries = 1;
2228   InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2229 
2230   if (RouteChart.Route.RouteString) {
2231     //
2232     // The device is behind of hub device.
2233     //
2234     ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2235     ASSERT (ParentSlotId != 0);
2236     //
2237     //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2238     //
2239     ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2240     if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2241         (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2242       if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2243         //
2244         // Full/Low device attached to High speed hub port that isolates the high speed signaling
2245         // environment from Full/Low speed signaling environment for a device
2246         //
2247         InputContext->Slot.TTPortNum   = ParentPort;
2248         InputContext->Slot.TTHubSlotId = ParentSlotId;
2249       }
2250     } else {
2251       //
2252       // Inherit the TT parameters from parent device.
2253       //
2254       InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;
2255       InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2256       //
2257       // If the device is a High speed device then down the speed to be the same as its parent Hub
2258       //
2259       if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2260         InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2261       }
2262     }
2263   }
2264 
2265   //
2266   // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2267   //
2268   EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2269   Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2270   CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2271   //
2272   // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2273   //
2274   InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2275 
2276   if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2277     InputContext->EP[0].MaxPacketSize = 512;
2278   } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2279     InputContext->EP[0].MaxPacketSize = 64;
2280   } else {
2281     InputContext->EP[0].MaxPacketSize = 8;
2282   }
2283   //
2284   // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2285   // 1KB, and Bulk and Isoch endpoints 3KB.
2286   //
2287   InputContext->EP[0].AverageTRBLength = 8;
2288   InputContext->EP[0].MaxBurstSize     = 0;
2289   InputContext->EP[0].Interval         = 0;
2290   InputContext->EP[0].MaxPStreams      = 0;
2291   InputContext->EP[0].Mult             = 0;
2292   InputContext->EP[0].CErr             = 3;
2293 
2294   //
2295   // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2296   //
2297   PhyAddr = UsbHcGetPciAddrForHostAddr (
2298               Xhc->MemPool,
2299               ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2300               sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2301               );
2302   InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2303   InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2304 
2305   //
2306   // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2307   //
2308   OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
2309   ASSERT (OutputContext != NULL);
2310   ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2311   ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2312 
2313   Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2314   //
2315   // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2316   //    a pointer to the Output Device Context data structure (6.2.1).
2317   //
2318   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
2319   //
2320   // Fill DCBAA with PCI device address
2321   //
2322   Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2323 
2324   //
2325   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2326   //    Context data structure described above.
2327   //
2328   // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2329   // to device.
2330   //
2331   gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2332   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2333   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2334   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2335   CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2336   CmdTrbAddr.CycleBit = 1;
2337   CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;
2338   CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2339   Status = XhcCmdTransfer (
2340              Xhc,
2341              (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2342              XHC_GENERIC_TIMEOUT,
2343              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2344              );
2345   if (!EFI_ERROR (Status)) {
2346     DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2347     DEBUG ((EFI_D_INFO, "    Address %d assigned successfully\n", DeviceAddress));
2348     Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2349   }
2350   return Status;
2351 }
2352 
2353 
2354 /**
2355   Disable the specified device slot.
2356 
2357   @param  Xhc           The XHCI Instance.
2358   @param  SlotId        The slot id to be disabled.
2359 
2360   @retval EFI_SUCCESS   Successfully disable the device slot.
2361 
2362 **/
2363 EFI_STATUS
2364 EFIAPI
XhcDisableSlotCmd(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId)2365 XhcDisableSlotCmd (
2366   IN USB_XHCI_INSTANCE         *Xhc,
2367   IN UINT8                     SlotId
2368   )
2369 {
2370   EFI_STATUS            Status;
2371   TRB_TEMPLATE          *EvtTrb;
2372   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
2373   UINT8                 Index;
2374   VOID                  *RingSeg;
2375 
2376   //
2377   // Disable the device slots occupied by these devices on its downstream ports.
2378   // Entry 0 is reserved.
2379   //
2380   for (Index = 0; Index < 255; Index++) {
2381     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2382         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2383         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2384       continue;
2385     }
2386 
2387     Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2388 
2389     if (EFI_ERROR (Status)) {
2390       DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2391       Xhc->UsbDevContext[Index + 1].SlotId = 0;
2392     }
2393   }
2394 
2395   //
2396   // Construct the disable slot command
2397   //
2398   DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2399 
2400   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2401   CmdTrbDisSlot.CycleBit = 1;
2402   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
2403   CmdTrbDisSlot.SlotId   = SlotId;
2404   Status = XhcCmdTransfer (
2405              Xhc,
2406              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2407              XHC_GENERIC_TIMEOUT,
2408              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2409              );
2410   if (EFI_ERROR (Status)) {
2411     DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2412     return Status;
2413   }
2414   //
2415   // Free the slot's device context entry
2416   //
2417   Xhc->DCBAA[SlotId] = 0;
2418 
2419   //
2420   // Free the slot related data structure
2421   //
2422   for (Index = 0; Index < 31; Index++) {
2423     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2424       RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2425       if (RingSeg != NULL) {
2426         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2427       }
2428       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2429       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2430     }
2431   }
2432 
2433   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2434     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2435       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2436     }
2437   }
2438 
2439   if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2440     FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2441   }
2442 
2443   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2444     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2445   }
2446 
2447   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2448     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
2449   }
2450   //
2451   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2452   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2453   // remove urb from XHCI's asynchronous transfer list.
2454   //
2455   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2456   Xhc->UsbDevContext[SlotId].SlotId  = 0;
2457 
2458   return Status;
2459 }
2460 
2461 /**
2462   Disable the specified device slot.
2463 
2464   @param  Xhc           The XHCI Instance.
2465   @param  SlotId        The slot id to be disabled.
2466 
2467   @retval EFI_SUCCESS   Successfully disable the device slot.
2468 
2469 **/
2470 EFI_STATUS
2471 EFIAPI
XhcDisableSlotCmd64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId)2472 XhcDisableSlotCmd64 (
2473   IN USB_XHCI_INSTANCE         *Xhc,
2474   IN UINT8                     SlotId
2475   )
2476 {
2477   EFI_STATUS            Status;
2478   TRB_TEMPLATE          *EvtTrb;
2479   CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;
2480   UINT8                 Index;
2481   VOID                  *RingSeg;
2482 
2483   //
2484   // Disable the device slots occupied by these devices on its downstream ports.
2485   // Entry 0 is reserved.
2486   //
2487   for (Index = 0; Index < 255; Index++) {
2488     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2489         (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2490         (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2491       continue;
2492     }
2493 
2494     Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2495 
2496     if (EFI_ERROR (Status)) {
2497       DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2498       Xhc->UsbDevContext[Index + 1].SlotId = 0;
2499     }
2500   }
2501 
2502   //
2503   // Construct the disable slot command
2504   //
2505   DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2506 
2507   ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2508   CmdTrbDisSlot.CycleBit = 1;
2509   CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;
2510   CmdTrbDisSlot.SlotId   = SlotId;
2511   Status = XhcCmdTransfer (
2512              Xhc,
2513              (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2514              XHC_GENERIC_TIMEOUT,
2515              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2516              );
2517   if (EFI_ERROR (Status)) {
2518     DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2519     return Status;
2520   }
2521   //
2522   // Free the slot's device context entry
2523   //
2524   Xhc->DCBAA[SlotId] = 0;
2525 
2526   //
2527   // Free the slot related data structure
2528   //
2529   for (Index = 0; Index < 31; Index++) {
2530     if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2531       RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2532       if (RingSeg != NULL) {
2533         UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2534       }
2535       FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2536       Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2537     }
2538   }
2539 
2540   for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2541     if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2542       FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2543     }
2544   }
2545 
2546   if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2547     FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2548   }
2549 
2550   if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2551     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2552   }
2553 
2554   if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2555      UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
2556   }
2557   //
2558   // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2559   // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2560   // remove urb from XHCI's asynchronous transfer list.
2561   //
2562   Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2563   Xhc->UsbDevContext[SlotId].SlotId  = 0;
2564 
2565   return Status;
2566 }
2567 
2568 /**
2569   Initialize endpoint context in input context.
2570 
2571   @param Xhc            The XHCI Instance.
2572   @param SlotId         The slot id to be configured.
2573   @param DeviceSpeed    The device's speed.
2574   @param InputContext   The pointer to the input context.
2575   @param IfDesc         The pointer to the usb device interface descriptor.
2576 
2577   @return The maximum device context index of endpoint.
2578 
2579 **/
2580 UINT8
2581 EFIAPI
XhcInitializeEndpointContext(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN INPUT_CONTEXT * InputContext,IN USB_INTERFACE_DESCRIPTOR * IfDesc)2582 XhcInitializeEndpointContext (
2583   IN USB_XHCI_INSTANCE          *Xhc,
2584   IN UINT8                      SlotId,
2585   IN UINT8                      DeviceSpeed,
2586   IN INPUT_CONTEXT              *InputContext,
2587   IN USB_INTERFACE_DESCRIPTOR   *IfDesc
2588   )
2589 {
2590   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
2591   UINTN                         NumEp;
2592   UINTN                         EpIndex;
2593   UINT8                         EpAddr;
2594   UINT8                         Direction;
2595   UINT8                         Dci;
2596   UINT8                         MaxDci;
2597   EFI_PHYSICAL_ADDRESS          PhyAddr;
2598   UINT8                         Interval;
2599   TRANSFER_RING                 *EndpointTransferRing;
2600 
2601   MaxDci = 0;
2602 
2603   NumEp = IfDesc->NumEndpoints;
2604 
2605   EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2606   for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2607     while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2608       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2609     }
2610 
2611     if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2612       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2613       continue;
2614     }
2615 
2616     EpAddr    = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2617     Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2618 
2619     Dci = XhcEndpointToDci (EpAddr, Direction);
2620     ASSERT (Dci < 32);
2621     if (Dci > MaxDci) {
2622       MaxDci = Dci;
2623     }
2624 
2625     InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2626     InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
2627 
2628     if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2629       //
2630       // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2631       //
2632       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2633     } else {
2634       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2635     }
2636 
2637     switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2638       case USB_ENDPOINT_BULK:
2639         if (Direction == EfiUsbDataIn) {
2640           InputContext->EP[Dci-1].CErr   = 3;
2641           InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2642         } else {
2643           InputContext->EP[Dci-1].CErr   = 3;
2644           InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2645         }
2646 
2647         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2648         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2649           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2650           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2651           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2652         }
2653 
2654         break;
2655       case USB_ENDPOINT_ISO:
2656         if (Direction == EfiUsbDataIn) {
2657           InputContext->EP[Dci-1].CErr   = 0;
2658           InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2659         } else {
2660           InputContext->EP[Dci-1].CErr   = 0;
2661           InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2662         }
2663         //
2664         // Do not support isochronous transfer now.
2665         //
2666         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2667         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2668         continue;
2669       case USB_ENDPOINT_INTERRUPT:
2670         if (Direction == EfiUsbDataIn) {
2671           InputContext->EP[Dci-1].CErr   = 3;
2672           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2673         } else {
2674           InputContext->EP[Dci-1].CErr   = 3;
2675           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2676         }
2677         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2678         InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
2679         //
2680         // Get the bInterval from descriptor and init the the interval field of endpoint context
2681         //
2682         if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2683           Interval = EpDesc->Interval;
2684           //
2685           // Calculate through the bInterval field of Endpoint descriptor.
2686           //
2687           ASSERT (Interval != 0);
2688           InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
2689         } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2690           Interval = EpDesc->Interval;
2691           ASSERT (Interval >= 1 && Interval <= 16);
2692           //
2693           // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2694           //
2695           InputContext->EP[Dci-1].Interval         = Interval - 1;
2696           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2697           InputContext->EP[Dci-1].MaxESITPayload   = 0x0002;
2698           InputContext->EP[Dci-1].MaxBurstSize     = 0x0;
2699           InputContext->EP[Dci-1].CErr             = 3;
2700         }
2701 
2702         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2703           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2704           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2705           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2706         }
2707         break;
2708 
2709       case USB_ENDPOINT_CONTROL:
2710         //
2711         // Do not support control transfer now.
2712         //
2713         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2714       default:
2715         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2716         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2717         continue;
2718     }
2719 
2720     PhyAddr = UsbHcGetPciAddrForHostAddr (
2721                 Xhc->MemPool,
2722                 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2723                 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2724                 );
2725     PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2726     PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2727     InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2728     InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2729 
2730     EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2731   }
2732 
2733   return MaxDci;
2734 }
2735 
2736 /**
2737   Initialize endpoint context in input context.
2738 
2739   @param Xhc            The XHCI Instance.
2740   @param SlotId         The slot id to be configured.
2741   @param DeviceSpeed    The device's speed.
2742   @param InputContext   The pointer to the input context.
2743   @param IfDesc         The pointer to the usb device interface descriptor.
2744 
2745   @return The maximum device context index of endpoint.
2746 
2747 **/
2748 UINT8
2749 EFIAPI
XhcInitializeEndpointContext64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN INPUT_CONTEXT_64 * InputContext,IN USB_INTERFACE_DESCRIPTOR * IfDesc)2750 XhcInitializeEndpointContext64 (
2751   IN USB_XHCI_INSTANCE          *Xhc,
2752   IN UINT8                      SlotId,
2753   IN UINT8                      DeviceSpeed,
2754   IN INPUT_CONTEXT_64           *InputContext,
2755   IN USB_INTERFACE_DESCRIPTOR   *IfDesc
2756   )
2757 {
2758   USB_ENDPOINT_DESCRIPTOR       *EpDesc;
2759   UINTN                         NumEp;
2760   UINTN                         EpIndex;
2761   UINT8                         EpAddr;
2762   UINT8                         Direction;
2763   UINT8                         Dci;
2764   UINT8                         MaxDci;
2765   EFI_PHYSICAL_ADDRESS          PhyAddr;
2766   UINT8                         Interval;
2767   TRANSFER_RING                 *EndpointTransferRing;
2768 
2769   MaxDci = 0;
2770 
2771   NumEp = IfDesc->NumEndpoints;
2772 
2773   EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2774   for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2775     while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2776       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2777     }
2778 
2779     if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2780       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2781       continue;
2782     }
2783 
2784     EpAddr    = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2785     Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2786 
2787     Dci = XhcEndpointToDci (EpAddr, Direction);
2788     ASSERT (Dci < 32);
2789     if (Dci > MaxDci) {
2790       MaxDci = Dci;
2791     }
2792 
2793     InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2794     InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;
2795 
2796     if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2797       //
2798       // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2799       //
2800       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2801     } else {
2802       InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2803     }
2804 
2805     switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2806       case USB_ENDPOINT_BULK:
2807         if (Direction == EfiUsbDataIn) {
2808           InputContext->EP[Dci-1].CErr   = 3;
2809           InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2810         } else {
2811           InputContext->EP[Dci-1].CErr   = 3;
2812           InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2813         }
2814 
2815         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2816         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2817           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2818           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2819           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2820         }
2821 
2822         break;
2823       case USB_ENDPOINT_ISO:
2824         if (Direction == EfiUsbDataIn) {
2825           InputContext->EP[Dci-1].CErr   = 0;
2826           InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2827         } else {
2828           InputContext->EP[Dci-1].CErr   = 0;
2829           InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2830         }
2831         //
2832         // Do not support isochronous transfer now.
2833         //
2834         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2835         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2836         continue;
2837       case USB_ENDPOINT_INTERRUPT:
2838         if (Direction == EfiUsbDataIn) {
2839           InputContext->EP[Dci-1].CErr   = 3;
2840           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2841         } else {
2842           InputContext->EP[Dci-1].CErr   = 3;
2843           InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2844         }
2845         InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2846         InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;
2847         //
2848         // Get the bInterval from descriptor and init the the interval field of endpoint context
2849         //
2850         if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2851           Interval = EpDesc->Interval;
2852           //
2853           // Calculate through the bInterval field of Endpoint descriptor.
2854           //
2855           ASSERT (Interval != 0);
2856           InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
2857         } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2858           Interval = EpDesc->Interval;
2859           ASSERT (Interval >= 1 && Interval <= 16);
2860           //
2861           // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2862           //
2863           InputContext->EP[Dci-1].Interval         = Interval - 1;
2864           InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2865           InputContext->EP[Dci-1].MaxESITPayload   = 0x0002;
2866           InputContext->EP[Dci-1].MaxBurstSize     = 0x0;
2867           InputContext->EP[Dci-1].CErr             = 3;
2868         }
2869 
2870         if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2871           EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2872           Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2873           CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2874         }
2875         break;
2876 
2877       case USB_ENDPOINT_CONTROL:
2878         //
2879         // Do not support control transfer now.
2880         //
2881         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2882       default:
2883         DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
2884         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2885         continue;
2886     }
2887 
2888     PhyAddr = UsbHcGetPciAddrForHostAddr (
2889                 Xhc->MemPool,
2890                 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2891                 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2892                 );
2893     PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2894     PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2895     InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2896     InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2897 
2898     EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2899   }
2900 
2901   return MaxDci;
2902 }
2903 
2904 /**
2905   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2906 
2907   @param  Xhc           The XHCI Instance.
2908   @param  SlotId        The slot id to be configured.
2909   @param  DeviceSpeed   The device's speed.
2910   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
2911 
2912   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
2913 
2914 **/
2915 EFI_STATUS
2916 EFIAPI
XhcSetConfigCmd(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)2917 XhcSetConfigCmd (
2918   IN USB_XHCI_INSTANCE        *Xhc,
2919   IN UINT8                    SlotId,
2920   IN UINT8                    DeviceSpeed,
2921   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc
2922   )
2923 {
2924   EFI_STATUS                  Status;
2925   USB_INTERFACE_DESCRIPTOR    *IfDesc;
2926   UINT8                       Index;
2927   UINT8                       Dci;
2928   UINT8                       MaxDci;
2929   EFI_PHYSICAL_ADDRESS        PhyAddr;
2930 
2931   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
2932   INPUT_CONTEXT               *InputContext;
2933   DEVICE_CONTEXT              *OutputContext;
2934   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
2935   //
2936   // 4.6.6 Configure Endpoint
2937   //
2938   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
2939   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2940   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2941   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
2942 
2943   ASSERT (ConfigDesc != NULL);
2944 
2945   MaxDci = 0;
2946 
2947   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2948   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2949     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
2950       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2951     }
2952 
2953     if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
2954       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2955       continue;
2956     }
2957 
2958     Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
2959     if (Dci > MaxDci) {
2960       MaxDci = Dci;
2961     }
2962 
2963     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2964   }
2965 
2966   InputContext->InputControlContext.Dword2 |= BIT0;
2967   InputContext->Slot.ContextEntries         = MaxDci;
2968   //
2969   // configure endpoint
2970   //
2971   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2972   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2973   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
2974   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
2975   CmdTrbCfgEP.CycleBit = 1;
2976   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
2977   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
2978   DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2979   Status = XhcCmdTransfer (
2980              Xhc,
2981              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2982              XHC_GENERIC_TIMEOUT,
2983              (TRB_TEMPLATE **) (UINTN) &EvtTrb
2984              );
2985   if (EFI_ERROR (Status)) {
2986     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
2987   } else {
2988     Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
2989   }
2990 
2991   return Status;
2992 }
2993 
2994 /**
2995   Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2996 
2997   @param  Xhc           The XHCI Instance.
2998   @param  SlotId        The slot id to be configured.
2999   @param  DeviceSpeed   The device's speed.
3000   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3001 
3002   @retval EFI_SUCCESS   Successfully configure all the device endpoints.
3003 
3004 **/
3005 EFI_STATUS
3006 EFIAPI
XhcSetConfigCmd64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc)3007 XhcSetConfigCmd64 (
3008   IN USB_XHCI_INSTANCE        *Xhc,
3009   IN UINT8                    SlotId,
3010   IN UINT8                    DeviceSpeed,
3011   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc
3012   )
3013 {
3014   EFI_STATUS                  Status;
3015   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3016   UINT8                       Index;
3017   UINT8                       Dci;
3018   UINT8                       MaxDci;
3019   EFI_PHYSICAL_ADDRESS        PhyAddr;
3020 
3021   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3022   INPUT_CONTEXT_64            *InputContext;
3023   DEVICE_CONTEXT_64           *OutputContext;
3024   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3025   //
3026   // 4.6.6 Configure Endpoint
3027   //
3028   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3029   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3030   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3031   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3032 
3033   ASSERT (ConfigDesc != NULL);
3034 
3035   MaxDci = 0;
3036 
3037   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3038   for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3039     while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3040       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3041     }
3042 
3043     if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3044       IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3045       continue;
3046     }
3047 
3048     Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3049     if (Dci > MaxDci) {
3050       MaxDci = Dci;
3051     }
3052 
3053     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3054   }
3055 
3056   InputContext->InputControlContext.Dword2 |= BIT0;
3057   InputContext->Slot.ContextEntries         = MaxDci;
3058   //
3059   // configure endpoint
3060   //
3061   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3062   PhyAddr  = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3063   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3064   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3065   CmdTrbCfgEP.CycleBit = 1;
3066   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3067   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3068   DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3069   Status = XhcCmdTransfer (
3070              Xhc,
3071              (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3072              XHC_GENERIC_TIMEOUT,
3073              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3074              );
3075   if (EFI_ERROR (Status)) {
3076     DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
3077   } else {
3078     Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3079   }
3080 
3081   return Status;
3082 }
3083 
3084 /**
3085   Stop endpoint through XHCI's Stop_Endpoint cmd.
3086 
3087   @param  Xhc                   The XHCI Instance.
3088   @param  SlotId                The slot id to be configured.
3089   @param  Dci                   The device context index of endpoint.
3090 
3091   @retval EFI_SUCCESS           Stop endpoint successfully.
3092   @retval Others                Failed to stop endpoint.
3093 
3094 **/
3095 EFI_STATUS
3096 EFIAPI
XhcStopEndpoint(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci)3097 XhcStopEndpoint (
3098   IN USB_XHCI_INSTANCE      *Xhc,
3099   IN UINT8                  SlotId,
3100   IN UINT8                  Dci
3101   )
3102 {
3103   EFI_STATUS                    Status;
3104   EVT_TRB_COMMAND_COMPLETION    *EvtTrb;
3105   CMD_TRB_STOP_ENDPOINT         CmdTrbStopED;
3106 
3107   DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3108 
3109   //
3110   // Send stop endpoint command to transit Endpoint from running to stop state
3111   //
3112   ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
3113   CmdTrbStopED.CycleBit = 1;
3114   CmdTrbStopED.Type     = TRB_TYPE_STOP_ENDPOINT;
3115   CmdTrbStopED.EDID     = Dci;
3116   CmdTrbStopED.SlotId   = SlotId;
3117   Status = XhcCmdTransfer (
3118              Xhc,
3119              (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
3120              XHC_GENERIC_TIMEOUT,
3121              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3122              );
3123   if (EFI_ERROR(Status)) {
3124     DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
3125   }
3126 
3127   return Status;
3128 }
3129 
3130 /**
3131   Reset endpoint through XHCI's Reset_Endpoint cmd.
3132 
3133   @param  Xhc                   The XHCI Instance.
3134   @param  SlotId                The slot id to be configured.
3135   @param  Dci                   The device context index of endpoint.
3136 
3137   @retval EFI_SUCCESS           Reset endpoint successfully.
3138   @retval Others                Failed to reset endpoint.
3139 
3140 **/
3141 EFI_STATUS
3142 EFIAPI
XhcResetEndpoint(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci)3143 XhcResetEndpoint (
3144   IN USB_XHCI_INSTANCE      *Xhc,
3145   IN UINT8                  SlotId,
3146   IN UINT8                  Dci
3147   )
3148 {
3149   EFI_STATUS                  Status;
3150   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3151   CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;
3152 
3153   DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3154 
3155   //
3156   // Send stop endpoint command to transit Endpoint from running to stop state
3157   //
3158   ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
3159   CmdTrbResetED.CycleBit = 1;
3160   CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;
3161   CmdTrbResetED.EDID     = Dci;
3162   CmdTrbResetED.SlotId   = SlotId;
3163   Status = XhcCmdTransfer (
3164              Xhc,
3165              (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
3166              XHC_GENERIC_TIMEOUT,
3167              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3168              );
3169   if (EFI_ERROR(Status)) {
3170     DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
3171   }
3172 
3173   return Status;
3174 }
3175 
3176 /**
3177   Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3178 
3179   @param  Xhc                   The XHCI Instance.
3180   @param  SlotId                The slot id to be configured.
3181   @param  Dci                   The device context index of endpoint.
3182   @param  Urb                   The dequeue pointer of the transfer ring specified
3183                                 by the urb to be updated.
3184 
3185   @retval EFI_SUCCESS           Set transfer ring dequeue pointer succeeds.
3186   @retval Others                Failed to set transfer ring dequeue pointer.
3187 
3188 **/
3189 EFI_STATUS
3190 EFIAPI
XhcSetTrDequeuePointer(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 Dci,IN URB * Urb)3191 XhcSetTrDequeuePointer (
3192   IN USB_XHCI_INSTANCE      *Xhc,
3193   IN UINT8                  SlotId,
3194   IN UINT8                  Dci,
3195   IN URB                    *Urb
3196   )
3197 {
3198   EFI_STATUS                  Status;
3199   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3200   CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;
3201   EFI_PHYSICAL_ADDRESS        PhyAddr;
3202 
3203   DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
3204 
3205   //
3206   // Send stop endpoint command to transit Endpoint from running to stop state
3207   //
3208   ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
3209   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
3210   CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
3211   CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3212   CmdSetTRDeq.CycleBit = 1;
3213   CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;
3214   CmdSetTRDeq.Endpoint = Dci;
3215   CmdSetTRDeq.SlotId   = SlotId;
3216   Status = XhcCmdTransfer (
3217              Xhc,
3218              (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
3219              XHC_GENERIC_TIMEOUT,
3220              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3221              );
3222   if (EFI_ERROR(Status)) {
3223     DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
3224   }
3225 
3226   return Status;
3227 }
3228 
3229 /**
3230   Set interface through XHCI's Configure_Endpoint cmd.
3231 
3232   @param  Xhc           The XHCI Instance.
3233   @param  SlotId        The slot id to be configured.
3234   @param  DeviceSpeed   The device's speed.
3235   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3236   @param  Request       USB device request to send.
3237 
3238   @retval EFI_SUCCESS   Successfully set interface.
3239 
3240 **/
3241 EFI_STATUS
3242 EFIAPI
XhcSetInterface(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc,IN EFI_USB_DEVICE_REQUEST * Request)3243 XhcSetInterface (
3244   IN USB_XHCI_INSTANCE        *Xhc,
3245   IN UINT8                    SlotId,
3246   IN UINT8                    DeviceSpeed,
3247   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc,
3248   IN EFI_USB_DEVICE_REQUEST   *Request
3249   )
3250 {
3251   EFI_STATUS                  Status;
3252   USB_INTERFACE_DESCRIPTOR    *IfDescActive;
3253   USB_INTERFACE_DESCRIPTOR    *IfDescSet;
3254   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3255   USB_ENDPOINT_DESCRIPTOR     *EpDesc;
3256   UINTN                       NumEp;
3257   UINTN                       EpIndex;
3258   UINT8                       EpAddr;
3259   UINT8                       Direction;
3260   UINT8                       Dci;
3261   UINT8                       MaxDci;
3262   EFI_PHYSICAL_ADDRESS        PhyAddr;
3263   VOID                        *RingSeg;
3264 
3265   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3266   INPUT_CONTEXT               *InputContext;
3267   DEVICE_CONTEXT              *OutputContext;
3268   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3269 
3270   Status = EFI_SUCCESS;
3271 
3272   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3273   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3274   //
3275   // XHCI 4.6.6 Configure Endpoint
3276   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3277   // Context and Add Context flags as follows:
3278   // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3279   // Context and Add Context flags to '0'.
3280   //
3281   // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3282   // So the default Drop Context and Add Context flags can be '0' to cover 1).
3283   //
3284   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3285   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3286 
3287   ASSERT (ConfigDesc != NULL);
3288 
3289   MaxDci = 0;
3290 
3291   IfDescActive = NULL;
3292   IfDescSet = NULL;
3293 
3294   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3295   while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3296     if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3297       if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3298         if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3299           //
3300           // Find out the active interface descriptor.
3301           //
3302           IfDescActive = IfDesc;
3303         } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3304           //
3305           // Find out the interface descriptor to set.
3306           //
3307           IfDescSet = IfDesc;
3308         }
3309       }
3310     }
3311     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3312   }
3313 
3314   //
3315   // XHCI 4.6.6 Configure Endpoint
3316   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3317   // Context and Add Context flags as follows:
3318   // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3319   // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3320   // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3321   // the Drop Context flag to '1' and Add Context flag to '0'.
3322   // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3323   // and Add Context flags shall be set to '1'.
3324   //
3325   // Below codes are to cover 2), 3) and 4).
3326   //
3327 
3328   if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3329     NumEp = IfDescActive->NumEndpoints;
3330     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3331     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3332       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3333         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3334       }
3335 
3336       if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3337         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3338         continue;
3339       }
3340 
3341       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3342       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3343 
3344       Dci = XhcEndpointToDci (EpAddr, Direction);
3345       ASSERT (Dci < 32);
3346       if (Dci > MaxDci) {
3347         MaxDci = Dci;
3348       }
3349       //
3350       // XHCI 4.3.6 - Setting Alternate Interfaces
3351       // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3352       //
3353       Status = XhcStopEndpoint (Xhc, SlotId, Dci);
3354       if (EFI_ERROR (Status)) {
3355         return Status;
3356       }
3357       //
3358       // XHCI 4.3.6 - Setting Alternate Interfaces
3359       // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3360       //
3361       if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3362         RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3363         if (RingSeg != NULL) {
3364           UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3365         }
3366         FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3367         Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3368       }
3369 
3370       //
3371       // Set the Drop Context flag to '1'.
3372       //
3373       InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3374 
3375       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3376     }
3377 
3378     //
3379     // XHCI 4.3.6 - Setting Alternate Interfaces
3380     // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3381     // Interface setting, to '0'.
3382     //
3383     // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3384     //
3385 
3386     //
3387     // XHCI 4.3.6 - Setting Alternate Interfaces
3388     // 4) For each endpoint enabled by the Configure Endpoint Command:
3389     //   a. Allocate a Transfer Ring.
3390     //   b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3391     //   c. Initialize the Endpoint Context data structure.
3392     //
3393     Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3394     if (Dci > MaxDci) {
3395       MaxDci = Dci;
3396     }
3397 
3398     InputContext->InputControlContext.Dword2 |= BIT0;
3399     InputContext->Slot.ContextEntries         = MaxDci;
3400     //
3401     // XHCI 4.3.6 - Setting Alternate Interfaces
3402     // 5) Issue and successfully complete a Configure Endpoint Command.
3403     //
3404     ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3405     PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3406     CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3407     CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3408     CmdTrbCfgEP.CycleBit = 1;
3409     CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3410     CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3411     DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));
3412     Status = XhcCmdTransfer (
3413                Xhc,
3414                (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3415                XHC_GENERIC_TIMEOUT,
3416                (TRB_TEMPLATE **) (UINTN) &EvtTrb
3417                );
3418     if (EFI_ERROR (Status)) {
3419       DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));
3420     } else {
3421       //
3422       // Update the active AlternateSetting.
3423       //
3424       Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3425     }
3426   }
3427 
3428   return Status;
3429 }
3430 
3431 /**
3432   Set interface through XHCI's Configure_Endpoint cmd.
3433 
3434   @param  Xhc           The XHCI Instance.
3435   @param  SlotId        The slot id to be configured.
3436   @param  DeviceSpeed   The device's speed.
3437   @param  ConfigDesc    The pointer to the usb device configuration descriptor.
3438   @param  Request       USB device request to send.
3439 
3440   @retval EFI_SUCCESS   Successfully set interface.
3441 
3442 **/
3443 EFI_STATUS
3444 EFIAPI
XhcSetInterface64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 DeviceSpeed,IN USB_CONFIG_DESCRIPTOR * ConfigDesc,IN EFI_USB_DEVICE_REQUEST * Request)3445 XhcSetInterface64 (
3446   IN USB_XHCI_INSTANCE        *Xhc,
3447   IN UINT8                    SlotId,
3448   IN UINT8                    DeviceSpeed,
3449   IN USB_CONFIG_DESCRIPTOR    *ConfigDesc,
3450   IN EFI_USB_DEVICE_REQUEST   *Request
3451   )
3452 {
3453   EFI_STATUS                  Status;
3454   USB_INTERFACE_DESCRIPTOR    *IfDescActive;
3455   USB_INTERFACE_DESCRIPTOR    *IfDescSet;
3456   USB_INTERFACE_DESCRIPTOR    *IfDesc;
3457   USB_ENDPOINT_DESCRIPTOR     *EpDesc;
3458   UINTN                       NumEp;
3459   UINTN                       EpIndex;
3460   UINT8                       EpAddr;
3461   UINT8                       Direction;
3462   UINT8                       Dci;
3463   UINT8                       MaxDci;
3464   EFI_PHYSICAL_ADDRESS        PhyAddr;
3465   VOID                        *RingSeg;
3466 
3467   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3468   INPUT_CONTEXT_64            *InputContext;
3469   DEVICE_CONTEXT_64           *OutputContext;
3470   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3471 
3472   Status = EFI_SUCCESS;
3473 
3474   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3475   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3476   //
3477   // XHCI 4.6.6 Configure Endpoint
3478   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3479   // Context and Add Context flags as follows:
3480   // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3481   // Context and Add Context flags to '0'.
3482   //
3483   // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3484   // So the default Drop Context and Add Context flags can be '0' to cover 1).
3485   //
3486   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3487   CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3488 
3489   ASSERT (ConfigDesc != NULL);
3490 
3491   MaxDci = 0;
3492 
3493   IfDescActive = NULL;
3494   IfDescSet = NULL;
3495 
3496   IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3497   while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3498     if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3499       if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3500         if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3501           //
3502           // Find out the active interface descriptor.
3503           //
3504           IfDescActive = IfDesc;
3505         } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3506           //
3507           // Find out the interface descriptor to set.
3508           //
3509           IfDescSet = IfDesc;
3510         }
3511       }
3512     }
3513     IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3514   }
3515 
3516   //
3517   // XHCI 4.6.6 Configure Endpoint
3518   // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3519   // Context and Add Context flags as follows:
3520   // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3521   // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3522   // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3523   // the Drop Context flag to '1' and Add Context flag to '0'.
3524   // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3525   // and Add Context flags shall be set to '1'.
3526   //
3527   // Below codes are to cover 2), 3) and 4).
3528   //
3529 
3530   if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3531     NumEp = IfDescActive->NumEndpoints;
3532     EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3533     for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3534       while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3535         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3536       }
3537 
3538       if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3539         EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3540         continue;
3541       }
3542 
3543       EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3544       Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3545 
3546       Dci = XhcEndpointToDci (EpAddr, Direction);
3547       ASSERT (Dci < 32);
3548       if (Dci > MaxDci) {
3549         MaxDci = Dci;
3550       }
3551       //
3552       // XHCI 4.3.6 - Setting Alternate Interfaces
3553       // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3554       //
3555       Status = XhcStopEndpoint (Xhc, SlotId, Dci);
3556       if (EFI_ERROR (Status)) {
3557         return Status;
3558       }
3559       //
3560       // XHCI 4.3.6 - Setting Alternate Interfaces
3561       // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3562       //
3563       if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3564         RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3565         if (RingSeg != NULL) {
3566           UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3567         }
3568         FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3569         Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3570       }
3571 
3572       //
3573       // Set the Drop Context flag to '1'.
3574       //
3575       InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3576 
3577       EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3578     }
3579 
3580     //
3581     // XHCI 4.3.6 - Setting Alternate Interfaces
3582     // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3583     // Interface setting, to '0'.
3584     //
3585     // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3586     //
3587 
3588     //
3589     // XHCI 4.3.6 - Setting Alternate Interfaces
3590     // 4) For each endpoint enabled by the Configure Endpoint Command:
3591     //   a. Allocate a Transfer Ring.
3592     //   b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3593     //   c. Initialize the Endpoint Context data structure.
3594     //
3595     Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3596     if (Dci > MaxDci) {
3597       MaxDci = Dci;
3598     }
3599 
3600     InputContext->InputControlContext.Dword2 |= BIT0;
3601     InputContext->Slot.ContextEntries         = MaxDci;
3602     //
3603     // XHCI 4.3.6 - Setting Alternate Interfaces
3604     // 5) Issue and successfully complete a Configure Endpoint Command.
3605     //
3606     ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3607     PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3608     CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3609     CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3610     CmdTrbCfgEP.CycleBit = 1;
3611     CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3612     CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3613     DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));
3614     Status = XhcCmdTransfer (
3615                Xhc,
3616                (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3617                XHC_GENERIC_TIMEOUT,
3618                (TRB_TEMPLATE **) (UINTN) &EvtTrb
3619                );
3620     if (EFI_ERROR (Status)) {
3621       DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));
3622     } else {
3623       //
3624       // Update the active AlternateSetting.
3625       //
3626       Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3627     }
3628   }
3629 
3630   return Status;
3631 }
3632 
3633 /**
3634   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3635 
3636   @param  Xhc           The XHCI Instance.
3637   @param  SlotId        The slot id to be evaluated.
3638   @param  MaxPacketSize The max packet size supported by the device control transfer.
3639 
3640   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
3641 
3642 **/
3643 EFI_STATUS
3644 EFIAPI
XhcEvaluateContext(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)3645 XhcEvaluateContext (
3646   IN USB_XHCI_INSTANCE        *Xhc,
3647   IN UINT8                    SlotId,
3648   IN UINT32                   MaxPacketSize
3649   )
3650 {
3651   EFI_STATUS                  Status;
3652   CMD_TRB_EVALUATE_CONTEXT    CmdTrbEvalu;
3653   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3654   INPUT_CONTEXT               *InputContext;
3655   EFI_PHYSICAL_ADDRESS        PhyAddr;
3656 
3657   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3658 
3659   //
3660   // 4.6.7 Evaluate Context
3661   //
3662   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3663   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3664 
3665   InputContext->InputControlContext.Dword2 |= BIT1;
3666   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
3667 
3668   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3669   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3670   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3671   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3672   CmdTrbEvalu.CycleBit = 1;
3673   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
3674   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3675   DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3676   Status = XhcCmdTransfer (
3677              Xhc,
3678              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3679              XHC_GENERIC_TIMEOUT,
3680              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3681              );
3682   if (EFI_ERROR (Status)) {
3683     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
3684   }
3685   return Status;
3686 }
3687 
3688 /**
3689   Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3690 
3691   @param  Xhc           The XHCI Instance.
3692   @param  SlotId        The slot id to be evaluated.
3693   @param  MaxPacketSize The max packet size supported by the device control transfer.
3694 
3695   @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.
3696 
3697 **/
3698 EFI_STATUS
3699 EFIAPI
XhcEvaluateContext64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT32 MaxPacketSize)3700 XhcEvaluateContext64 (
3701   IN USB_XHCI_INSTANCE        *Xhc,
3702   IN UINT8                    SlotId,
3703   IN UINT32                   MaxPacketSize
3704   )
3705 {
3706   EFI_STATUS                  Status;
3707   CMD_TRB_EVALUATE_CONTEXT    CmdTrbEvalu;
3708   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3709   INPUT_CONTEXT_64            *InputContext;
3710   EFI_PHYSICAL_ADDRESS        PhyAddr;
3711 
3712   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3713 
3714   //
3715   // 4.6.7 Evaluate Context
3716   //
3717   InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3718   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3719 
3720   InputContext->InputControlContext.Dword2 |= BIT1;
3721   InputContext->EP[0].MaxPacketSize         = MaxPacketSize;
3722 
3723   ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3724   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3725   CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3726   CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3727   CmdTrbEvalu.CycleBit = 1;
3728   CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;
3729   CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3730   DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3731   Status = XhcCmdTransfer (
3732              Xhc,
3733              (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3734              XHC_GENERIC_TIMEOUT,
3735              (TRB_TEMPLATE **) (UINTN) &EvtTrb
3736              );
3737   if (EFI_ERROR (Status)) {
3738     DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
3739   }
3740   return Status;
3741 }
3742 
3743 
3744 /**
3745   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3746 
3747   @param  Xhc           The XHCI Instance.
3748   @param  SlotId        The slot id to be configured.
3749   @param  PortNum       The total number of downstream port supported by the hub.
3750   @param  TTT           The TT think time of the hub device.
3751   @param  MTT           The multi-TT of the hub device.
3752 
3753   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
3754 
3755 **/
3756 EFI_STATUS
XhcConfigHubContext(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)3757 XhcConfigHubContext (
3758   IN USB_XHCI_INSTANCE        *Xhc,
3759   IN UINT8                    SlotId,
3760   IN UINT8                    PortNum,
3761   IN UINT8                    TTT,
3762   IN UINT8                    MTT
3763   )
3764 {
3765   EFI_STATUS                  Status;
3766   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3767   INPUT_CONTEXT               *InputContext;
3768   DEVICE_CONTEXT              *OutputContext;
3769   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3770   EFI_PHYSICAL_ADDRESS        PhyAddr;
3771 
3772   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3773   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3774   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3775 
3776   //
3777   // 4.6.7 Evaluate Context
3778   //
3779   ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3780 
3781   InputContext->InputControlContext.Dword2 |= BIT0;
3782 
3783   //
3784   // Copy the slot context from OutputContext to Input context
3785   //
3786   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
3787   InputContext->Slot.Hub     = 1;
3788   InputContext->Slot.PortNum = PortNum;
3789   InputContext->Slot.TTT     = TTT;
3790   InputContext->Slot.MTT     = MTT;
3791 
3792   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3793   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3794   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3795   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3796   CmdTrbCfgEP.CycleBit = 1;
3797   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3798   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3799   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
3800   Status = XhcCmdTransfer (
3801               Xhc,
3802               (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3803               XHC_GENERIC_TIMEOUT,
3804               (TRB_TEMPLATE **) (UINTN) &EvtTrb
3805               );
3806   if (EFI_ERROR (Status)) {
3807     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
3808   }
3809   return Status;
3810 }
3811 
3812 /**
3813   Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3814 
3815   @param  Xhc           The XHCI Instance.
3816   @param  SlotId        The slot id to be configured.
3817   @param  PortNum       The total number of downstream port supported by the hub.
3818   @param  TTT           The TT think time of the hub device.
3819   @param  MTT           The multi-TT of the hub device.
3820 
3821   @retval EFI_SUCCESS   Successfully configure the hub device's slot context.
3822 
3823 **/
3824 EFI_STATUS
XhcConfigHubContext64(IN USB_XHCI_INSTANCE * Xhc,IN UINT8 SlotId,IN UINT8 PortNum,IN UINT8 TTT,IN UINT8 MTT)3825 XhcConfigHubContext64 (
3826   IN USB_XHCI_INSTANCE        *Xhc,
3827   IN UINT8                    SlotId,
3828   IN UINT8                    PortNum,
3829   IN UINT8                    TTT,
3830   IN UINT8                    MTT
3831   )
3832 {
3833   EFI_STATUS                  Status;
3834   EVT_TRB_COMMAND_COMPLETION  *EvtTrb;
3835   INPUT_CONTEXT_64            *InputContext;
3836   DEVICE_CONTEXT_64           *OutputContext;
3837   CMD_TRB_CONFIG_ENDPOINT     CmdTrbCfgEP;
3838   EFI_PHYSICAL_ADDRESS        PhyAddr;
3839 
3840   ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3841   InputContext  = Xhc->UsbDevContext[SlotId].InputContext;
3842   OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3843 
3844   //
3845   // 4.6.7 Evaluate Context
3846   //
3847   ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3848 
3849   InputContext->InputControlContext.Dword2 |= BIT0;
3850 
3851   //
3852   // Copy the slot context from OutputContext to Input context
3853   //
3854   CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
3855   InputContext->Slot.Hub     = 1;
3856   InputContext->Slot.PortNum = PortNum;
3857   InputContext->Slot.TTT     = TTT;
3858   InputContext->Slot.MTT     = MTT;
3859 
3860   ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3861   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3862   CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);
3863   CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);
3864   CmdTrbCfgEP.CycleBit = 1;
3865   CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;
3866   CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;
3867   DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
3868   Status = XhcCmdTransfer (
3869               Xhc,
3870               (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3871               XHC_GENERIC_TIMEOUT,
3872               (TRB_TEMPLATE **) (UINTN) &EvtTrb
3873               );
3874   if (EFI_ERROR (Status)) {
3875     DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
3876   }
3877   return Status;
3878 }
3879 
3880 
3881