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