]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg/XhciDxe: Fix Broken Timeouts
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
1 /** @file
2
3 XHCI transfer scheduling routines.
4
5 Copyright (c) 2011 - 2018, 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 }
2283
2284 return Status;
2285 }
2286
2287 /**
2288 Assign and initialize the device slot for a new device.
2289
2290 @param Xhc The XHCI Instance.
2291 @param ParentRouteChart The route string pointed to the parent device.
2292 @param ParentPort The port at which the device is located.
2293 @param RouteChart The route string pointed to the device.
2294 @param DeviceSpeed The device speed.
2295
2296 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2297
2298 **/
2299 EFI_STATUS
2300 EFIAPI
2301 XhcInitializeDeviceSlot64 (
2302 IN USB_XHCI_INSTANCE *Xhc,
2303 IN USB_DEV_ROUTE ParentRouteChart,
2304 IN UINT16 ParentPort,
2305 IN USB_DEV_ROUTE RouteChart,
2306 IN UINT8 DeviceSpeed
2307 )
2308 {
2309 EFI_STATUS Status;
2310 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2311 INPUT_CONTEXT_64 *InputContext;
2312 DEVICE_CONTEXT_64 *OutputContext;
2313 TRANSFER_RING *EndpointTransferRing;
2314 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
2315 UINT8 DeviceAddress;
2316 CMD_TRB_ENABLE_SLOT CmdTrb;
2317 UINT8 SlotId;
2318 UINT8 ParentSlotId;
2319 DEVICE_CONTEXT_64 *ParentDeviceContext;
2320 EFI_PHYSICAL_ADDRESS PhyAddr;
2321
2322 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2323 CmdTrb.CycleBit = 1;
2324 CmdTrb.Type = TRB_TYPE_EN_SLOT;
2325
2326 Status = XhcCmdTransfer (
2327 Xhc,
2328 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2329 XHC_GENERIC_TIMEOUT,
2330 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2331 );
2332 if (EFI_ERROR (Status)) {
2333 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
2334 return Status;
2335 }
2336 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2337 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2338 SlotId = (UINT8)EvtTrb->SlotId;
2339 ASSERT (SlotId != 0);
2340
2341 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2342 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
2343 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
2344 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
2345 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2346
2347 //
2348 // 4.3.3 Device Slot Initialization
2349 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2350 //
2351 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
2352 ASSERT (InputContext != NULL);
2353 ASSERT (((UINTN) InputContext & 0x3F) == 0);
2354 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2355
2356 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2357
2358 //
2359 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2360 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2361 // Context are affected by the command.
2362 //
2363 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2364
2365 //
2366 // 3) Initialize the Input Slot Context data structure
2367 //
2368 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
2369 InputContext->Slot.Speed = DeviceSpeed + 1;
2370 InputContext->Slot.ContextEntries = 1;
2371 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2372
2373 if (RouteChart.Route.RouteString) {
2374 //
2375 // The device is behind of hub device.
2376 //
2377 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2378 ASSERT (ParentSlotId != 0);
2379 //
2380 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2381 //
2382 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2383 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2384 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2385 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2386 //
2387 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2388 // environment from Full/Low speed signaling environment for a device
2389 //
2390 InputContext->Slot.TTPortNum = ParentPort;
2391 InputContext->Slot.TTHubSlotId = ParentSlotId;
2392 }
2393 } else {
2394 //
2395 // Inherit the TT parameters from parent device.
2396 //
2397 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
2398 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2399 //
2400 // If the device is a High speed device then down the speed to be the same as its parent Hub
2401 //
2402 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2403 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2404 }
2405 }
2406 }
2407
2408 //
2409 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2410 //
2411 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2412 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2413 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2414 //
2415 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2416 //
2417 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2418
2419 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2420 InputContext->EP[0].MaxPacketSize = 512;
2421 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2422 InputContext->EP[0].MaxPacketSize = 64;
2423 } else {
2424 InputContext->EP[0].MaxPacketSize = 8;
2425 }
2426 //
2427 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2428 // 1KB, and Bulk and Isoch endpoints 3KB.
2429 //
2430 InputContext->EP[0].AverageTRBLength = 8;
2431 InputContext->EP[0].MaxBurstSize = 0;
2432 InputContext->EP[0].Interval = 0;
2433 InputContext->EP[0].MaxPStreams = 0;
2434 InputContext->EP[0].Mult = 0;
2435 InputContext->EP[0].CErr = 3;
2436
2437 //
2438 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2439 //
2440 PhyAddr = UsbHcGetPciAddrForHostAddr (
2441 Xhc->MemPool,
2442 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2443 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2444 );
2445 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2446 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2447
2448 //
2449 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2450 //
2451 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
2452 ASSERT (OutputContext != NULL);
2453 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2454 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2455
2456 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2457 //
2458 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2459 // a pointer to the Output Device Context data structure (6.2.1).
2460 //
2461 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
2462 //
2463 // Fill DCBAA with PCI device address
2464 //
2465 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2466
2467 //
2468 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2469 // Context data structure described above.
2470 //
2471 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2472 // to device.
2473 //
2474 gBS->Stall (XHC_RESET_RECOVERY_DELAY);
2475 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2476 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2477 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
2478 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2479 CmdTrbAddr.CycleBit = 1;
2480 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2481 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2482 Status = XhcCmdTransfer (
2483 Xhc,
2484 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2485 XHC_GENERIC_TIMEOUT,
2486 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2487 );
2488 if (!EFI_ERROR (Status)) {
2489 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2490 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2491 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2492 }
2493 return Status;
2494 }
2495
2496
2497 /**
2498 Disable the specified device slot.
2499
2500 @param Xhc The XHCI Instance.
2501 @param SlotId The slot id to be disabled.
2502
2503 @retval EFI_SUCCESS Successfully disable the device slot.
2504
2505 **/
2506 EFI_STATUS
2507 EFIAPI
2508 XhcDisableSlotCmd (
2509 IN USB_XHCI_INSTANCE *Xhc,
2510 IN UINT8 SlotId
2511 )
2512 {
2513 EFI_STATUS Status;
2514 TRB_TEMPLATE *EvtTrb;
2515 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2516 UINT8 Index;
2517 VOID *RingSeg;
2518
2519 //
2520 // Disable the device slots occupied by these devices on its downstream ports.
2521 // Entry 0 is reserved.
2522 //
2523 for (Index = 0; Index < 255; Index++) {
2524 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2525 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2526 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2527 continue;
2528 }
2529
2530 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2531
2532 if (EFI_ERROR (Status)) {
2533 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2534 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2535 }
2536 }
2537
2538 //
2539 // Construct the disable slot command
2540 //
2541 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2542
2543 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2544 CmdTrbDisSlot.CycleBit = 1;
2545 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2546 CmdTrbDisSlot.SlotId = SlotId;
2547 Status = XhcCmdTransfer (
2548 Xhc,
2549 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2550 XHC_GENERIC_TIMEOUT,
2551 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2552 );
2553 if (EFI_ERROR (Status)) {
2554 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2555 return Status;
2556 }
2557 //
2558 // Free the slot's device context entry
2559 //
2560 Xhc->DCBAA[SlotId] = 0;
2561
2562 //
2563 // Free the slot related data structure
2564 //
2565 for (Index = 0; Index < 31; Index++) {
2566 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2567 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2568 if (RingSeg != NULL) {
2569 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2570 }
2571 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2572 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2573 }
2574 }
2575
2576 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2577 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2578 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2579 }
2580 }
2581
2582 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2583 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2584 }
2585
2586 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2587 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2588 }
2589
2590 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2591 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
2592 }
2593 //
2594 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2595 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2596 // remove urb from XHCI's asynchronous transfer list.
2597 //
2598 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2599 Xhc->UsbDevContext[SlotId].SlotId = 0;
2600
2601 return Status;
2602 }
2603
2604 /**
2605 Disable the specified device slot.
2606
2607 @param Xhc The XHCI Instance.
2608 @param SlotId The slot id to be disabled.
2609
2610 @retval EFI_SUCCESS Successfully disable the device slot.
2611
2612 **/
2613 EFI_STATUS
2614 EFIAPI
2615 XhcDisableSlotCmd64 (
2616 IN USB_XHCI_INSTANCE *Xhc,
2617 IN UINT8 SlotId
2618 )
2619 {
2620 EFI_STATUS Status;
2621 TRB_TEMPLATE *EvtTrb;
2622 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2623 UINT8 Index;
2624 VOID *RingSeg;
2625
2626 //
2627 // Disable the device slots occupied by these devices on its downstream ports.
2628 // Entry 0 is reserved.
2629 //
2630 for (Index = 0; Index < 255; Index++) {
2631 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2632 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2633 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2634 continue;
2635 }
2636
2637 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2638
2639 if (EFI_ERROR (Status)) {
2640 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2641 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2642 }
2643 }
2644
2645 //
2646 // Construct the disable slot command
2647 //
2648 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2649
2650 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2651 CmdTrbDisSlot.CycleBit = 1;
2652 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2653 CmdTrbDisSlot.SlotId = SlotId;
2654 Status = XhcCmdTransfer (
2655 Xhc,
2656 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2657 XHC_GENERIC_TIMEOUT,
2658 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2659 );
2660 if (EFI_ERROR (Status)) {
2661 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2662 return Status;
2663 }
2664 //
2665 // Free the slot's device context entry
2666 //
2667 Xhc->DCBAA[SlotId] = 0;
2668
2669 //
2670 // Free the slot related data structure
2671 //
2672 for (Index = 0; Index < 31; Index++) {
2673 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2674 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2675 if (RingSeg != NULL) {
2676 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2677 }
2678 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2679 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2680 }
2681 }
2682
2683 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2684 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2685 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2686 }
2687 }
2688
2689 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
2690 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
2691 }
2692
2693 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2694 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2695 }
2696
2697 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2698 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
2699 }
2700 //
2701 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2702 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2703 // remove urb from XHCI's asynchronous transfer list.
2704 //
2705 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2706 Xhc->UsbDevContext[SlotId].SlotId = 0;
2707
2708 return Status;
2709 }
2710
2711 /**
2712 Initialize endpoint context in input context.
2713
2714 @param Xhc The XHCI Instance.
2715 @param SlotId The slot id to be configured.
2716 @param DeviceSpeed The device's speed.
2717 @param InputContext The pointer to the input context.
2718 @param IfDesc The pointer to the usb device interface descriptor.
2719
2720 @return The maximum device context index of endpoint.
2721
2722 **/
2723 UINT8
2724 EFIAPI
2725 XhcInitializeEndpointContext (
2726 IN USB_XHCI_INSTANCE *Xhc,
2727 IN UINT8 SlotId,
2728 IN UINT8 DeviceSpeed,
2729 IN INPUT_CONTEXT *InputContext,
2730 IN USB_INTERFACE_DESCRIPTOR *IfDesc
2731 )
2732 {
2733 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2734 UINTN NumEp;
2735 UINTN EpIndex;
2736 UINT8 EpAddr;
2737 UINT8 Direction;
2738 UINT8 Dci;
2739 UINT8 MaxDci;
2740 EFI_PHYSICAL_ADDRESS PhyAddr;
2741 UINT8 Interval;
2742 TRANSFER_RING *EndpointTransferRing;
2743
2744 MaxDci = 0;
2745
2746 NumEp = IfDesc->NumEndpoints;
2747
2748 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2749 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2750 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2751 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2752 }
2753
2754 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2755 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2756 continue;
2757 }
2758
2759 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2760 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2761
2762 Dci = XhcEndpointToDci (EpAddr, Direction);
2763 ASSERT (Dci < 32);
2764 if (Dci > MaxDci) {
2765 MaxDci = Dci;
2766 }
2767
2768 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2769 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2770
2771 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2772 //
2773 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2774 //
2775 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2776 } else {
2777 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2778 }
2779
2780 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2781 case USB_ENDPOINT_BULK:
2782 if (Direction == EfiUsbDataIn) {
2783 InputContext->EP[Dci-1].CErr = 3;
2784 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2785 } else {
2786 InputContext->EP[Dci-1].CErr = 3;
2787 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2788 }
2789
2790 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2791 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2792 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2793 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2794 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2795 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2796 EpDesc->EndpointAddress,
2797 EndpointTransferRing->RingSeg0,
2798 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2799 ));
2800 }
2801
2802 break;
2803 case USB_ENDPOINT_ISO:
2804 if (Direction == EfiUsbDataIn) {
2805 InputContext->EP[Dci-1].CErr = 0;
2806 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2807 } else {
2808 InputContext->EP[Dci-1].CErr = 0;
2809 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2810 }
2811 //
2812 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2813 // Refer to XHCI 1.1 spec section 6.2.3.6.
2814 //
2815 if (DeviceSpeed == EFI_USB_SPEED_FULL) {
2816 Interval = EpDesc->Interval;
2817 ASSERT (Interval >= 1 && Interval <= 16);
2818 InputContext->EP[Dci-1].Interval = Interval + 2;
2819 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2820 Interval = EpDesc->Interval;
2821 ASSERT (Interval >= 1 && Interval <= 16);
2822 InputContext->EP[Dci-1].Interval = Interval - 1;
2823 }
2824
2825 //
2826 // Do not support isochronous transfer now.
2827 //
2828 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2829 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2830 continue;
2831 case USB_ENDPOINT_INTERRUPT:
2832 if (Direction == EfiUsbDataIn) {
2833 InputContext->EP[Dci-1].CErr = 3;
2834 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2835 } else {
2836 InputContext->EP[Dci-1].CErr = 3;
2837 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2838 }
2839 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2840 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2841 //
2842 // Get the bInterval from descriptor and init the the interval field of endpoint context
2843 //
2844 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2845 Interval = EpDesc->Interval;
2846 //
2847 // Calculate through the bInterval field of Endpoint descriptor.
2848 //
2849 ASSERT (Interval != 0);
2850 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
2851 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2852 Interval = EpDesc->Interval;
2853 ASSERT (Interval >= 1 && Interval <= 16);
2854 //
2855 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2856 //
2857 InputContext->EP[Dci-1].Interval = Interval - 1;
2858 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2859 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2860 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2861 InputContext->EP[Dci-1].CErr = 3;
2862 }
2863
2864 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2865 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2866 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2867 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2868 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2869 EpDesc->EndpointAddress,
2870 EndpointTransferRing->RingSeg0,
2871 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2872 ));
2873 }
2874 break;
2875
2876 case USB_ENDPOINT_CONTROL:
2877 //
2878 // Do not support control transfer now.
2879 //
2880 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2881 default:
2882 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2883 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2884 continue;
2885 }
2886
2887 PhyAddr = UsbHcGetPciAddrForHostAddr (
2888 Xhc->MemPool,
2889 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2890 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2891 );
2892 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2893 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2894 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2895 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2896
2897 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2898 }
2899
2900 return MaxDci;
2901 }
2902
2903 /**
2904 Initialize endpoint context in input context.
2905
2906 @param Xhc The XHCI Instance.
2907 @param SlotId The slot id to be configured.
2908 @param DeviceSpeed The device's speed.
2909 @param InputContext The pointer to the input context.
2910 @param IfDesc The pointer to the usb device interface descriptor.
2911
2912 @return The maximum device context index of endpoint.
2913
2914 **/
2915 UINT8
2916 EFIAPI
2917 XhcInitializeEndpointContext64 (
2918 IN USB_XHCI_INSTANCE *Xhc,
2919 IN UINT8 SlotId,
2920 IN UINT8 DeviceSpeed,
2921 IN INPUT_CONTEXT_64 *InputContext,
2922 IN USB_INTERFACE_DESCRIPTOR *IfDesc
2923 )
2924 {
2925 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2926 UINTN NumEp;
2927 UINTN EpIndex;
2928 UINT8 EpAddr;
2929 UINT8 Direction;
2930 UINT8 Dci;
2931 UINT8 MaxDci;
2932 EFI_PHYSICAL_ADDRESS PhyAddr;
2933 UINT8 Interval;
2934 TRANSFER_RING *EndpointTransferRing;
2935
2936 MaxDci = 0;
2937
2938 NumEp = IfDesc->NumEndpoints;
2939
2940 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2941 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2942 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2943 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2944 }
2945
2946 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
2947 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2948 continue;
2949 }
2950
2951 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2952 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2953
2954 Dci = XhcEndpointToDci (EpAddr, Direction);
2955 ASSERT (Dci < 32);
2956 if (Dci > MaxDci) {
2957 MaxDci = Dci;
2958 }
2959
2960 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2961 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2962
2963 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2964 //
2965 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2966 //
2967 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2968 } else {
2969 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2970 }
2971
2972 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2973 case USB_ENDPOINT_BULK:
2974 if (Direction == EfiUsbDataIn) {
2975 InputContext->EP[Dci-1].CErr = 3;
2976 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2977 } else {
2978 InputContext->EP[Dci-1].CErr = 3;
2979 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2980 }
2981
2982 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2983 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2984 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2985 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2986 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2987 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
2988 EpDesc->EndpointAddress,
2989 EndpointTransferRing->RingSeg0,
2990 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
2991 ));
2992 }
2993
2994 break;
2995 case USB_ENDPOINT_ISO:
2996 if (Direction == EfiUsbDataIn) {
2997 InputContext->EP[Dci-1].CErr = 0;
2998 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2999 } else {
3000 InputContext->EP[Dci-1].CErr = 0;
3001 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
3002 }
3003 //
3004 // Get the bInterval from descriptor and init the the interval field of endpoint context.
3005 // Refer to XHCI 1.1 spec section 6.2.3.6.
3006 //
3007 if (DeviceSpeed == EFI_USB_SPEED_FULL) {
3008 Interval = EpDesc->Interval;
3009 ASSERT (Interval >= 1 && Interval <= 16);
3010 InputContext->EP[Dci-1].Interval = Interval + 2;
3011 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
3012 Interval = EpDesc->Interval;
3013 ASSERT (Interval >= 1 && Interval <= 16);
3014 InputContext->EP[Dci-1].Interval = Interval - 1;
3015 }
3016
3017 //
3018 // Do not support isochronous transfer now.
3019 //
3020 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
3021 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3022 continue;
3023 case USB_ENDPOINT_INTERRUPT:
3024 if (Direction == EfiUsbDataIn) {
3025 InputContext->EP[Dci-1].CErr = 3;
3026 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
3027 } else {
3028 InputContext->EP[Dci-1].CErr = 3;
3029 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
3030 }
3031 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
3032 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
3033 //
3034 // Get the bInterval from descriptor and init the the interval field of endpoint context
3035 //
3036 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
3037 Interval = EpDesc->Interval;
3038 //
3039 // Calculate through the bInterval field of Endpoint descriptor.
3040 //
3041 ASSERT (Interval != 0);
3042 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
3043 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
3044 Interval = EpDesc->Interval;
3045 ASSERT (Interval >= 1 && Interval <= 16);
3046 //
3047 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
3048 //
3049 InputContext->EP[Dci-1].Interval = Interval - 1;
3050 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
3051 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
3052 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
3053 InputContext->EP[Dci-1].CErr = 3;
3054 }
3055
3056 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
3057 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
3058 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
3059 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
3060 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
3061 EpDesc->EndpointAddress,
3062 EndpointTransferRing->RingSeg0,
3063 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
3064 ));
3065 }
3066 break;
3067
3068 case USB_ENDPOINT_CONTROL:
3069 //
3070 // Do not support control transfer now.
3071 //
3072 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
3073 default:
3074 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
3075 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3076 continue;
3077 }
3078
3079 PhyAddr = UsbHcGetPciAddrForHostAddr (
3080 Xhc->MemPool,
3081 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
3082 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
3083 );
3084 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
3085 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
3086 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
3087 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
3088
3089 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3090 }
3091
3092 return MaxDci;
3093 }
3094
3095 /**
3096 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3097
3098 @param Xhc The XHCI Instance.
3099 @param SlotId The slot id to be configured.
3100 @param DeviceSpeed The device's speed.
3101 @param ConfigDesc The pointer to the usb device configuration descriptor.
3102
3103 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3104
3105 **/
3106 EFI_STATUS
3107 EFIAPI
3108 XhcSetConfigCmd (
3109 IN USB_XHCI_INSTANCE *Xhc,
3110 IN UINT8 SlotId,
3111 IN UINT8 DeviceSpeed,
3112 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
3113 )
3114 {
3115 EFI_STATUS Status;
3116 USB_INTERFACE_DESCRIPTOR *IfDesc;
3117 UINT8 Index;
3118 UINT8 Dci;
3119 UINT8 MaxDci;
3120 EFI_PHYSICAL_ADDRESS PhyAddr;
3121
3122 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3123 INPUT_CONTEXT *InputContext;
3124 DEVICE_CONTEXT *OutputContext;
3125 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3126 //
3127 // 4.6.6 Configure Endpoint
3128 //
3129 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3130 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3131 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3132 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3133
3134 ASSERT (ConfigDesc != NULL);
3135
3136 MaxDci = 0;
3137
3138 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3139 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3140 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3141 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3142 }
3143
3144 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3145 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3146 continue;
3147 }
3148
3149 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3150 if (Dci > MaxDci) {
3151 MaxDci = Dci;
3152 }
3153
3154 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3155 }
3156
3157 InputContext->InputControlContext.Dword2 |= BIT0;
3158 InputContext->Slot.ContextEntries = MaxDci;
3159 //
3160 // configure endpoint
3161 //
3162 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3163 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3164 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3165 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3166 CmdTrbCfgEP.CycleBit = 1;
3167 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3168 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3169 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3170 Status = XhcCmdTransfer (
3171 Xhc,
3172 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3173 XHC_GENERIC_TIMEOUT,
3174 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3175 );
3176 if (EFI_ERROR (Status)) {
3177 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
3178 } else {
3179 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3180 }
3181
3182 return Status;
3183 }
3184
3185 /**
3186 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3187
3188 @param Xhc The XHCI Instance.
3189 @param SlotId The slot id to be configured.
3190 @param DeviceSpeed The device's speed.
3191 @param ConfigDesc The pointer to the usb device configuration descriptor.
3192
3193 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3194
3195 **/
3196 EFI_STATUS
3197 EFIAPI
3198 XhcSetConfigCmd64 (
3199 IN USB_XHCI_INSTANCE *Xhc,
3200 IN UINT8 SlotId,
3201 IN UINT8 DeviceSpeed,
3202 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
3203 )
3204 {
3205 EFI_STATUS Status;
3206 USB_INTERFACE_DESCRIPTOR *IfDesc;
3207 UINT8 Index;
3208 UINT8 Dci;
3209 UINT8 MaxDci;
3210 EFI_PHYSICAL_ADDRESS PhyAddr;
3211
3212 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3213 INPUT_CONTEXT_64 *InputContext;
3214 DEVICE_CONTEXT_64 *OutputContext;
3215 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3216 //
3217 // 4.6.6 Configure Endpoint
3218 //
3219 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3220 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3221 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3222 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3223
3224 ASSERT (ConfigDesc != NULL);
3225
3226 MaxDci = 0;
3227
3228 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3229 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
3230 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
3231 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3232 }
3233
3234 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
3235 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3236 continue;
3237 }
3238
3239 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
3240 if (Dci > MaxDci) {
3241 MaxDci = Dci;
3242 }
3243
3244 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3245 }
3246
3247 InputContext->InputControlContext.Dword2 |= BIT0;
3248 InputContext->Slot.ContextEntries = MaxDci;
3249 //
3250 // configure endpoint
3251 //
3252 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3253 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3254 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3255 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3256 CmdTrbCfgEP.CycleBit = 1;
3257 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3258 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3259 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
3260 Status = XhcCmdTransfer (
3261 Xhc,
3262 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3263 XHC_GENERIC_TIMEOUT,
3264 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3265 );
3266 if (EFI_ERROR (Status)) {
3267 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
3268 } else {
3269 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
3270 }
3271
3272 return Status;
3273 }
3274
3275 /**
3276 Stop endpoint through XHCI's Stop_Endpoint cmd.
3277
3278 @param Xhc The XHCI Instance.
3279 @param SlotId The slot id to be configured.
3280 @param Dci The device context index of endpoint.
3281 @param PendingUrb The pending URB to check completion status when stopping the end point.
3282
3283 @retval EFI_SUCCESS Stop endpoint successfully.
3284 @retval Others Failed to stop endpoint.
3285
3286 **/
3287 EFI_STATUS
3288 EFIAPI
3289 XhcStopEndpoint (
3290 IN USB_XHCI_INSTANCE *Xhc,
3291 IN UINT8 SlotId,
3292 IN UINT8 Dci,
3293 IN URB *PendingUrb OPTIONAL
3294 )
3295 {
3296 EFI_STATUS Status;
3297 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3298 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;
3299
3300 DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3301
3302 //
3303 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
3304 // the PendingUrb completion status, because it's possible that the PendingUrb is
3305 // finished just before stopping the end point, but after the looping check.
3306 //
3307 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
3308 // through function parameter, but That will cause every consumer of XhcCmdTransfer,
3309 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
3310 // But actually only XhcCheckUrbResult is aware of the PendingUrb.
3311 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
3312 //
3313 ASSERT (Xhc->PendingUrb == NULL);
3314 Xhc->PendingUrb = PendingUrb;
3315 //
3316 // Reset the URB result from Timeout to NoError.
3317 // The USB result will be:
3318 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
3319 // remain NoError when Success/ShortPacket Transfer Event is received.
3320 //
3321 if (PendingUrb != NULL) {
3322 PendingUrb->Result = EFI_USB_NOERROR;
3323 }
3324
3325 //
3326 // Send stop endpoint command to transit Endpoint from running to stop state
3327 //
3328 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
3329 CmdTrbStopED.CycleBit = 1;
3330 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;
3331 CmdTrbStopED.EDID = Dci;
3332 CmdTrbStopED.SlotId = SlotId;
3333 Status = XhcCmdTransfer (
3334 Xhc,
3335 (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
3336 XHC_GENERIC_TIMEOUT,
3337 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3338 );
3339 if (EFI_ERROR(Status)) {
3340 DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
3341 }
3342
3343 Xhc->PendingUrb = NULL;
3344
3345 return Status;
3346 }
3347
3348 /**
3349 Reset endpoint through XHCI's Reset_Endpoint cmd.
3350
3351 @param Xhc The XHCI Instance.
3352 @param SlotId The slot id to be configured.
3353 @param Dci The device context index of endpoint.
3354
3355 @retval EFI_SUCCESS Reset endpoint successfully.
3356 @retval Others Failed to reset endpoint.
3357
3358 **/
3359 EFI_STATUS
3360 EFIAPI
3361 XhcResetEndpoint (
3362 IN USB_XHCI_INSTANCE *Xhc,
3363 IN UINT8 SlotId,
3364 IN UINT8 Dci
3365 )
3366 {
3367 EFI_STATUS Status;
3368 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3369 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
3370
3371 DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
3372
3373 //
3374 // Send stop endpoint command to transit Endpoint from running to stop state
3375 //
3376 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
3377 CmdTrbResetED.CycleBit = 1;
3378 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
3379 CmdTrbResetED.EDID = Dci;
3380 CmdTrbResetED.SlotId = SlotId;
3381 Status = XhcCmdTransfer (
3382 Xhc,
3383 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
3384 XHC_GENERIC_TIMEOUT,
3385 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3386 );
3387 if (EFI_ERROR(Status)) {
3388 DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
3389 }
3390
3391 return Status;
3392 }
3393
3394 /**
3395 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3396
3397 @param Xhc The XHCI Instance.
3398 @param SlotId The slot id to be configured.
3399 @param Dci The device context index of endpoint.
3400 @param Urb The dequeue pointer of the transfer ring specified
3401 by the urb to be updated.
3402
3403 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3404 @retval Others Failed to set transfer ring dequeue pointer.
3405
3406 **/
3407 EFI_STATUS
3408 EFIAPI
3409 XhcSetTrDequeuePointer (
3410 IN USB_XHCI_INSTANCE *Xhc,
3411 IN UINT8 SlotId,
3412 IN UINT8 Dci,
3413 IN URB *Urb
3414 )
3415 {
3416 EFI_STATUS Status;
3417 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3418 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
3419 EFI_PHYSICAL_ADDRESS PhyAddr;
3420
3421 DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
3422
3423 //
3424 // Send stop endpoint command to transit Endpoint from running to stop state
3425 //
3426 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
3427 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
3428 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
3429 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3430 CmdSetTRDeq.CycleBit = 1;
3431 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
3432 CmdSetTRDeq.Endpoint = Dci;
3433 CmdSetTRDeq.SlotId = SlotId;
3434 Status = XhcCmdTransfer (
3435 Xhc,
3436 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
3437 XHC_GENERIC_TIMEOUT,
3438 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3439 );
3440 if (EFI_ERROR(Status)) {
3441 DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
3442 }
3443
3444 return Status;
3445 }
3446
3447 /**
3448 Set interface through XHCI's Configure_Endpoint cmd.
3449
3450 @param Xhc The XHCI Instance.
3451 @param SlotId The slot id to be configured.
3452 @param DeviceSpeed The device's speed.
3453 @param ConfigDesc The pointer to the usb device configuration descriptor.
3454 @param Request USB device request to send.
3455
3456 @retval EFI_SUCCESS Successfully set interface.
3457
3458 **/
3459 EFI_STATUS
3460 EFIAPI
3461 XhcSetInterface (
3462 IN USB_XHCI_INSTANCE *Xhc,
3463 IN UINT8 SlotId,
3464 IN UINT8 DeviceSpeed,
3465 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
3466 IN EFI_USB_DEVICE_REQUEST *Request
3467 )
3468 {
3469 EFI_STATUS Status;
3470 USB_INTERFACE_DESCRIPTOR *IfDescActive;
3471 USB_INTERFACE_DESCRIPTOR *IfDescSet;
3472 USB_INTERFACE_DESCRIPTOR *IfDesc;
3473 USB_ENDPOINT_DESCRIPTOR *EpDesc;
3474 UINTN NumEp;
3475 UINTN EpIndex;
3476 UINT8 EpAddr;
3477 UINT8 Direction;
3478 UINT8 Dci;
3479 UINT8 MaxDci;
3480 EFI_PHYSICAL_ADDRESS PhyAddr;
3481 VOID *RingSeg;
3482
3483 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3484 INPUT_CONTEXT *InputContext;
3485 DEVICE_CONTEXT *OutputContext;
3486 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3487
3488 Status = EFI_SUCCESS;
3489
3490 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3491 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3492 //
3493 // XHCI 4.6.6 Configure Endpoint
3494 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3495 // Context and Add Context flags as follows:
3496 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3497 // Context and Add Context flags to '0'.
3498 //
3499 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3500 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3501 //
3502 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3503 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
3504
3505 ASSERT (ConfigDesc != NULL);
3506
3507 MaxDci = 0;
3508
3509 IfDescActive = NULL;
3510 IfDescSet = NULL;
3511
3512 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3513 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3514 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3515 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3516 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3517 //
3518 // Find out the active interface descriptor.
3519 //
3520 IfDescActive = IfDesc;
3521 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3522 //
3523 // Find out the interface descriptor to set.
3524 //
3525 IfDescSet = IfDesc;
3526 }
3527 }
3528 }
3529 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3530 }
3531
3532 //
3533 // XHCI 4.6.6 Configure Endpoint
3534 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3535 // Context and Add Context flags as follows:
3536 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3537 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3538 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3539 // the Drop Context flag to '1' and Add Context flag to '0'.
3540 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3541 // and Add Context flags shall be set to '1'.
3542 //
3543 // Below codes are to cover 2), 3) and 4).
3544 //
3545
3546 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3547 NumEp = IfDescActive->NumEndpoints;
3548 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3549 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3550 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3551 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3552 }
3553
3554 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3555 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3556 continue;
3557 }
3558
3559 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3560 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3561
3562 Dci = XhcEndpointToDci (EpAddr, Direction);
3563 ASSERT (Dci < 32);
3564 if (Dci > MaxDci) {
3565 MaxDci = Dci;
3566 }
3567 //
3568 // XHCI 4.3.6 - Setting Alternate Interfaces
3569 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3570 //
3571 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
3572 if (EFI_ERROR (Status)) {
3573 return Status;
3574 }
3575 //
3576 // XHCI 4.3.6 - Setting Alternate Interfaces
3577 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3578 //
3579 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3580 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3581 if (RingSeg != NULL) {
3582 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3583 }
3584 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3585 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3586 }
3587
3588 //
3589 // Set the Drop Context flag to '1'.
3590 //
3591 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3592
3593 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3594 }
3595
3596 //
3597 // XHCI 4.3.6 - Setting Alternate Interfaces
3598 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3599 // Interface setting, to '0'.
3600 //
3601 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3602 //
3603
3604 //
3605 // XHCI 4.3.6 - Setting Alternate Interfaces
3606 // 4) For each endpoint enabled by the Configure Endpoint Command:
3607 // a. Allocate a Transfer Ring.
3608 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3609 // c. Initialize the Endpoint Context data structure.
3610 //
3611 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3612 if (Dci > MaxDci) {
3613 MaxDci = Dci;
3614 }
3615
3616 InputContext->InputControlContext.Dword2 |= BIT0;
3617 InputContext->Slot.ContextEntries = MaxDci;
3618 //
3619 // XHCI 4.3.6 - Setting Alternate Interfaces
3620 // 5) Issue and successfully complete a Configure Endpoint Command.
3621 //
3622 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3623 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3624 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3625 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3626 CmdTrbCfgEP.CycleBit = 1;
3627 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3628 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3629 DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));
3630 Status = XhcCmdTransfer (
3631 Xhc,
3632 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3633 XHC_GENERIC_TIMEOUT,
3634 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3635 );
3636 if (EFI_ERROR (Status)) {
3637 DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));
3638 } else {
3639 //
3640 // Update the active AlternateSetting.
3641 //
3642 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3643 }
3644 }
3645
3646 return Status;
3647 }
3648
3649 /**
3650 Set interface through XHCI's Configure_Endpoint cmd.
3651
3652 @param Xhc The XHCI Instance.
3653 @param SlotId The slot id to be configured.
3654 @param DeviceSpeed The device's speed.
3655 @param ConfigDesc The pointer to the usb device configuration descriptor.
3656 @param Request USB device request to send.
3657
3658 @retval EFI_SUCCESS Successfully set interface.
3659
3660 **/
3661 EFI_STATUS
3662 EFIAPI
3663 XhcSetInterface64 (
3664 IN USB_XHCI_INSTANCE *Xhc,
3665 IN UINT8 SlotId,
3666 IN UINT8 DeviceSpeed,
3667 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
3668 IN EFI_USB_DEVICE_REQUEST *Request
3669 )
3670 {
3671 EFI_STATUS Status;
3672 USB_INTERFACE_DESCRIPTOR *IfDescActive;
3673 USB_INTERFACE_DESCRIPTOR *IfDescSet;
3674 USB_INTERFACE_DESCRIPTOR *IfDesc;
3675 USB_ENDPOINT_DESCRIPTOR *EpDesc;
3676 UINTN NumEp;
3677 UINTN EpIndex;
3678 UINT8 EpAddr;
3679 UINT8 Direction;
3680 UINT8 Dci;
3681 UINT8 MaxDci;
3682 EFI_PHYSICAL_ADDRESS PhyAddr;
3683 VOID *RingSeg;
3684
3685 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3686 INPUT_CONTEXT_64 *InputContext;
3687 DEVICE_CONTEXT_64 *OutputContext;
3688 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3689
3690 Status = EFI_SUCCESS;
3691
3692 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3693 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3694 //
3695 // XHCI 4.6.6 Configure Endpoint
3696 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3697 // Context and Add Context flags as follows:
3698 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3699 // Context and Add Context flags to '0'.
3700 //
3701 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3702 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3703 //
3704 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3705 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
3706
3707 ASSERT (ConfigDesc != NULL);
3708
3709 MaxDci = 0;
3710
3711 IfDescActive = NULL;
3712 IfDescSet = NULL;
3713
3714 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
3715 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
3716 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
3717 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
3718 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
3719 //
3720 // Find out the active interface descriptor.
3721 //
3722 IfDescActive = IfDesc;
3723 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
3724 //
3725 // Find out the interface descriptor to set.
3726 //
3727 IfDescSet = IfDesc;
3728 }
3729 }
3730 }
3731 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
3732 }
3733
3734 //
3735 // XHCI 4.6.6 Configure Endpoint
3736 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3737 // Context and Add Context flags as follows:
3738 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3739 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3740 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3741 // the Drop Context flag to '1' and Add Context flag to '0'.
3742 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3743 // and Add Context flags shall be set to '1'.
3744 //
3745 // Below codes are to cover 2), 3) and 4).
3746 //
3747
3748 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
3749 NumEp = IfDescActive->NumEndpoints;
3750 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
3751 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
3752 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
3753 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3754 }
3755
3756 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
3757 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3758 continue;
3759 }
3760
3761 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
3762 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
3763
3764 Dci = XhcEndpointToDci (EpAddr, Direction);
3765 ASSERT (Dci < 32);
3766 if (Dci > MaxDci) {
3767 MaxDci = Dci;
3768 }
3769 //
3770 // XHCI 4.3.6 - Setting Alternate Interfaces
3771 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3772 //
3773 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
3774 if (EFI_ERROR (Status)) {
3775 return Status;
3776 }
3777 //
3778 // XHCI 4.3.6 - Setting Alternate Interfaces
3779 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3780 //
3781 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
3782 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
3783 if (RingSeg != NULL) {
3784 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
3785 }
3786 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
3787 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
3788 }
3789
3790 //
3791 // Set the Drop Context flag to '1'.
3792 //
3793 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
3794
3795 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
3796 }
3797
3798 //
3799 // XHCI 4.3.6 - Setting Alternate Interfaces
3800 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3801 // Interface setting, to '0'.
3802 //
3803 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3804 //
3805
3806 //
3807 // XHCI 4.3.6 - Setting Alternate Interfaces
3808 // 4) For each endpoint enabled by the Configure Endpoint Command:
3809 // a. Allocate a Transfer Ring.
3810 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3811 // c. Initialize the Endpoint Context data structure.
3812 //
3813 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
3814 if (Dci > MaxDci) {
3815 MaxDci = Dci;
3816 }
3817
3818 InputContext->InputControlContext.Dword2 |= BIT0;
3819 InputContext->Slot.ContextEntries = MaxDci;
3820 //
3821 // XHCI 4.3.6 - Setting Alternate Interfaces
3822 // 5) Issue and successfully complete a Configure Endpoint Command.
3823 //
3824 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3825 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3826 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3827 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3828 CmdTrbCfgEP.CycleBit = 1;
3829 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3830 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3831 DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));
3832 Status = XhcCmdTransfer (
3833 Xhc,
3834 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3835 XHC_GENERIC_TIMEOUT,
3836 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3837 );
3838 if (EFI_ERROR (Status)) {
3839 DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));
3840 } else {
3841 //
3842 // Update the active AlternateSetting.
3843 //
3844 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
3845 }
3846 }
3847
3848 return Status;
3849 }
3850
3851 /**
3852 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3853
3854 @param Xhc The XHCI Instance.
3855 @param SlotId The slot id to be evaluated.
3856 @param MaxPacketSize The max packet size supported by the device control transfer.
3857
3858 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3859
3860 **/
3861 EFI_STATUS
3862 EFIAPI
3863 XhcEvaluateContext (
3864 IN USB_XHCI_INSTANCE *Xhc,
3865 IN UINT8 SlotId,
3866 IN UINT32 MaxPacketSize
3867 )
3868 {
3869 EFI_STATUS Status;
3870 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
3871 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3872 INPUT_CONTEXT *InputContext;
3873 EFI_PHYSICAL_ADDRESS PhyAddr;
3874
3875 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3876
3877 //
3878 // 4.6.7 Evaluate Context
3879 //
3880 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3881 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3882
3883 InputContext->InputControlContext.Dword2 |= BIT1;
3884 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
3885
3886 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3887 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3888 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
3889 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3890 CmdTrbEvalu.CycleBit = 1;
3891 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
3892 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3893 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3894 Status = XhcCmdTransfer (
3895 Xhc,
3896 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3897 XHC_GENERIC_TIMEOUT,
3898 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3899 );
3900 if (EFI_ERROR (Status)) {
3901 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
3902 }
3903 return Status;
3904 }
3905
3906 /**
3907 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3908
3909 @param Xhc The XHCI Instance.
3910 @param SlotId The slot id to be evaluated.
3911 @param MaxPacketSize The max packet size supported by the device control transfer.
3912
3913 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3914
3915 **/
3916 EFI_STATUS
3917 EFIAPI
3918 XhcEvaluateContext64 (
3919 IN USB_XHCI_INSTANCE *Xhc,
3920 IN UINT8 SlotId,
3921 IN UINT32 MaxPacketSize
3922 )
3923 {
3924 EFI_STATUS Status;
3925 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
3926 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3927 INPUT_CONTEXT_64 *InputContext;
3928 EFI_PHYSICAL_ADDRESS PhyAddr;
3929
3930 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3931
3932 //
3933 // 4.6.7 Evaluate Context
3934 //
3935 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3936 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3937
3938 InputContext->InputControlContext.Dword2 |= BIT1;
3939 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
3940
3941 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
3942 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3943 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
3944 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3945 CmdTrbEvalu.CycleBit = 1;
3946 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
3947 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3948 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3949 Status = XhcCmdTransfer (
3950 Xhc,
3951 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3952 XHC_GENERIC_TIMEOUT,
3953 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3954 );
3955 if (EFI_ERROR (Status)) {
3956 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
3957 }
3958 return Status;
3959 }
3960
3961
3962 /**
3963 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3964
3965 @param Xhc The XHCI Instance.
3966 @param SlotId The slot id to be configured.
3967 @param PortNum The total number of downstream port supported by the hub.
3968 @param TTT The TT think time of the hub device.
3969 @param MTT The multi-TT of the hub device.
3970
3971 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3972
3973 **/
3974 EFI_STATUS
3975 XhcConfigHubContext (
3976 IN USB_XHCI_INSTANCE *Xhc,
3977 IN UINT8 SlotId,
3978 IN UINT8 PortNum,
3979 IN UINT8 TTT,
3980 IN UINT8 MTT
3981 )
3982 {
3983 EFI_STATUS Status;
3984 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3985 INPUT_CONTEXT *InputContext;
3986 DEVICE_CONTEXT *OutputContext;
3987 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3988 EFI_PHYSICAL_ADDRESS PhyAddr;
3989
3990 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3991 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3992 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3993
3994 //
3995 // 4.6.7 Evaluate Context
3996 //
3997 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3998
3999 InputContext->InputControlContext.Dword2 |= BIT0;
4000
4001 //
4002 // Copy the slot context from OutputContext to Input context
4003 //
4004 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
4005 InputContext->Slot.Hub = 1;
4006 InputContext->Slot.PortNum = PortNum;
4007 InputContext->Slot.TTT = TTT;
4008 InputContext->Slot.MTT = MTT;
4009
4010 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
4011 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
4012 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
4013 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
4014 CmdTrbCfgEP.CycleBit = 1;
4015 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
4016 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
4017 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
4018 Status = XhcCmdTransfer (
4019 Xhc,
4020 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
4021 XHC_GENERIC_TIMEOUT,
4022 (TRB_TEMPLATE **) (UINTN) &EvtTrb
4023 );
4024 if (EFI_ERROR (Status)) {
4025 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
4026 }
4027 return Status;
4028 }
4029
4030 /**
4031 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
4032
4033 @param Xhc The XHCI Instance.
4034 @param SlotId The slot id to be configured.
4035 @param PortNum The total number of downstream port supported by the hub.
4036 @param TTT The TT think time of the hub device.
4037 @param MTT The multi-TT of the hub device.
4038
4039 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
4040
4041 **/
4042 EFI_STATUS
4043 XhcConfigHubContext64 (
4044 IN USB_XHCI_INSTANCE *Xhc,
4045 IN UINT8 SlotId,
4046 IN UINT8 PortNum,
4047 IN UINT8 TTT,
4048 IN UINT8 MTT
4049 )
4050 {
4051 EFI_STATUS Status;
4052 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
4053 INPUT_CONTEXT_64 *InputContext;
4054 DEVICE_CONTEXT_64 *OutputContext;
4055 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
4056 EFI_PHYSICAL_ADDRESS PhyAddr;
4057
4058 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
4059 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
4060 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
4061
4062 //
4063 // 4.6.7 Evaluate Context
4064 //
4065 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
4066
4067 InputContext->InputControlContext.Dword2 |= BIT0;
4068
4069 //
4070 // Copy the slot context from OutputContext to Input context
4071 //
4072 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
4073 InputContext->Slot.Hub = 1;
4074 InputContext->Slot.PortNum = PortNum;
4075 InputContext->Slot.TTT = TTT;
4076 InputContext->Slot.MTT = MTT;
4077
4078 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
4079 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
4080 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
4081 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
4082 CmdTrbCfgEP.CycleBit = 1;
4083 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
4084 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
4085 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
4086 Status = XhcCmdTransfer (
4087 Xhc,
4088 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
4089 XHC_GENERIC_TIMEOUT,
4090 (TRB_TEMPLATE **) (UINTN) &EvtTrb
4091 );
4092 if (EFI_ERROR (Status)) {
4093 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
4094 }
4095 return Status;
4096 }
4097
4098