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