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