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