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