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