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