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