]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg/XhciDxe: Error handle for USB slot initialization 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 USB_DEV_ROUTE RouteChart;
1721
1722 Status = EFI_SUCCESS;
1723
1724 if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
1725 return EFI_SUCCESS;
1726 }
1727
1728 if (ParentRouteChart.Dword == 0) {
1729 RouteChart.Route.RouteString = 0;
1730 RouteChart.Route.RootPortNum = Port + 1;
1731 RouteChart.Route.TierNum = 1;
1732 } else {
1733 if(Port < 14) {
1734 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
1735 } else {
1736 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
1737 }
1738 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
1739 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
1740 }
1741
1742 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1743 if (SlotId != 0) {
1744 if (Xhc->HcCParams.Data.Csz == 0) {
1745 Status = XhcDisableSlotCmd (Xhc, SlotId);
1746 } else {
1747 Status = XhcDisableSlotCmd64 (Xhc, SlotId);
1748 }
1749 }
1750
1751 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
1752 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
1753 //
1754 // Has a device attached, Identify device speed after port is enabled.
1755 //
1756 Speed = EFI_USB_SPEED_FULL;
1757 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
1758 Speed = EFI_USB_SPEED_LOW;
1759 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
1760 Speed = EFI_USB_SPEED_HIGH;
1761 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
1762 Speed = EFI_USB_SPEED_SUPER;
1763 }
1764 //
1765 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1766 //
1767 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1768 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
1769 if (Xhc->HcCParams.Data.Csz == 0) {
1770 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1771 } else {
1772 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1773 }
1774 }
1775 }
1776
1777 return Status;
1778 }
1779
1780
1781 /**
1782 Calculate the device context index by endpoint address and direction.
1783
1784 @param EpAddr The target endpoint number.
1785 @param Direction The direction of the target endpoint.
1786
1787 @return The device context index of endpoint.
1788
1789 **/
1790 UINT8
1791 XhcEndpointToDci (
1792 IN UINT8 EpAddr,
1793 IN UINT8 Direction
1794 )
1795 {
1796 UINT8 Index;
1797
1798 if (EpAddr == 0) {
1799 return 1;
1800 } else {
1801 Index = (UINT8) (2 * EpAddr);
1802 if (Direction == EfiUsbDataIn) {
1803 Index += 1;
1804 }
1805 return Index;
1806 }
1807 }
1808
1809 /**
1810 Find out the actual device address according to the requested device address from UsbBus.
1811
1812 @param Xhc The XHCI Instance.
1813 @param BusDevAddr The requested device address by UsbBus upper driver.
1814
1815 @return The actual device address assigned to the device.
1816
1817 **/
1818 UINT8
1819 EFIAPI
1820 XhcBusDevAddrToSlotId (
1821 IN USB_XHCI_INSTANCE *Xhc,
1822 IN UINT8 BusDevAddr
1823 )
1824 {
1825 UINT8 Index;
1826
1827 for (Index = 0; Index < 255; Index++) {
1828 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1829 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1830 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
1831 break;
1832 }
1833 }
1834
1835 if (Index == 255) {
1836 return 0;
1837 }
1838
1839 return Xhc->UsbDevContext[Index + 1].SlotId;
1840 }
1841
1842 /**
1843 Find out the slot id according to the device's route string.
1844
1845 @param Xhc The XHCI Instance.
1846 @param RouteString The route string described the device location.
1847
1848 @return The slot id used by the device.
1849
1850 **/
1851 UINT8
1852 EFIAPI
1853 XhcRouteStringToSlotId (
1854 IN USB_XHCI_INSTANCE *Xhc,
1855 IN USB_DEV_ROUTE RouteString
1856 )
1857 {
1858 UINT8 Index;
1859
1860 for (Index = 0; Index < 255; Index++) {
1861 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1862 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1863 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
1864 break;
1865 }
1866 }
1867
1868 if (Index == 255) {
1869 return 0;
1870 }
1871
1872 return Xhc->UsbDevContext[Index + 1].SlotId;
1873 }
1874
1875 /**
1876 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1877
1878 @param Xhc The XHCI Instance.
1879 @param EvtRing The event ring to sync.
1880
1881 @retval EFI_SUCCESS The event ring is synchronized successfully.
1882
1883 **/
1884 EFI_STATUS
1885 EFIAPI
1886 XhcSyncEventRing (
1887 IN USB_XHCI_INSTANCE *Xhc,
1888 IN EVENT_RING *EvtRing
1889 )
1890 {
1891 UINTN Index;
1892 TRB_TEMPLATE *EvtTrb1;
1893
1894 ASSERT (EvtRing != NULL);
1895
1896 //
1897 // Calculate the EventRingEnqueue and EventRingCCS.
1898 // Note: only support single Segment
1899 //
1900 EvtTrb1 = EvtRing->EventRingDequeue;
1901
1902 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
1903 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
1904 break;
1905 }
1906
1907 EvtTrb1++;
1908
1909 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1910 EvtTrb1 = EvtRing->EventRingSeg0;
1911 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
1912 }
1913 }
1914
1915 if (Index < EvtRing->TrbNumber) {
1916 EvtRing->EventRingEnqueue = EvtTrb1;
1917 } else {
1918 ASSERT (FALSE);
1919 }
1920
1921 return EFI_SUCCESS;
1922 }
1923
1924 /**
1925 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1926
1927 @param Xhc The XHCI Instance.
1928 @param TrsRing The transfer ring to sync.
1929
1930 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1931
1932 **/
1933 EFI_STATUS
1934 EFIAPI
1935 XhcSyncTrsRing (
1936 IN USB_XHCI_INSTANCE *Xhc,
1937 IN TRANSFER_RING *TrsRing
1938 )
1939 {
1940 UINTN Index;
1941 TRB_TEMPLATE *TrsTrb;
1942
1943 ASSERT (TrsRing != NULL);
1944 //
1945 // Calculate the latest RingEnqueue and RingPCS
1946 //
1947 TrsTrb = TrsRing->RingEnqueue;
1948 ASSERT (TrsTrb != NULL);
1949
1950 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
1951 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
1952 break;
1953 }
1954 TrsTrb++;
1955 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
1956 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
1957 //
1958 // set cycle bit in Link TRB as normal
1959 //
1960 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
1961 //
1962 // Toggle PCS maintained by software
1963 //
1964 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
1965 TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address
1966 }
1967 }
1968
1969 ASSERT (Index != TrsRing->TrbNumber);
1970
1971 if (TrsTrb != TrsRing->RingEnqueue) {
1972 TrsRing->RingEnqueue = TrsTrb;
1973 }
1974
1975 //
1976 // Clear the Trb context for enqueue, but reserve the PCS bit
1977 //
1978 TrsTrb->Parameter1 = 0;
1979 TrsTrb->Parameter2 = 0;
1980 TrsTrb->Status = 0;
1981 TrsTrb->RsvdZ1 = 0;
1982 TrsTrb->Type = 0;
1983 TrsTrb->Control = 0;
1984
1985 return EFI_SUCCESS;
1986 }
1987
1988 /**
1989 Check if there is a new generated event.
1990
1991 @param Xhc The XHCI Instance.
1992 @param EvtRing The event ring to check.
1993 @param NewEvtTrb The new event TRB found.
1994
1995 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1996 @retval EFI_NOT_READY The event ring has no new event.
1997
1998 **/
1999 EFI_STATUS
2000 EFIAPI
2001 XhcCheckNewEvent (
2002 IN USB_XHCI_INSTANCE *Xhc,
2003 IN EVENT_RING *EvtRing,
2004 OUT TRB_TEMPLATE **NewEvtTrb
2005 )
2006 {
2007 ASSERT (EvtRing != NULL);
2008
2009 *NewEvtTrb = EvtRing->EventRingDequeue;
2010
2011 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
2012 return EFI_NOT_READY;
2013 }
2014
2015 EvtRing->EventRingDequeue++;
2016 //
2017 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2018 //
2019 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2020 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
2021 }
2022
2023 return EFI_SUCCESS;
2024 }
2025
2026 /**
2027 Ring the door bell to notify XHCI there is a transaction to be executed.
2028
2029 @param Xhc The XHCI Instance.
2030 @param SlotId The slot id of the target device.
2031 @param Dci The device context index of the target slot or endpoint.
2032
2033 @retval EFI_SUCCESS Successfully ring the door bell.
2034
2035 **/
2036 EFI_STATUS
2037 EFIAPI
2038 XhcRingDoorBell (
2039 IN USB_XHCI_INSTANCE *Xhc,
2040 IN UINT8 SlotId,
2041 IN UINT8 Dci
2042 )
2043 {
2044 if (SlotId == 0) {
2045 XhcWriteDoorBellReg (Xhc, 0, 0);
2046 } else {
2047 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
2048 }
2049
2050 return EFI_SUCCESS;
2051 }
2052
2053 /**
2054 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
2055
2056 @param Xhc The XHCI Instance.
2057 @param Urb The URB to be rung.
2058
2059 @retval EFI_SUCCESS Successfully ring the door bell.
2060
2061 **/
2062 EFI_STATUS
2063 RingIntTransferDoorBell (
2064 IN USB_XHCI_INSTANCE *Xhc,
2065 IN URB *Urb
2066 )
2067 {
2068 UINT8 SlotId;
2069 UINT8 Dci;
2070
2071 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
2072 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
2073 XhcRingDoorBell (Xhc, SlotId, Dci);
2074 return EFI_SUCCESS;
2075 }
2076
2077 /**
2078 Assign and initialize the device slot for a new device.
2079
2080 @param Xhc The XHCI Instance.
2081 @param ParentRouteChart The route string pointed to the parent device.
2082 @param ParentPort The port at which the device is located.
2083 @param RouteChart The route string pointed to the device.
2084 @param DeviceSpeed The device speed.
2085
2086 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2087
2088 **/
2089 EFI_STATUS
2090 EFIAPI
2091 XhcInitializeDeviceSlot (
2092 IN USB_XHCI_INSTANCE *Xhc,
2093 IN USB_DEV_ROUTE ParentRouteChart,
2094 IN UINT16 ParentPort,
2095 IN USB_DEV_ROUTE RouteChart,
2096 IN UINT8 DeviceSpeed
2097 )
2098 {
2099 EFI_STATUS Status;
2100 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2101 INPUT_CONTEXT *InputContext;
2102 DEVICE_CONTEXT *OutputContext;
2103 TRANSFER_RING *EndpointTransferRing;
2104 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
2105 UINT8 DeviceAddress;
2106 CMD_TRB_ENABLE_SLOT CmdTrb;
2107 UINT8 SlotId;
2108 UINT8 ParentSlotId;
2109 DEVICE_CONTEXT *ParentDeviceContext;
2110 EFI_PHYSICAL_ADDRESS PhyAddr;
2111
2112 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2113 CmdTrb.CycleBit = 1;
2114 CmdTrb.Type = TRB_TYPE_EN_SLOT;
2115
2116 Status = XhcCmdTransfer (
2117 Xhc,
2118 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2119 XHC_GENERIC_TIMEOUT,
2120 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2121 );
2122 if (EFI_ERROR (Status)) {
2123 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
2124 return Status;
2125 }
2126 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2127 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2128 SlotId = (UINT8)EvtTrb->SlotId;
2129 ASSERT (SlotId != 0);
2130
2131 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2132 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
2133 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
2134 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
2135 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2136
2137 //
2138 // 4.3.3 Device Slot Initialization
2139 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2140 //
2141 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
2142 ASSERT (InputContext != NULL);
2143 ASSERT (((UINTN) InputContext & 0x3F) == 0);
2144 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2145
2146 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2147
2148 //
2149 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2150 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2151 // Context are affected by the command.
2152 //
2153 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2154
2155 //
2156 // 3) Initialize the Input Slot Context data structure
2157 //
2158 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
2159 InputContext->Slot.Speed = DeviceSpeed + 1;
2160 InputContext->Slot.ContextEntries = 1;
2161 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2162
2163 if (RouteChart.Route.RouteString) {
2164 //
2165 // The device is behind of hub device.
2166 //
2167 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2168 ASSERT (ParentSlotId != 0);
2169 //
2170 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2171 //
2172 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2173 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2174 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2175 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2176 //
2177 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2178 // environment from Full/Low speed signaling environment for a device
2179 //
2180 InputContext->Slot.TTPortNum = ParentPort;
2181 InputContext->Slot.TTHubSlotId = ParentSlotId;
2182 }
2183 } else {
2184 //
2185 // Inherit the TT parameters from parent device.
2186 //
2187 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
2188 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2189 //
2190 // If the device is a High speed device then down the speed to be the same as its parent Hub
2191 //
2192 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2193 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2194 }
2195 }
2196 }
2197
2198 //
2199 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2200 //
2201 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2202 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2203 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2204 //
2205 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2206 //
2207 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2208
2209 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2210 InputContext->EP[0].MaxPacketSize = 512;
2211 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2212 InputContext->EP[0].MaxPacketSize = 64;
2213 } else {
2214 InputContext->EP[0].MaxPacketSize = 8;
2215 }
2216 //
2217 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2218 // 1KB, and Bulk and Isoch endpoints 3KB.
2219 //
2220 InputContext->EP[0].AverageTRBLength = 8;
2221 InputContext->EP[0].MaxBurstSize = 0;
2222 InputContext->EP[0].Interval = 0;
2223 InputContext->EP[0].MaxPStreams = 0;
2224 InputContext->EP[0].Mult = 0;
2225 InputContext->EP[0].CErr = 3;
2226
2227 //
2228 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2229 //
2230 PhyAddr = UsbHcGetPciAddrForHostAddr (
2231 Xhc->MemPool,
2232 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2233 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2234 );
2235 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2236 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2237
2238 //
2239 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2240 //
2241 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
2242 ASSERT (OutputContext != NULL);
2243 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2244 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
2245
2246 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2247 //
2248 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2249 // a pointer to the Output Device Context data structure (6.2.1).
2250 //
2251 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
2252 //
2253 // Fill DCBAA with PCI device address
2254 //
2255 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2256
2257 //
2258 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2259 // Context data structure described above.
2260 //
2261 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2262 // to device.
2263 //
2264 gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2265 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2266 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2267 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
2268 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2269 CmdTrbAddr.CycleBit = 1;
2270 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2271 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2272 Status = XhcCmdTransfer (
2273 Xhc,
2274 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2275 XHC_GENERIC_TIMEOUT,
2276 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2277 );
2278 if (!EFI_ERROR (Status)) {
2279 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
2280 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2281 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2282 } else {
2283 DEBUG ((DEBUG_INFO, " Address %d assigned unsuccessfully\n"));
2284 XhcDisableSlotCmd (Xhc, SlotId);
2285 }
2286
2287 return Status;
2288 }
2289
2290 /**
2291 Assign and initialize the device slot for a new device.
2292
2293 @param Xhc The XHCI Instance.
2294 @param ParentRouteChart The route string pointed to the parent device.
2295 @param ParentPort The port at which the device is located.
2296 @param RouteChart The route string pointed to the device.
2297 @param DeviceSpeed The device speed.
2298
2299 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2300
2301 **/
2302 EFI_STATUS
2303 EFIAPI
2304 XhcInitializeDeviceSlot64 (
2305 IN USB_XHCI_INSTANCE *Xhc,
2306 IN USB_DEV_ROUTE ParentRouteChart,
2307 IN UINT16 ParentPort,
2308 IN USB_DEV_ROUTE RouteChart,
2309 IN UINT8 DeviceSpeed
2310 )
2311 {
2312 EFI_STATUS Status;
2313 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2314 INPUT_CONTEXT_64 *InputContext;
2315 DEVICE_CONTEXT_64 *OutputContext;
2316 TRANSFER_RING *EndpointTransferRing;
2317 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
2318 UINT8 DeviceAddress;
2319 CMD_TRB_ENABLE_SLOT CmdTrb;
2320 UINT8 SlotId;
2321 UINT8 ParentSlotId;
2322 DEVICE_CONTEXT_64 *ParentDeviceContext;
2323 EFI_PHYSICAL_ADDRESS PhyAddr;
2324
2325 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2326 CmdTrb.CycleBit = 1;
2327 CmdTrb.Type = TRB_TYPE_EN_SLOT;
2328
2329 Status = XhcCmdTransfer (
2330 Xhc,
2331 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2332 XHC_GENERIC_TIMEOUT,
2333 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2334 );
2335 if (EFI_ERROR (Status)) {
2336 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
2337 return Status;
2338 }
2339 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2340 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2341 SlotId = (UINT8)EvtTrb->SlotId;
2342 ASSERT (SlotId != 0);
2343
2344 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2345 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
2346 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
2347 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
2348 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2349
2350 //
2351 // 4.3.3 Device Slot Initialization
2352 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2353 //
2354 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
2355 ASSERT (InputContext != NULL);
2356 ASSERT (((UINTN) InputContext & 0x3F) == 0);
2357 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2358
2359 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2360
2361 //
2362 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2363 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2364 // Context are affected by the command.
2365 //
2366 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2367
2368 //
2369 // 3) Initialize the Input Slot Context data structure
2370 //
2371 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
2372 InputContext->Slot.Speed = DeviceSpeed + 1;
2373 InputContext->Slot.ContextEntries = 1;
2374 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2375
2376 if (RouteChart.Route.RouteString) {
2377 //
2378 // The device is behind of hub device.
2379 //
2380 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2381 ASSERT (ParentSlotId != 0);
2382 //
2383 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2384 //
2385 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2386 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2387 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2388 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2389 //
2390 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2391 // environment from Full/Low speed signaling environment for a device
2392 //
2393 InputContext->Slot.TTPortNum = ParentPort;
2394 InputContext->Slot.TTHubSlotId = ParentSlotId;
2395 }
2396 } else {
2397 //
2398 // Inherit the TT parameters from parent device.
2399 //
2400 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
2401 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2402 //
2403 // If the device is a High speed device then down the speed to be the same as its parent Hub
2404 //
2405 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2406 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2407 }
2408 }
2409 }
2410
2411 //
2412 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2413 //
2414 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2415 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2416 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2417 //
2418 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2419 //
2420 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2421
2422 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2423 InputContext->EP[0].MaxPacketSize = 512;
2424 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2425 InputContext->EP[0].MaxPacketSize = 64;
2426 } else {
2427 InputContext->EP[0].MaxPacketSize = 8;
2428 }
2429 //
2430 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2431 // 1KB, and Bulk and Isoch endpoints 3KB.
2432 //
2433 InputContext->EP[0].AverageTRBLength = 8;
2434 InputContext->EP[0].MaxBurstSize = 0;
2435 InputContext->EP[0].Interval = 0;
2436 InputContext->EP[0].MaxPStreams = 0;
2437 InputContext->EP[0].Mult = 0;
2438 InputContext->EP[0].CErr = 3;
2439
2440 //
2441 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2442 //
2443 PhyAddr = UsbHcGetPciAddrForHostAddr (
2444 Xhc->MemPool,
2445 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2446 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2447 );
2448 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2449 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2450
2451 //
2452 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2453 //
2454 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
2455 ASSERT (OutputContext != NULL);
2456 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2457 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2458
2459 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2460 //
2461 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2462 // a pointer to the Output Device Context data structure (6.2.1).
2463 //
2464 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
2465 //
2466 // Fill DCBAA with PCI device address
2467 //
2468 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2469
2470 //
2471 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2472 // Context data structure described above.
2473 //
2474 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2475 // to device.
2476 //
2477 gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2478 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2479 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2480 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
2481 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2482 CmdTrbAddr.CycleBit = 1;
2483 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2484 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2485 Status = XhcCmdTransfer (
2486 Xhc,
2487 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2488 XHC_GENERIC_TIMEOUT,
2489 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2490 );
2491 if (!EFI_ERROR (Status)) {
2492 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2493 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2494 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2495 } else {
2496 DEBUG ((DEBUG_INFO, " Address %d assigned unsuccessfully\n"));
2497 XhcDisableSlotCmd64 (Xhc, SlotId);
2498 }
2499
2500 return Status;
2501 }
2502
2503
2504 /**
2505 Disable the specified device slot.
2506
2507 @param Xhc The XHCI Instance.
2508 @param SlotId The slot id to be disabled.
2509
2510 @retval EFI_SUCCESS Successfully disable the device slot.
2511
2512 **/
2513 EFI_STATUS
2514 EFIAPI
2515 XhcDisableSlotCmd (
2516 IN USB_XHCI_INSTANCE *Xhc,
2517 IN UINT8 SlotId
2518 )
2519 {
2520 EFI_STATUS Status;
2521 TRB_TEMPLATE *EvtTrb;
2522 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2523 UINT8 Index;
2524 VOID *RingSeg;
2525
2526 //
2527 // Disable the device slots occupied by these devices on its downstream ports.
2528 // Entry 0 is reserved.
2529 //
2530 for (Index = 0; Index < 255; Index++) {
2531 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2532 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2533 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2534 continue;
2535 }
2536
2537 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2538
2539 if (EFI_ERROR (Status)) {
2540 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2541 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2542 }
2543 }
2544
2545 //
2546 // Construct the disable slot command
2547 //
2548 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2549
2550 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2551 CmdTrbDisSlot.CycleBit = 1;
2552 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2553 CmdTrbDisSlot.SlotId = SlotId;
2554 Status = XhcCmdTransfer (
2555 Xhc,
2556 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2557 XHC_GENERIC_TIMEOUT,
2558 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2559 );
2560 if (EFI_ERROR (Status)) {
2561 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2562 return Status;
2563 }
2564 //
2565 // Free the slot's device context entry
2566 //
2567 Xhc->DCBAA[SlotId] = 0;
2568
2569 //
2570 // Free the slot related data structure
2571 //
2572 for (Index = 0; Index < 31; Index++) {
2573 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2574 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2575 if (RingSeg != NULL) {
2576 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2577 }
2578 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2579 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2580 }
2581 }
2582
2583 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2584 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2585 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2586 }
2587 }
2588
2589 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2590 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2591 }
2592
2593 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2594 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2595 }
2596
2597 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2598 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
2599 }
2600 //
2601 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2602 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2603 // remove urb from XHCI's asynchronous transfer list.
2604 //
2605 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2606 Xhc->UsbDevContext[SlotId].SlotId = 0;
2607
2608 return Status;
2609 }
2610
2611 /**
2612 Disable the specified device slot.
2613
2614 @param Xhc The XHCI Instance.
2615 @param SlotId The slot id to be disabled.
2616
2617 @retval EFI_SUCCESS Successfully disable the device slot.
2618
2619 **/
2620 EFI_STATUS
2621 EFIAPI
2622 XhcDisableSlotCmd64 (
2623 IN USB_XHCI_INSTANCE *Xhc,
2624 IN UINT8 SlotId
2625 )
2626 {
2627 EFI_STATUS Status;
2628 TRB_TEMPLATE *EvtTrb;
2629 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2630 UINT8 Index;
2631 VOID *RingSeg;
2632
2633 //
2634 // Disable the device slots occupied by these devices on its downstream ports.
2635 // Entry 0 is reserved.
2636 //
2637 for (Index = 0; Index < 255; Index++) {
2638 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2639 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2640 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2641 continue;
2642 }
2643
2644 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2645
2646 if (EFI_ERROR (Status)) {
2647 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2648 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2649 }
2650 }
2651
2652 //
2653 // Construct the disable slot command
2654 //
2655 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2656
2657 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2658 CmdTrbDisSlot.CycleBit = 1;
2659 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2660 CmdTrbDisSlot.SlotId = SlotId;
2661 Status = XhcCmdTransfer (
2662 Xhc,
2663 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2664 XHC_GENERIC_TIMEOUT,
2665 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2666 );
2667 if (EFI_ERROR (Status)) {
2668 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2669 return Status;
2670 }
2671 //
2672 // Free the slot's device context entry
2673 //
2674 Xhc->DCBAA[SlotId] = 0;
2675
2676 //
2677 // Free the slot related data structure
2678 //
2679 for (Index = 0; Index < 31; Index++) {
2680 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2681 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2682 if (RingSeg != NULL) {
2683 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2684 }
2685 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2686 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2687 }
2688 }
2689
2690 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2691 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2692 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2693 }
2694 }
2695
2696 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2697 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2698 }
2699
2700 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2701 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2702 }
2703
2704 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2705 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
2706 }
2707 //
2708 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2709 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2710 // remove urb from XHCI's asynchronous transfer list.
2711 //
2712 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2713 Xhc->UsbDevContext[SlotId].SlotId = 0;
2714
2715 return Status;
2716 }
2717
2718 /**
2719 Initialize endpoint context in input context.
2720
2721 @param Xhc The XHCI Instance.
2722 @param SlotId The slot id to be configured.
2723 @param DeviceSpeed The device's speed.
2724 @param InputContext The pointer to the input context.
2725 @param IfDesc The pointer to the usb device interface descriptor.
2726
2727 @return The maximum device context index of endpoint.
2728
2729 **/
2730 UINT8
2731 EFIAPI
2732 XhcInitializeEndpointContext (
2733 IN USB_XHCI_INSTANCE *Xhc,
2734 IN UINT8 SlotId,
2735 IN UINT8 DeviceSpeed,
2736 IN INPUT_CONTEXT *InputContext,
2737 IN USB_INTERFACE_DESCRIPTOR *IfDesc
2738 )
2739 {
2740 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2741 UINTN NumEp;
2742 UINTN EpIndex;
2743 UINT8 EpAddr;
2744 UINT8 Direction;
2745 UINT8 Dci;
2746 UINT8 MaxDci;
2747 EFI_PHYSICAL_ADDRESS PhyAddr;
2748 UINT8 Interval;
2749 TRANSFER_RING *EndpointTransferRing;
2750
2751 MaxDci = 0;
2752
2753 NumEp = IfDesc->NumEndpoints;
2754
2755 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2756 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2757 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2758 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2759 }
2760
2761 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2762 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2763 continue;
2764 }
2765
2766 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2767 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2768
2769 Dci = XhcEndpointToDci (EpAddr, Direction);
2770 ASSERT (Dci < 32);
2771 if (Dci > MaxDci) {
2772 MaxDci = Dci;
2773 }
2774
2775 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2776 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2777
2778 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2779 //
2780 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2781 //
2782 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2783 } else {
2784 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2785 }
2786
2787 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2788 case USB_ENDPOINT_BULK:
2789 if (Direction == EfiUsbDataIn) {
2790 InputContext->EP[Dci-1].CErr = 3;
2791 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2792 } else {
2793 InputContext->EP[Dci-1].CErr = 3;
2794 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2795 }
2796
2797 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2798 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2799 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2800 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2801 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2802 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2803 EpDesc->EndpointAddress,
2804 EndpointTransferRing->RingSeg0,
2805 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2806 ));
2807 }
2808
2809 break;
2810 case USB_ENDPOINT_ISO:
2811 if (Direction == EfiUsbDataIn) {
2812 InputContext->EP[Dci-1].CErr = 0;
2813 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2814 } else {
2815 InputContext->EP[Dci-1].CErr = 0;
2816 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2817 }
2818 //
2819 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2820 // Refer to XHCI 1.1 spec section 6.2.3.6.
2821 //
2822 if (DeviceSpeed == EFI_USB_SPEED_FULL) {
2823 Interval = EpDesc->Interval;
2824 ASSERT (Interval >= 1 && Interval <= 16);
2825 InputContext->EP[Dci-1].Interval = Interval + 2;
2826 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2827 Interval = EpDesc->Interval;
2828 ASSERT (Interval >= 1 && Interval <= 16);
2829 InputContext->EP[Dci-1].Interval = Interval - 1;
2830 }
2831
2832 //
2833 // Do not support isochronous transfer now.
2834 //
2835 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2836 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2837 continue;
2838 case USB_ENDPOINT_INTERRUPT:
2839 if (Direction == EfiUsbDataIn) {
2840 InputContext->EP[Dci-1].CErr = 3;
2841 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2842 } else {
2843 InputContext->EP[Dci-1].CErr = 3;
2844 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2845 }
2846 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2847 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2848 //
2849 // Get the bInterval from descriptor and init the the interval field of endpoint context
2850 //
2851 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2852 Interval = EpDesc->Interval;
2853 //
2854 // Calculate through the bInterval field of Endpoint descriptor.
2855 //
2856 ASSERT (Interval != 0);
2857 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
2858 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2859 Interval = EpDesc->Interval;
2860 ASSERT (Interval >= 1 && Interval <= 16);
2861 //
2862 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2863 //
2864 InputContext->EP[Dci-1].Interval = Interval - 1;
2865 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2866 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2867 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2868 InputContext->EP[Dci-1].CErr = 3;
2869 }
2870
2871 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2872 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2873 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2874 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2875 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2876 EpDesc->EndpointAddress,
2877 EndpointTransferRing->RingSeg0,
2878 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2879 ));
2880 }
2881 break;
2882
2883 case USB_ENDPOINT_CONTROL:
2884 //
2885 // Do not support control transfer now.
2886 //
2887 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2888 default:
2889 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2890 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2891 continue;
2892 }
2893
2894 PhyAddr = UsbHcGetPciAddrForHostAddr (
2895 Xhc->MemPool,
2896 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2897 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2898 );
2899 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2900 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2901 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2902 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2903
2904 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2905 }
2906
2907 return MaxDci;
2908 }
2909
2910 /**
2911 Initialize endpoint context in input context.
2912
2913 @param Xhc The XHCI Instance.
2914 @param SlotId The slot id to be configured.
2915 @param DeviceSpeed The device's speed.
2916 @param InputContext The pointer to the input context.
2917 @param IfDesc The pointer to the usb device interface descriptor.
2918
2919 @return The maximum device context index of endpoint.
2920
2921 **/
2922 UINT8
2923 EFIAPI
2924 XhcInitializeEndpointContext64 (
2925 IN USB_XHCI_INSTANCE *Xhc,
2926 IN UINT8 SlotId,
2927 IN UINT8 DeviceSpeed,
2928 IN INPUT_CONTEXT_64 *InputContext,
2929 IN USB_INTERFACE_DESCRIPTOR *IfDesc
2930 )
2931 {
2932 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2933 UINTN NumEp;
2934 UINTN EpIndex;
2935 UINT8 EpAddr;
2936 UINT8 Direction;
2937 UINT8 Dci;
2938 UINT8 MaxDci;
2939 EFI_PHYSICAL_ADDRESS PhyAddr;
2940 UINT8 Interval;
2941 TRANSFER_RING *EndpointTransferRing;
2942
2943 MaxDci = 0;
2944
2945 NumEp = IfDesc->NumEndpoints;
2946
2947 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2948 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2949 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2950 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2951 }
2952
2953 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2954 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2955 continue;
2956 }
2957
2958 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2959 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2960
2961 Dci = XhcEndpointToDci (EpAddr, Direction);
2962 ASSERT (Dci < 32);
2963 if (Dci > MaxDci) {
2964 MaxDci = Dci;
2965 }
2966
2967 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2968 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2969
2970 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2971 //
2972 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2973 //
2974 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2975 } else {
2976 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2977 }
2978
2979 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2980 case USB_ENDPOINT_BULK:
2981 if (Direction == EfiUsbDataIn) {
2982 InputContext->EP[Dci-1].CErr = 3;
2983 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2984 } else {
2985 InputContext->EP[Dci-1].CErr = 3;
2986 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2987 }
2988
2989 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2990 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2991 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2992 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2993 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2994 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
2995 EpDesc->EndpointAddress,
2996 EndpointTransferRing->RingSeg0,
2997 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2998 ));
2999 }
3000
3001 break;
3002 case USB_ENDPOINT_ISO:
3003 if (Direction == EfiUsbDataIn) {
3004 InputContext->EP[Dci-1].CErr = 0;
3005 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
3006 } else {
3007 InputContext->EP[Dci-1].CErr = 0;
3008 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
3009 }
3010 //
3011 // Get the bInterval from descriptor and init the the interval field of endpoint context.
3012 // Refer to XHCI 1.1 spec section 6.2.3.6.
3013 //
3014 if (DeviceSpeed == EFI_USB_SPEED_FULL) {
3015 Interval = EpDesc->Interval;
3016 ASSERT (Interval >= 1 && Interval <= 16);
3017 InputContext->EP[Dci-1].Interval = Interval + 2;
3018 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
3019 Interval = EpDesc->Interval;
3020 ASSERT (Interval >= 1 && Interval <= 16);
3021 InputContext->EP[Dci-1].Interval = Interval - 1;
3022 }
3023
3024 //
3025 // Do not support isochronous transfer now.
3026 //
3027 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
3028 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3029 continue;
3030 case USB_ENDPOINT_INTERRUPT:
3031 if (Direction == EfiUsbDataIn) {
3032 InputContext->EP[Dci-1].CErr = 3;
3033 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
3034 } else {
3035 InputContext->EP[Dci-1].CErr = 3;
3036 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
3037 }
3038 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
3039 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
3040 //
3041 // Get the bInterval from descriptor and init the the interval field of endpoint context
3042 //
3043 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
3044 Interval = EpDesc->Interval;
3045 //
3046 // Calculate through the bInterval field of Endpoint descriptor.
3047 //
3048 ASSERT (Interval != 0);
3049 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
3050 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
3051 Interval = EpDesc->Interval;
3052 ASSERT (Interval >= 1 && Interval <= 16);
3053 //
3054 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
3055 //
3056 InputContext->EP[Dci-1].Interval = Interval - 1;
3057 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
3058 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
3059 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
3060 InputContext->EP[Dci-1].CErr = 3;
3061 }
3062
3063 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
3064 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
3065 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
3066 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
3067 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
3068 EpDesc->EndpointAddress,
3069 EndpointTransferRing->RingSeg0,
3070 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
3071 ));
3072 }
3073 break;
3074
3075 case USB_ENDPOINT_CONTROL:
3076 //
3077 // Do not support control transfer now.
3078 //
3079 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
3080 default:
3081 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
3082 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3083 continue;
3084 }
3085
3086 PhyAddr = UsbHcGetPciAddrForHostAddr (
3087 Xhc->MemPool,
3088 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
3089 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
3090 );
3091 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
3092 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
3093 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
3094 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
3095
3096 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3097 }
3098
3099 return MaxDci;
3100 }
3101
3102 /**
3103 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3104
3105 @param Xhc The XHCI Instance.
3106 @param SlotId The slot id to be configured.
3107 @param DeviceSpeed The device's speed.
3108 @param ConfigDesc The pointer to the usb device configuration descriptor.
3109
3110 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3111
3112 **/
3113 EFI_STATUS
3114 EFIAPI
3115 XhcSetConfigCmd (
3116 IN USB_XHCI_INSTANCE *Xhc,
3117 IN UINT8 SlotId,
3118 IN UINT8 DeviceSpeed,
3119 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
3120 )
3121 {
3122 EFI_STATUS Status;
3123 USB_INTERFACE_DESCRIPTOR *IfDesc;
3124 UINT8 Index;
3125 UINT8 Dci;
3126 UINT8 MaxDci;
3127 EFI_PHYSICAL_ADDRESS PhyAddr;
3128
3129 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3130 INPUT_CONTEXT *InputContext;
3131 DEVICE_CONTEXT *OutputContext;
3132 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3133 //
3134 // 4.6.6 Configure Endpoint
3135 //
3136 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3137 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3138 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3139 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3140
3141 ASSERT (ConfigDesc != NULL);
3142
3143 MaxDci = 0;
3144
3145 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3146 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3147 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3148 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3149 }
3150
3151 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3152 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3153 continue;
3154 }
3155
3156 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3157 if (Dci > MaxDci) {
3158 MaxDci = Dci;
3159 }
3160
3161 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3162 }
3163
3164 InputContext->InputControlContext.Dword2 |= BIT0;
3165 InputContext->Slot.ContextEntries = MaxDci;
3166 //
3167 // configure endpoint
3168 //
3169 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3170 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3171 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3172 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3173 CmdTrbCfgEP.CycleBit = 1;
3174 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3175 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3176 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3177 Status = XhcCmdTransfer (
3178 Xhc,
3179 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3180 XHC_GENERIC_TIMEOUT,
3181 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3182 );
3183 if (EFI_ERROR (Status)) {
3184 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
3185 } else {
3186 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3187 }
3188
3189 return Status;
3190 }
3191
3192 /**
3193 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3194
3195 @param Xhc The XHCI Instance.
3196 @param SlotId The slot id to be configured.
3197 @param DeviceSpeed The device's speed.
3198 @param ConfigDesc The pointer to the usb device configuration descriptor.
3199
3200 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3201
3202 **/
3203 EFI_STATUS
3204 EFIAPI
3205 XhcSetConfigCmd64 (
3206 IN USB_XHCI_INSTANCE *Xhc,
3207 IN UINT8 SlotId,
3208 IN UINT8 DeviceSpeed,
3209 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
3210 )
3211 {
3212 EFI_STATUS Status;
3213 USB_INTERFACE_DESCRIPTOR *IfDesc;
3214 UINT8 Index;
3215 UINT8 Dci;
3216 UINT8 MaxDci;
3217 EFI_PHYSICAL_ADDRESS PhyAddr;
3218
3219 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3220 INPUT_CONTEXT_64 *InputContext;
3221 DEVICE_CONTEXT_64 *OutputContext;
3222 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3223 //
3224 // 4.6.6 Configure Endpoint
3225 //
3226 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3227 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3228 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3229 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3230
3231 ASSERT (ConfigDesc != NULL);
3232
3233 MaxDci = 0;
3234
3235 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3236 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3237 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3238 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3239 }
3240
3241 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3242 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3243 continue;
3244 }
3245
3246 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3247 if (Dci > MaxDci) {
3248 MaxDci = Dci;
3249 }
3250
3251 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3252 }
3253
3254 InputContext->InputControlContext.Dword2 |= BIT0;
3255 InputContext->Slot.ContextEntries = MaxDci;
3256 //
3257 // configure endpoint
3258 //
3259 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3260 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3261 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3262 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3263 CmdTrbCfgEP.CycleBit = 1;
3264 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3265 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3266 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3267 Status = XhcCmdTransfer (
3268 Xhc,
3269 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3270 XHC_GENERIC_TIMEOUT,
3271 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3272 );
3273 if (EFI_ERROR (Status)) {
3274 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
3275 } else {
3276 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3277 }
3278
3279 return Status;
3280 }
3281
3282 /**
3283 Stop endpoint through XHCI's Stop_Endpoint cmd.
3284
3285 @param Xhc The XHCI Instance.
3286 @param SlotId The slot id to be configured.
3287 @param Dci The device context index of endpoint.
3288 @param PendingUrb The pending URB to check completion status when stopping the end point.
3289
3290 @retval EFI_SUCCESS Stop endpoint successfully.
3291 @retval Others Failed to stop endpoint.
3292
3293 **/
3294 EFI_STATUS
3295 EFIAPI
3296 XhcStopEndpoint (
3297 IN USB_XHCI_INSTANCE *Xhc,
3298 IN UINT8 SlotId,
3299 IN UINT8 Dci,
3300 IN URB *PendingUrb OPTIONAL
3301 )
3302 {
3303 EFI_STATUS Status;
3304 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3305 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;
3306
3307 DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3308
3309 //
3310 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
3311 // the PendingUrb completion status, because it's possible that the PendingUrb is
3312 // finished just before stopping the end point, but after the looping check.
3313 //
3314 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
3315 // through function parameter, but That will cause every consumer of XhcCmdTransfer,
3316 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
3317 // But actually only XhcCheckUrbResult is aware of the PendingUrb.
3318 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
3319 //
3320 ASSERT (Xhc->PendingUrb == NULL);
3321 Xhc->PendingUrb = PendingUrb;
3322 //
3323 // Reset the URB result from Timeout to NoError.
3324 // The USB result will be:
3325 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
3326 // remain NoError when Success/ShortPacket Transfer Event is received.
3327 //
3328 if (PendingUrb != NULL) {
3329 PendingUrb->Result = EFI_USB_NOERROR;
3330 }
3331
3332 //
3333 // Send stop endpoint command to transit Endpoint from running to stop state
3334 //
3335 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
3336 CmdTrbStopED.CycleBit = 1;
3337 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;
3338 CmdTrbStopED.EDID = Dci;
3339 CmdTrbStopED.SlotId = SlotId;
3340 Status = XhcCmdTransfer (
3341 Xhc,
3342 (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
3343 XHC_GENERIC_TIMEOUT,
3344 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3345 );
3346 if (EFI_ERROR(Status)) {
3347 DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
3348 }
3349
3350 Xhc->PendingUrb = NULL;
3351
3352 return Status;
3353 }
3354
3355 /**
3356 Reset endpoint through XHCI's Reset_Endpoint cmd.
3357
3358 @param Xhc The XHCI Instance.
3359 @param SlotId The slot id to be configured.
3360 @param Dci The device context index of endpoint.
3361
3362 @retval EFI_SUCCESS Reset endpoint successfully.
3363 @retval Others Failed to reset endpoint.
3364
3365 **/
3366 EFI_STATUS
3367 EFIAPI
3368 XhcResetEndpoint (
3369 IN USB_XHCI_INSTANCE *Xhc,
3370 IN UINT8 SlotId,
3371 IN UINT8 Dci
3372 )
3373 {
3374 EFI_STATUS Status;
3375 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3376 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
3377
3378 DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3379
3380 //
3381 // Send stop endpoint command to transit Endpoint from running to stop state
3382 //
3383 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
3384 CmdTrbResetED.CycleBit = 1;
3385 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
3386 CmdTrbResetED.EDID = Dci;
3387 CmdTrbResetED.SlotId = SlotId;
3388 Status = XhcCmdTransfer (
3389 Xhc,
3390 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
3391 XHC_GENERIC_TIMEOUT,
3392 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3393 );
3394 if (EFI_ERROR(Status)) {
3395 DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
3396 }
3397
3398 return Status;
3399 }
3400
3401 /**
3402 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3403
3404 @param Xhc The XHCI Instance.
3405 @param SlotId The slot id to be configured.
3406 @param Dci The device context index of endpoint.
3407 @param Urb The dequeue pointer of the transfer ring specified
3408 by the urb to be updated.
3409
3410 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3411 @retval Others Failed to set transfer ring dequeue pointer.
3412
3413 **/
3414 EFI_STATUS
3415 EFIAPI
3416 XhcSetTrDequeuePointer (
3417 IN USB_XHCI_INSTANCE *Xhc,
3418 IN UINT8 SlotId,
3419 IN UINT8 Dci,
3420 IN URB *Urb
3421 )
3422 {
3423 EFI_STATUS Status;
3424 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3425 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
3426 EFI_PHYSICAL_ADDRESS PhyAddr;
3427
3428 DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
3429
3430 //
3431 // Send stop endpoint command to transit Endpoint from running to stop state
3432 //
3433 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
3434 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
3435 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
3436 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3437 CmdSetTRDeq.CycleBit = 1;
3438 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
3439 CmdSetTRDeq.Endpoint = Dci;
3440 CmdSetTRDeq.SlotId = SlotId;
3441 Status = XhcCmdTransfer (
3442 Xhc,
3443 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
3444 XHC_GENERIC_TIMEOUT,
3445 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3446 );
3447 if (EFI_ERROR(Status)) {
3448 DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
3449 }
3450
3451 return Status;
3452 }
3453
3454 /**
3455 Set interface through XHCI's Configure_Endpoint cmd.
3456
3457 @param Xhc The XHCI Instance.
3458 @param SlotId The slot id to be configured.
3459 @param DeviceSpeed The device's speed.
3460 @param ConfigDesc The pointer to the usb device configuration descriptor.
3461 @param Request USB device request to send.
3462
3463 @retval EFI_SUCCESS Successfully set interface.
3464
3465 **/
3466 EFI_STATUS
3467 EFIAPI
3468 XhcSetInterface (
3469 IN USB_XHCI_INSTANCE *Xhc,
3470 IN UINT8 SlotId,
3471 IN UINT8 DeviceSpeed,
3472 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
3473 IN EFI_USB_DEVICE_REQUEST *Request
3474 )
3475 {
3476 EFI_STATUS Status;
3477 USB_INTERFACE_DESCRIPTOR *IfDescActive;
3478 USB_INTERFACE_DESCRIPTOR *IfDescSet;
3479 USB_INTERFACE_DESCRIPTOR *IfDesc;
3480 USB_ENDPOINT_DESCRIPTOR *EpDesc;
3481 UINTN NumEp;
3482 UINTN EpIndex;
3483 UINT8 EpAddr;
3484 UINT8 Direction;
3485 UINT8 Dci;
3486 UINT8 MaxDci;
3487 EFI_PHYSICAL_ADDRESS PhyAddr;
3488 VOID *RingSeg;
3489
3490 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3491 INPUT_CONTEXT *InputContext;
3492 DEVICE_CONTEXT *OutputContext;
3493 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3494
3495 Status = EFI_SUCCESS;
3496
3497 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3498 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3499 //
3500 // XHCI 4.6.6 Configure Endpoint
3501 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3502 // Context and Add Context flags as follows:
3503 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3504 // Context and Add Context flags to '0'.
3505 //
3506 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3507 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3508 //
3509 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3510 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3511
3512 ASSERT (ConfigDesc != NULL);
3513
3514 MaxDci = 0;
3515
3516 IfDescActive = NULL;
3517 IfDescSet = NULL;
3518
3519 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3520 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3521 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3522 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3523 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3524 //
3525 // Find out the active interface descriptor.
3526 //
3527 IfDescActive = IfDesc;
3528 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3529 //
3530 // Find out the interface descriptor to set.
3531 //
3532 IfDescSet = IfDesc;
3533 }
3534 }
3535 }
3536 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3537 }
3538
3539 //
3540 // XHCI 4.6.6 Configure Endpoint
3541 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3542 // Context and Add Context flags as follows:
3543 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3544 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3545 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3546 // the Drop Context flag to '1' and Add Context flag to '0'.
3547 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3548 // and Add Context flags shall be set to '1'.
3549 //
3550 // Below codes are to cover 2), 3) and 4).
3551 //
3552
3553 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3554 NumEp = IfDescActive->NumEndpoints;
3555 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3556 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3557 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3558 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3559 }
3560
3561 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3562 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3563 continue;
3564 }
3565
3566 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3567 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3568
3569 Dci = XhcEndpointToDci (EpAddr, Direction);
3570 ASSERT (Dci < 32);
3571 if (Dci > MaxDci) {
3572 MaxDci = Dci;
3573 }
3574 //
3575 // XHCI 4.3.6 - Setting Alternate Interfaces
3576 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3577 //
3578 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
3579 if (EFI_ERROR (Status)) {
3580 return Status;
3581 }
3582 //
3583 // XHCI 4.3.6 - Setting Alternate Interfaces
3584 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3585 //
3586 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3587 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3588 if (RingSeg != NULL) {
3589 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3590 }
3591 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3592 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3593 }
3594
3595 //
3596 // Set the Drop Context flag to '1'.
3597 //
3598 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3599
3600 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3601 }
3602
3603 //
3604 // XHCI 4.3.6 - Setting Alternate Interfaces
3605 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3606 // Interface setting, to '0'.
3607 //
3608 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3609 //
3610
3611 //
3612 // XHCI 4.3.6 - Setting Alternate Interfaces
3613 // 4) For each endpoint enabled by the Configure Endpoint Command:
3614 // a. Allocate a Transfer Ring.
3615 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3616 // c. Initialize the Endpoint Context data structure.
3617 //
3618 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3619 if (Dci > MaxDci) {
3620 MaxDci = Dci;
3621 }
3622
3623 InputContext->InputControlContext.Dword2 |= BIT0;
3624 InputContext->Slot.ContextEntries = MaxDci;
3625 //
3626 // XHCI 4.3.6 - Setting Alternate Interfaces
3627 // 5) Issue and successfully complete a Configure Endpoint Command.
3628 //
3629 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3630 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3631 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3632 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3633 CmdTrbCfgEP.CycleBit = 1;
3634 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3635 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3636 DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));
3637 Status = XhcCmdTransfer (
3638 Xhc,
3639 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3640 XHC_GENERIC_TIMEOUT,
3641 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3642 );
3643 if (EFI_ERROR (Status)) {
3644 DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));
3645 } else {
3646 //
3647 // Update the active AlternateSetting.
3648 //
3649 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3650 }
3651 }
3652
3653 return Status;
3654 }
3655
3656 /**
3657 Set interface through XHCI's Configure_Endpoint cmd.
3658
3659 @param Xhc The XHCI Instance.
3660 @param SlotId The slot id to be configured.
3661 @param DeviceSpeed The device's speed.
3662 @param ConfigDesc The pointer to the usb device configuration descriptor.
3663 @param Request USB device request to send.
3664
3665 @retval EFI_SUCCESS Successfully set interface.
3666
3667 **/
3668 EFI_STATUS
3669 EFIAPI
3670 XhcSetInterface64 (
3671 IN USB_XHCI_INSTANCE *Xhc,
3672 IN UINT8 SlotId,
3673 IN UINT8 DeviceSpeed,
3674 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
3675 IN EFI_USB_DEVICE_REQUEST *Request
3676 )
3677 {
3678 EFI_STATUS Status;
3679 USB_INTERFACE_DESCRIPTOR *IfDescActive;
3680 USB_INTERFACE_DESCRIPTOR *IfDescSet;
3681 USB_INTERFACE_DESCRIPTOR *IfDesc;
3682 USB_ENDPOINT_DESCRIPTOR *EpDesc;
3683 UINTN NumEp;
3684 UINTN EpIndex;
3685 UINT8 EpAddr;
3686 UINT8 Direction;
3687 UINT8 Dci;
3688 UINT8 MaxDci;
3689 EFI_PHYSICAL_ADDRESS PhyAddr;
3690 VOID *RingSeg;
3691
3692 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3693 INPUT_CONTEXT_64 *InputContext;
3694 DEVICE_CONTEXT_64 *OutputContext;
3695 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3696
3697 Status = EFI_SUCCESS;
3698
3699 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3700 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3701 //
3702 // XHCI 4.6.6 Configure Endpoint
3703 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3704 // Context and Add Context flags as follows:
3705 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3706 // Context and Add Context flags to '0'.
3707 //
3708 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3709 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3710 //
3711 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3712 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3713
3714 ASSERT (ConfigDesc != NULL);
3715
3716 MaxDci = 0;
3717
3718 IfDescActive = NULL;
3719 IfDescSet = NULL;
3720
3721 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3722 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3723 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3724 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3725 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3726 //
3727 // Find out the active interface descriptor.
3728 //
3729 IfDescActive = IfDesc;
3730 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3731 //
3732 // Find out the interface descriptor to set.
3733 //
3734 IfDescSet = IfDesc;
3735 }
3736 }
3737 }
3738 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3739 }
3740
3741 //
3742 // XHCI 4.6.6 Configure Endpoint
3743 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3744 // Context and Add Context flags as follows:
3745 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3746 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3747 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3748 // the Drop Context flag to '1' and Add Context flag to '0'.
3749 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3750 // and Add Context flags shall be set to '1'.
3751 //
3752 // Below codes are to cover 2), 3) and 4).
3753 //
3754
3755 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3756 NumEp = IfDescActive->NumEndpoints;
3757 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3758 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3759 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3760 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3761 }
3762
3763 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3764 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3765 continue;
3766 }
3767
3768 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3769 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3770
3771 Dci = XhcEndpointToDci (EpAddr, Direction);
3772 ASSERT (Dci < 32);
3773 if (Dci > MaxDci) {
3774 MaxDci = Dci;
3775 }
3776 //
3777 // XHCI 4.3.6 - Setting Alternate Interfaces
3778 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3779 //
3780 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
3781 if (EFI_ERROR (Status)) {
3782 return Status;
3783 }
3784 //
3785 // XHCI 4.3.6 - Setting Alternate Interfaces
3786 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3787 //
3788 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3789 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3790 if (RingSeg != NULL) {
3791 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3792 }
3793 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3794 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3795 }
3796
3797 //
3798 // Set the Drop Context flag to '1'.
3799 //
3800 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3801
3802 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3803 }
3804
3805 //
3806 // XHCI 4.3.6 - Setting Alternate Interfaces
3807 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3808 // Interface setting, to '0'.
3809 //
3810 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3811 //
3812
3813 //
3814 // XHCI 4.3.6 - Setting Alternate Interfaces
3815 // 4) For each endpoint enabled by the Configure Endpoint Command:
3816 // a. Allocate a Transfer Ring.
3817 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3818 // c. Initialize the Endpoint Context data structure.
3819 //
3820 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3821 if (Dci > MaxDci) {
3822 MaxDci = Dci;
3823 }
3824
3825 InputContext->InputControlContext.Dword2 |= BIT0;
3826 InputContext->Slot.ContextEntries = MaxDci;
3827 //
3828 // XHCI 4.3.6 - Setting Alternate Interfaces
3829 // 5) Issue and successfully complete a Configure Endpoint Command.
3830 //
3831 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3832 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3833 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3834 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3835 CmdTrbCfgEP.CycleBit = 1;
3836 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3837 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3838 DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));
3839 Status = XhcCmdTransfer (
3840 Xhc,
3841 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3842 XHC_GENERIC_TIMEOUT,
3843 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3844 );
3845 if (EFI_ERROR (Status)) {
3846 DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));
3847 } else {
3848 //
3849 // Update the active AlternateSetting.
3850 //
3851 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3852 }
3853 }
3854
3855 return Status;
3856 }
3857
3858 /**
3859 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3860
3861 @param Xhc The XHCI Instance.
3862 @param SlotId The slot id to be evaluated.
3863 @param MaxPacketSize The max packet size supported by the device control transfer.
3864
3865 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3866
3867 **/
3868 EFI_STATUS
3869 EFIAPI
3870 XhcEvaluateContext (
3871 IN USB_XHCI_INSTANCE *Xhc,
3872 IN UINT8 SlotId,
3873 IN UINT32 MaxPacketSize
3874 )
3875 {
3876 EFI_STATUS Status;
3877 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
3878 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3879 INPUT_CONTEXT *InputContext;
3880 EFI_PHYSICAL_ADDRESS PhyAddr;
3881
3882 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3883
3884 //
3885 // 4.6.7 Evaluate Context
3886 //
3887 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3888 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3889
3890 InputContext->InputControlContext.Dword2 |= BIT1;
3891 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
3892
3893 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3894 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3895 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
3896 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3897 CmdTrbEvalu.CycleBit = 1;
3898 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
3899 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3900 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3901 Status = XhcCmdTransfer (
3902 Xhc,
3903 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3904 XHC_GENERIC_TIMEOUT,
3905 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3906 );
3907 if (EFI_ERROR (Status)) {
3908 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
3909 }
3910 return Status;
3911 }
3912
3913 /**
3914 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3915
3916 @param Xhc The XHCI Instance.
3917 @param SlotId The slot id to be evaluated.
3918 @param MaxPacketSize The max packet size supported by the device control transfer.
3919
3920 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3921
3922 **/
3923 EFI_STATUS
3924 EFIAPI
3925 XhcEvaluateContext64 (
3926 IN USB_XHCI_INSTANCE *Xhc,
3927 IN UINT8 SlotId,
3928 IN UINT32 MaxPacketSize
3929 )
3930 {
3931 EFI_STATUS Status;
3932 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
3933 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3934 INPUT_CONTEXT_64 *InputContext;
3935 EFI_PHYSICAL_ADDRESS PhyAddr;
3936
3937 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3938
3939 //
3940 // 4.6.7 Evaluate Context
3941 //
3942 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3943 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3944
3945 InputContext->InputControlContext.Dword2 |= BIT1;
3946 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
3947
3948 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3949 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3950 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
3951 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3952 CmdTrbEvalu.CycleBit = 1;
3953 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
3954 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3955 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3956 Status = XhcCmdTransfer (
3957 Xhc,
3958 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3959 XHC_GENERIC_TIMEOUT,
3960 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3961 );
3962 if (EFI_ERROR (Status)) {
3963 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
3964 }
3965 return Status;
3966 }
3967
3968
3969 /**
3970 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3971
3972 @param Xhc The XHCI Instance.
3973 @param SlotId The slot id to be configured.
3974 @param PortNum The total number of downstream port supported by the hub.
3975 @param TTT The TT think time of the hub device.
3976 @param MTT The multi-TT of the hub device.
3977
3978 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3979
3980 **/
3981 EFI_STATUS
3982 XhcConfigHubContext (
3983 IN USB_XHCI_INSTANCE *Xhc,
3984 IN UINT8 SlotId,
3985 IN UINT8 PortNum,
3986 IN UINT8 TTT,
3987 IN UINT8 MTT
3988 )
3989 {
3990 EFI_STATUS Status;
3991 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3992 INPUT_CONTEXT *InputContext;
3993 DEVICE_CONTEXT *OutputContext;
3994 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3995 EFI_PHYSICAL_ADDRESS PhyAddr;
3996
3997 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3998 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3999 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
4000
4001 //
4002 // 4.6.7 Evaluate Context
4003 //
4004 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
4005
4006 InputContext->InputControlContext.Dword2 |= BIT0;
4007
4008 //
4009 // Copy the slot context from OutputContext to Input context
4010 //
4011 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
4012 InputContext->Slot.Hub = 1;
4013 InputContext->Slot.PortNum = PortNum;
4014 InputContext->Slot.TTT = TTT;
4015 InputContext->Slot.MTT = MTT;
4016
4017 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
4018 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
4019 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
4020 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
4021 CmdTrbCfgEP.CycleBit = 1;
4022 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
4023 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
4024 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
4025 Status = XhcCmdTransfer (
4026 Xhc,
4027 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
4028 XHC_GENERIC_TIMEOUT,
4029 (TRB_TEMPLATE **) (UINTN) &EvtTrb
4030 );
4031 if (EFI_ERROR (Status)) {
4032 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
4033 }
4034 return Status;
4035 }
4036
4037 /**
4038 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
4039
4040 @param Xhc The XHCI Instance.
4041 @param SlotId The slot id to be configured.
4042 @param PortNum The total number of downstream port supported by the hub.
4043 @param TTT The TT think time of the hub device.
4044 @param MTT The multi-TT of the hub device.
4045
4046 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
4047
4048 **/
4049 EFI_STATUS
4050 XhcConfigHubContext64 (
4051 IN USB_XHCI_INSTANCE *Xhc,
4052 IN UINT8 SlotId,
4053 IN UINT8 PortNum,
4054 IN UINT8 TTT,
4055 IN UINT8 MTT
4056 )
4057 {
4058 EFI_STATUS Status;
4059 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
4060 INPUT_CONTEXT_64 *InputContext;
4061 DEVICE_CONTEXT_64 *OutputContext;
4062 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
4063 EFI_PHYSICAL_ADDRESS PhyAddr;
4064
4065 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
4066 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
4067 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
4068
4069 //
4070 // 4.6.7 Evaluate Context
4071 //
4072 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
4073
4074 InputContext->InputControlContext.Dword2 |= BIT0;
4075
4076 //
4077 // Copy the slot context from OutputContext to Input context
4078 //
4079 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
4080 InputContext->Slot.Hub = 1;
4081 InputContext->Slot.PortNum = PortNum;
4082 InputContext->Slot.TTT = TTT;
4083 InputContext->Slot.MTT = MTT;
4084
4085 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
4086 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
4087 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
4088 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
4089 CmdTrbCfgEP.CycleBit = 1;
4090 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
4091 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
4092 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
4093 Status = XhcCmdTransfer (
4094 Xhc,
4095 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
4096 XHC_GENERIC_TIMEOUT,
4097 (TRB_TEMPLATE **) (UINTN) &EvtTrb
4098 );
4099 if (EFI_ERROR (Status)) {
4100 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
4101 }
4102 return Status;
4103 }
4104
4105