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