TianoCore EDK2 master
Loading...
Searching...
No Matches
XhciSched.c
Go to the documentation of this file.
1
12#include "XhcPeim.h"
13
23URB *
25 IN PEI_XHC_DEV *Xhc,
26 IN TRB_TEMPLATE *CmdTrb
27 )
28{
29 URB *Urb;
30
31 Urb = AllocateZeroPool (sizeof (URB));
32 if (Urb == NULL) {
33 return NULL;
34 }
35
36 Urb->Signature = XHC_URB_SIG;
37
38 Urb->Ring = &Xhc->CmdRing;
39 XhcPeiSyncTrsRing (Xhc, Urb->Ring);
40 Urb->TrbNum = 1;
41 Urb->TrbStart = Urb->Ring->RingEnqueue;
42 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
43 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
44 Urb->TrbEnd = Urb->TrbStart;
45
46 return Urb;
47}
48
66 IN PEI_XHC_DEV *Xhc,
67 IN TRB_TEMPLATE *CmdTrb,
68 IN UINTN Timeout,
69 OUT TRB_TEMPLATE **EvtTrb
70 )
71{
72 EFI_STATUS Status;
73 URB *Urb;
74
75 //
76 // Validate the parameters
77 //
78 if ((Xhc == NULL) || (CmdTrb == NULL)) {
79 return EFI_INVALID_PARAMETER;
80 }
81
82 Status = EFI_DEVICE_ERROR;
83
84 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
85 DEBUG ((DEBUG_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
86 goto ON_EXIT;
87 }
88
89 //
90 // Create a new URB, then poll the execution status.
91 //
92 Urb = XhcPeiCreateCmdTrb (Xhc, CmdTrb);
93 if (Urb == NULL) {
94 DEBUG ((DEBUG_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));
95 Status = EFI_OUT_OF_RESOURCES;
96 goto ON_EXIT;
97 }
98
99 Status = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);
100 *EvtTrb = Urb->EvtTrb;
101
102 if (Urb->Result == EFI_USB_NOERROR) {
103 Status = EFI_SUCCESS;
104 }
105
106 XhcPeiFreeUrb (Xhc, Urb);
107
108ON_EXIT:
109 return Status;
110}
111
130URB *
132 IN PEI_XHC_DEV *Xhc,
133 IN UINT8 BusAddr,
134 IN UINT8 EpAddr,
135 IN UINT8 DevSpeed,
136 IN UINTN MaxPacket,
137 IN UINTN Type,
138 IN EFI_USB_DEVICE_REQUEST *Request,
139 IN VOID *Data,
140 IN UINTN DataLen,
142 IN VOID *Context
143 )
144{
145 USB_ENDPOINT *Ep;
146 EFI_STATUS Status;
147 URB *Urb;
148
149 Urb = AllocateZeroPool (sizeof (URB));
150 if (Urb == NULL) {
151 return NULL;
152 }
153
154 Urb->Signature = XHC_URB_SIG;
155
156 Ep = &Urb->Ep;
157 Ep->BusAddr = BusAddr;
158 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);
159 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
160 Ep->DevSpeed = DevSpeed;
161 Ep->MaxPacket = MaxPacket;
162 Ep->Type = Type;
163
164 Urb->Request = Request;
165 Urb->Data = Data;
166 Urb->DataLen = DataLen;
167 Urb->Callback = Callback;
168 Urb->Context = Context;
169
170 Status = XhcPeiCreateTransferTrb (Xhc, Urb);
171 if (EFI_ERROR (Status)) {
172 DEBUG ((DEBUG_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));
173 FreePool (Urb);
174 Urb = NULL;
175 }
176
177 return Urb;
178}
179
187VOID
189 IN PEI_XHC_DEV *Xhc,
190 IN URB *Urb
191 )
192{
193 if ((Xhc == NULL) || (Urb == NULL)) {
194 return;
195 }
196
197 IoMmuUnmap (Urb->DataMap);
198
199 FreePool (Urb);
200}
201
213 IN PEI_XHC_DEV *Xhc,
214 IN URB *Urb
215 )
216{
217 VOID *OutputContext;
218 TRANSFER_RING *EPRing;
219 UINT8 EPType;
220 UINT8 SlotId;
221 UINT8 Dci;
222 TRB *TrbStart;
223 UINTN TotalLen;
224 UINTN Len;
225 UINTN TrbNum;
227 EFI_PHYSICAL_ADDRESS PhyAddr;
228 VOID *Map;
229 EFI_STATUS Status;
230
231 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
232 if (SlotId == 0) {
233 return EFI_DEVICE_ERROR;
234 }
235
236 Urb->Finished = FALSE;
237 Urb->StartDone = FALSE;
238 Urb->EndDone = FALSE;
239 Urb->Completed = 0;
240 Urb->Result = EFI_USB_NOERROR;
241
242 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
243 EPRing = (TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
244 Urb->Ring = EPRing;
245 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
246 if (Xhc->HcCParams.Data.Csz == 0) {
247 EPType = (UINT8)((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
248 } else {
249 EPType = (UINT8)((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
250 }
251
252 //
253 // No need to remap.
254 //
255 if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {
256 if (((UINT8)(Urb->Ep.Direction)) == EfiUsbDataIn) {
258 } else {
260 }
261
262 Len = Urb->DataLen;
263 Status = IoMmuMap (MapOp, Urb->Data, &Len, &PhyAddr, &Map);
264
265 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
266 DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
267 return EFI_OUT_OF_RESOURCES;
268 }
269
270 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);
271 Urb->DataMap = Map;
272 }
273
274 //
275 // Construct the TRB
276 //
277 XhcPeiSyncTrsRing (Xhc, EPRing);
278 Urb->TrbStart = EPRing->RingEnqueue;
279 switch (EPType) {
280 case ED_CONTROL_BIDIR:
281 //
282 // For control transfer, create SETUP_STAGE_TRB first.
283 //
284 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
285 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
286 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;
287 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;
288 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;
289 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;
290 TrbStart->TrbCtrSetup.Length = 8;
291 TrbStart->TrbCtrSetup.IntTarget = 0;
292 TrbStart->TrbCtrSetup.IOC = 1;
293 TrbStart->TrbCtrSetup.IDT = 1;
294 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;
295 if (Urb->DataLen > 0) {
296 if (Urb->Ep.Direction == EfiUsbDataIn) {
297 TrbStart->TrbCtrSetup.TRT = 3;
298 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
299 TrbStart->TrbCtrSetup.TRT = 2;
300 } else {
301 DEBUG ((DEBUG_ERROR, "XhcPeiCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));
302 ASSERT (FALSE);
303 }
304 } else {
305 TrbStart->TrbCtrSetup.TRT = 0;
306 }
307
308 //
309 // Update the cycle bit
310 //
311 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
312 Urb->TrbNum++;
313
314 //
315 // For control transfer, create DATA_STAGE_TRB.
316 //
317 if (Urb->DataLen > 0) {
318 XhcPeiSyncTrsRing (Xhc, EPRing);
319 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
320 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT (Urb->DataPhy);
321 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT (Urb->DataPhy);
322 TrbStart->TrbCtrData.Length = (UINT32)Urb->DataLen;
323 TrbStart->TrbCtrData.TDSize = 0;
324 TrbStart->TrbCtrData.IntTarget = 0;
325 TrbStart->TrbCtrData.ISP = 1;
326 TrbStart->TrbCtrData.IOC = 1;
327 TrbStart->TrbCtrData.IDT = 0;
328 TrbStart->TrbCtrData.CH = 0;
329 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;
330 if (Urb->Ep.Direction == EfiUsbDataIn) {
331 TrbStart->TrbCtrData.DIR = 1;
332 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
333 TrbStart->TrbCtrData.DIR = 0;
334 } else {
335 TrbStart->TrbCtrData.DIR = 0;
336 }
337
338 //
339 // Update the cycle bit
340 //
341 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
342 Urb->TrbNum++;
343 }
344
345 //
346 // For control transfer, create STATUS_STAGE_TRB.
347 // Get the pointer to next TRB for status stage use
348 //
349 XhcPeiSyncTrsRing (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 //
364 // Update the cycle bit
365 //
366 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
367 //
368 // Update the enqueue pointer
369 //
370 XhcPeiSyncTrsRing (Xhc, EPRing);
371 Urb->TrbNum++;
372 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
373
374 break;
375
376 case ED_BULK_OUT:
377 case ED_BULK_IN:
378 TotalLen = 0;
379 Len = 0;
380 TrbNum = 0;
381 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
382 while (TotalLen < Urb->DataLen) {
383 if ((TotalLen + 0x10000) >= Urb->DataLen) {
384 Len = Urb->DataLen - TotalLen;
385 } else {
386 Len = 0x10000;
387 }
388
389 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
390 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);
391 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);
392 TrbStart->TrbNormal.Length = (UINT32)Len;
393 TrbStart->TrbNormal.TDSize = 0;
394 TrbStart->TrbNormal.IntTarget = 0;
395 TrbStart->TrbNormal.ISP = 1;
396 TrbStart->TrbNormal.IOC = 1;
397 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
398 //
399 // Update the cycle bit
400 //
401 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
402
403 XhcPeiSyncTrsRing (Xhc, EPRing);
404 TrbNum++;
405 TotalLen += Len;
406 }
407
408 Urb->TrbNum = TrbNum;
409 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
410 break;
411
412 case ED_INTERRUPT_OUT:
413 case ED_INTERRUPT_IN:
414 TotalLen = 0;
415 Len = 0;
416 TrbNum = 0;
417 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
418 while (TotalLen < Urb->DataLen) {
419 if ((TotalLen + 0x10000) >= Urb->DataLen) {
420 Len = Urb->DataLen - TotalLen;
421 } else {
422 Len = 0x10000;
423 }
424
425 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
426 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);
427 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);
428 TrbStart->TrbNormal.Length = (UINT32)Len;
429 TrbStart->TrbNormal.TDSize = 0;
430 TrbStart->TrbNormal.IntTarget = 0;
431 TrbStart->TrbNormal.ISP = 1;
432 TrbStart->TrbNormal.IOC = 1;
433 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
434 //
435 // Update the cycle bit
436 //
437 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
438
439 XhcPeiSyncTrsRing (Xhc, EPRing);
440 TrbNum++;
441 TotalLen += Len;
442 }
443
444 Urb->TrbNum = TrbNum;
445 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
446 break;
447
448 default:
449 DEBUG ((DEBUG_INFO, "Not supported EPType 0x%x!\n", EPType));
450 ASSERT (FALSE);
451 break;
452 }
453
454 return EFI_SUCCESS;
455}
456
473 IN PEI_XHC_DEV *Xhc,
474 IN URB *Urb
475 )
476{
477 EFI_STATUS Status;
478 UINT8 Dci;
479 UINT8 SlotId;
480
481 Status = EFI_SUCCESS;
482 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
483 if (SlotId == 0) {
484 return EFI_DEVICE_ERROR;
485 }
486
487 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
488
489 DEBUG ((DEBUG_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));
490
491 //
492 // 1) Send Reset endpoint command to transit from halt to stop state
493 //
494 Status = XhcPeiResetEndpoint (Xhc, SlotId, Dci);
495 if (EFI_ERROR (Status)) {
496 DEBUG ((DEBUG_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
497 goto Done;
498 }
499
500 //
501 // 2) Set dequeue pointer
502 //
503 Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
504 if (EFI_ERROR (Status)) {
505 DEBUG ((DEBUG_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
506 goto Done;
507 }
508
509 //
510 // 3) Ring the doorbell to transit from stop to active
511 //
512 XhcPeiRingDoorBell (Xhc, SlotId, Dci);
513
514Done:
515 return Status;
516}
517
533 IN PEI_XHC_DEV *Xhc,
534 IN URB *Urb
535 )
536{
537 EFI_STATUS Status;
538 UINT8 Dci;
539 UINT8 SlotId;
540
541 Status = EFI_SUCCESS;
542 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
543 if (SlotId == 0) {
544 return EFI_DEVICE_ERROR;
545 }
546
547 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
548
549 DEBUG ((DEBUG_INFO, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId, Dci));
550
551 //
552 // 1) Send Stop endpoint command to stop endpoint.
553 //
554 Status = XhcPeiStopEndpoint (Xhc, SlotId, Dci);
555 if (EFI_ERROR (Status)) {
556 DEBUG ((DEBUG_ERROR, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
557 goto Done;
558 }
559
560 //
561 // 2) Set dequeue pointer
562 //
563 Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
564 if (EFI_ERROR (Status)) {
565 DEBUG ((DEBUG_ERROR, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
566 goto Done;
567 }
568
569 //
570 // 3) Ring the doorbell to transit from stop to active
571 //
572 XhcPeiRingDoorBell (Xhc, SlotId, Dci);
573
574Done:
575 return Status;
576}
577
588BOOLEAN
590 IN TRB_TEMPLATE *Trb,
591 IN URB *Urb
592 )
593{
594 TRB_TEMPLATE *CheckedTrb;
595 UINTN Index;
596
597 CheckedTrb = Urb->Ring->RingSeg0;
598
599 ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
600
601 for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
602 if (Trb == CheckedTrb) {
603 return TRUE;
604 }
605
606 CheckedTrb++;
607 }
608
609 return FALSE;
610}
611
622BOOLEAN
624 IN PEI_XHC_DEV *Xhc,
625 IN URB *Urb
626 )
627{
628 EVT_TRB_TRANSFER *EvtTrb;
629 TRB_TEMPLATE *TRBPtr;
630 UINTN Index;
631 UINT8 TRBType;
632 EFI_STATUS Status;
633 URB *CheckedUrb;
634 UINT64 XhcDequeue;
635 UINT32 High;
636 UINT32 Low;
637 EFI_PHYSICAL_ADDRESS PhyAddr;
638
639 ASSERT ((Xhc != NULL) && (Urb != NULL));
640
641 Status = EFI_SUCCESS;
642
643 if (Urb->Finished) {
644 goto EXIT;
645 }
646
647 EvtTrb = NULL;
648
649 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
650 Urb->Result |= EFI_USB_ERR_SYSTEM;
651 goto EXIT;
652 }
653
654 //
655 // Traverse the event ring to find out all new events from the previous check.
656 //
657 XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);
658 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
659 Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
660 if (Status == EFI_NOT_READY) {
661 //
662 // All new events are handled, return directly.
663 //
664 goto EXIT;
665 }
666
667 //
668 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
669 //
670 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
671 continue;
672 }
673
674 //
675 // Need convert pci device address to host address
676 //
677 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));
678 TRBPtr = (TRB_TEMPLATE *)(UINTN)UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN)PhyAddr, sizeof (TRB_TEMPLATE), FALSE);
679
680 //
681 // Update the status of Urb according to the finished event regardless of whether
682 // the urb is current checked one or in the XHCI's async transfer list.
683 // This way is used to avoid that those completed async transfer events don't get
684 // handled in time and are flushed by newer coming events.
685 //
686 if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {
687 CheckedUrb = Urb;
688 } else {
689 continue;
690 }
691
692 switch (EvtTrb->Completecode) {
693 case TRB_COMPLETION_STALL_ERROR:
694 CheckedUrb->Result |= EFI_USB_ERR_STALL;
695 CheckedUrb->Finished = TRUE;
696 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));
697 goto EXIT;
698
699 case TRB_COMPLETION_BABBLE_ERROR:
700 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
701 CheckedUrb->Finished = TRUE;
702 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));
703 goto EXIT;
704
705 case TRB_COMPLETION_DATA_BUFFER_ERROR:
706 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
707 CheckedUrb->Finished = TRUE;
708 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));
709 goto EXIT;
710
711 case TRB_COMPLETION_USB_TRANSACTION_ERROR:
712 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
713 CheckedUrb->Finished = TRUE;
714 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));
715 goto EXIT;
716
717 case TRB_COMPLETION_SHORT_PACKET:
718 case TRB_COMPLETION_SUCCESS:
719 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
720 DEBUG ((DEBUG_VERBOSE, "XhcPeiCheckUrbResult: short packet happens!\n"));
721 }
722
723 TRBType = (UINT8)(TRBPtr->Type);
724 if ((TRBType == TRB_TYPE_DATA_STAGE) ||
725 (TRBType == TRB_TYPE_NORMAL) ||
726 (TRBType == TRB_TYPE_ISOCH))
727 {
728 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);
729 }
730
731 break;
732
733 default:
734 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));
735 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
736 CheckedUrb->Finished = TRUE;
737 goto EXIT;
738 }
739
740 //
741 // Only check first and end Trb event address
742 //
743 if (TRBPtr == CheckedUrb->TrbStart) {
744 CheckedUrb->StartDone = TRUE;
745 }
746
747 if (TRBPtr == CheckedUrb->TrbEnd) {
748 CheckedUrb->EndDone = TRUE;
749 }
750
751 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
752 CheckedUrb->Finished = TRUE;
753 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;
754 }
755 }
756
757EXIT:
758
759 //
760 // Advance event ring to last available entry
761 //
762 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
763 // So divide it to two 32-bytes width register access.
764 //
765 Low = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
766 High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
767 XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);
768
769 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE), FALSE);
770
771 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
772 //
773 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
774 // So divide it to two 32-bytes width register access.
775 //
776 XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
777 XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
778 }
779
780 return Urb->Finished;
781}
782
798 IN PEI_XHC_DEV *Xhc,
799 IN BOOLEAN CmdTransfer,
800 IN URB *Urb,
801 IN UINTN Timeout
802 )
803{
804 EFI_STATUS Status;
805 UINTN Index;
806 UINT64 Loop;
807 UINT8 SlotId;
808 UINT8 Dci;
809 BOOLEAN Finished;
810
811 if (CmdTransfer) {
812 SlotId = 0;
813 Dci = 0;
814 } else {
815 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
816 if (SlotId == 0) {
817 return EFI_DEVICE_ERROR;
818 }
819
820 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
821 }
822
823 Status = EFI_SUCCESS;
824 Loop = Timeout * XHC_1_MILLISECOND;
825 if (Timeout == 0) {
826 Loop = 0xFFFFFFFF;
827 }
828
829 XhcPeiRingDoorBell (Xhc, SlotId, Dci);
830
831 for (Index = 0; Index < Loop; Index++) {
832 Finished = XhcPeiCheckUrbResult (Xhc, Urb);
833 if (Finished) {
834 break;
835 }
836
837 MicroSecondDelay (XHC_1_MICROSECOND);
838 }
839
840 if (Index == Loop) {
841 Urb->Result = EFI_USB_ERR_TIMEOUT;
842 Status = EFI_TIMEOUT;
843 } else if (Urb->Result != EFI_USB_NOERROR) {
844 Status = EFI_DEVICE_ERROR;
845 }
846
847 return Status;
848}
849
864 IN PEI_XHC_DEV *Xhc,
865 IN USB_DEV_ROUTE ParentRouteChart,
866 IN UINT8 Port,
867 IN EFI_USB_PORT_STATUS *PortState
868 )
869{
870 EFI_STATUS Status;
871 UINT8 Speed;
872 UINT8 SlotId;
873 USB_DEV_ROUTE RouteChart;
874
875 DEBUG ((DEBUG_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));
876
877 Status = EFI_SUCCESS;
878
879 if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
880 return EFI_SUCCESS;
881 }
882
883 if (ParentRouteChart.Dword == 0) {
884 RouteChart.Route.RouteString = 0;
885 RouteChart.Route.RootPortNum = Port + 1;
886 RouteChart.Route.TierNum = 1;
887 } else {
888 if (Port < 14) {
889 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
890 } else {
891 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
892 }
893
894 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
895 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
896 }
897
898 SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
899 if (SlotId != 0) {
900 if (Xhc->HcCParams.Data.Csz == 0) {
901 Status = XhcPeiDisableSlotCmd (Xhc, SlotId);
902 } else {
903 Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);
904 }
905 }
906
907 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
908 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0))
909 {
910 //
911 // Has a device attached, Identify device speed after port is enabled.
912 //
913 Speed = EFI_USB_SPEED_FULL;
914 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
915 Speed = EFI_USB_SPEED_LOW;
916 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
917 Speed = EFI_USB_SPEED_HIGH;
918 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
919 Speed = EFI_USB_SPEED_SUPER;
920 }
921
922 //
923 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
924 //
925 SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
926 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
927 if (Xhc->HcCParams.Data.Csz == 0) {
928 Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
929 } else {
930 Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
931 }
932 }
933 }
934
935 return Status;
936}
937
947UINT8
949 IN UINT8 EpAddr,
950 IN EFI_USB_DATA_DIRECTION Direction
951 )
952{
953 UINT8 Index;
954
955 ASSERT (EpAddr <= 15);
956
957 if (EpAddr == 0) {
958 return 1;
959 } else {
960 Index = (UINT8)(2 * EpAddr);
961 if (Direction == EfiUsbDataIn) {
962 Index += 1;
963 }
964
965 return Index;
966 }
967}
968
978UINT8
980 IN PEI_XHC_DEV *Xhc,
981 IN UINT8 BusDevAddr
982 )
983{
984 UINT8 Index;
985
986 for (Index = 0; Index < 255; Index++) {
987 if (Xhc->UsbDevContext[Index + 1].Enabled &&
988 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
989 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr))
990 {
991 break;
992 }
993 }
994
995 if (Index == 255) {
996 return 0;
997 }
998
999 return Xhc->UsbDevContext[Index + 1].SlotId;
1000}
1001
1011UINT8
1013 IN PEI_XHC_DEV *Xhc,
1014 IN USB_DEV_ROUTE RouteString
1015 )
1016{
1017 UINT8 Index;
1018
1019 for (Index = 0; Index < 255; Index++) {
1020 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1021 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1022 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword))
1023 {
1024 break;
1025 }
1026 }
1027
1028 if (Index == 255) {
1029 return 0;
1030 }
1031
1032 return Xhc->UsbDevContext[Index + 1].SlotId;
1033}
1034
1043VOID
1045 IN PEI_XHC_DEV *Xhc,
1046 IN UINT8 SlotId,
1047 IN UINT8 Dci
1048 )
1049{
1050 if (SlotId == 0) {
1051 XhcPeiWriteDoorBellReg (Xhc, 0, 0);
1052 } else {
1053 XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1054 }
1055}
1056
1072 IN PEI_XHC_DEV *Xhc,
1073 IN USB_DEV_ROUTE ParentRouteChart,
1074 IN UINT16 ParentPort,
1075 IN USB_DEV_ROUTE RouteChart,
1076 IN UINT8 DeviceSpeed
1077 )
1078{
1079 EFI_STATUS Status;
1081 INPUT_CONTEXT *InputContext;
1082 DEVICE_CONTEXT *OutputContext;
1083 TRANSFER_RING *EndpointTransferRing;
1084 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1085 UINT8 DeviceAddress;
1086 CMD_TRB_ENABLE_SLOT CmdTrb;
1087 UINT8 SlotId;
1088 UINT8 ParentSlotId;
1089 DEVICE_CONTEXT *ParentDeviceContext;
1090 EFI_PHYSICAL_ADDRESS PhyAddr;
1091
1092 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1093 CmdTrb.CycleBit = 1;
1094 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1095
1096 Status = XhcPeiCmdTransfer (
1097 Xhc,
1098 (TRB_TEMPLATE *)(UINTN)&CmdTrb,
1099 XHC_GENERIC_TIMEOUT,
1100 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1101 );
1102 if (EFI_ERROR (Status)) {
1103 DEBUG ((DEBUG_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
1104 return Status;
1105 }
1106
1107 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1108 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1109 SlotId = (UINT8)EvtTrb->SlotId;
1110 ASSERT (SlotId != 0);
1111
1112 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1113 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1114 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1115 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1116 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1117
1118 //
1119 // 4.3.3 Device Slot Initialization
1120 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1121 //
1122 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
1123 ASSERT (InputContext != NULL);
1124 ASSERT (((UINTN)InputContext & 0x3F) == 0);
1125 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1126
1127 Xhc->UsbDevContext[SlotId].InputContext = (VOID *)InputContext;
1128
1129 //
1130 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1131 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1132 // Context are affected by the command.
1133 //
1134 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1135
1136 //
1137 // 3) Initialize the Input Slot Context data structure
1138 //
1139 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1140 InputContext->Slot.Speed = DeviceSpeed + 1;
1141 InputContext->Slot.ContextEntries = 1;
1142 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1143
1144 if (RouteChart.Route.RouteString != 0) {
1145 //
1146 // The device is behind of hub device.
1147 //
1148 ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
1149 ASSERT (ParentSlotId != 0);
1150 //
1151 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1152 //
1153 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1154 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1155 (ParentDeviceContext->Slot.TTHubSlotId == 0))
1156 {
1157 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1158 //
1159 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1160 // environment from Full/Low speed signaling environment for a device
1161 //
1162 InputContext->Slot.TTPortNum = ParentPort;
1163 InputContext->Slot.TTHubSlotId = ParentSlotId;
1164 }
1165 } else {
1166 //
1167 // Inherit the TT parameters from parent device.
1168 //
1169 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
1170 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1171 //
1172 // If the device is a High speed device then down the speed to be the same as its parent Hub
1173 //
1174 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1175 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1176 }
1177 }
1178 }
1179
1180 //
1181 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1182 //
1183 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1184 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1185 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1186 //
1187 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1188 //
1189 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1190
1191 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1192 InputContext->EP[0].MaxPacketSize = 512;
1193 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1194 InputContext->EP[0].MaxPacketSize = 64;
1195 } else {
1196 InputContext->EP[0].MaxPacketSize = 8;
1197 }
1198
1199 //
1200 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1201 // 1KB, and Bulk and Isoch endpoints 3KB.
1202 //
1203 InputContext->EP[0].AverageTRBLength = 8;
1204 InputContext->EP[0].MaxBurstSize = 0;
1205 InputContext->EP[0].Interval = 0;
1206 InputContext->EP[0].MaxPStreams = 0;
1207 InputContext->EP[0].Mult = 0;
1208 InputContext->EP[0].CErr = 3;
1209
1210 //
1211 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1212 //
1213 PhyAddr = UsbHcGetPciAddrForHostAddr (
1214 Xhc->MemPool,
1215 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
1216 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,
1217 TRUE
1218 );
1219 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
1220 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1221
1222 //
1223 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1224 //
1225 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
1226 ASSERT (OutputContext != NULL);
1227 ASSERT (((UINTN)OutputContext & 0x3F) == 0);
1228 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
1229
1230 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1231 //
1232 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1233 // a pointer to the Output Device Context data structure (6.2.1).
1234 //
1235 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT), TRUE);
1236 //
1237 // Fill DCBAA with PCI device address
1238 //
1239 Xhc->DCBAA[SlotId] = (UINT64)(UINTN)PhyAddr;
1240
1241 //
1242 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1243 // Context data structure described above.
1244 //
1245 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1246 // to device.
1247 //
1248 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
1249 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1250 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT), TRUE);
1251 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
1252 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
1253 CmdTrbAddr.CycleBit = 1;
1254 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
1255 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
1256 Status = XhcPeiCmdTransfer (
1257 Xhc,
1258 (TRB_TEMPLATE *)(UINTN)&CmdTrbAddr,
1259 XHC_GENERIC_TIMEOUT,
1260 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1261 );
1262 if (!EFI_ERROR (Status)) {
1263 DeviceAddress = (UINT8)OutputContext->Slot.DeviceAddress;
1264 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));
1265 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1266 }
1267
1268 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));
1269 return Status;
1270}
1271
1287 IN PEI_XHC_DEV *Xhc,
1288 IN USB_DEV_ROUTE ParentRouteChart,
1289 IN UINT16 ParentPort,
1290 IN USB_DEV_ROUTE RouteChart,
1291 IN UINT8 DeviceSpeed
1292 )
1293{
1294 EFI_STATUS Status;
1296 INPUT_CONTEXT_64 *InputContext;
1297 DEVICE_CONTEXT_64 *OutputContext;
1298 TRANSFER_RING *EndpointTransferRing;
1299 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1300 UINT8 DeviceAddress;
1301 CMD_TRB_ENABLE_SLOT CmdTrb;
1302 UINT8 SlotId;
1303 UINT8 ParentSlotId;
1304 DEVICE_CONTEXT_64 *ParentDeviceContext;
1305 EFI_PHYSICAL_ADDRESS PhyAddr;
1306
1307 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1308 CmdTrb.CycleBit = 1;
1309 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1310
1311 Status = XhcPeiCmdTransfer (
1312 Xhc,
1313 (TRB_TEMPLATE *)(UINTN)&CmdTrb,
1314 XHC_GENERIC_TIMEOUT,
1315 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1316 );
1317 if (EFI_ERROR (Status)) {
1318 DEBUG ((DEBUG_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
1319 return Status;
1320 }
1321
1322 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1323 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1324 SlotId = (UINT8)EvtTrb->SlotId;
1325 ASSERT (SlotId != 0);
1326
1327 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1328 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1329 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1330 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1331 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1332
1333 //
1334 // 4.3.3 Device Slot Initialization
1335 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1336 //
1337 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
1338 ASSERT (InputContext != NULL);
1339 ASSERT (((UINTN)InputContext & 0x3F) == 0);
1340 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1341
1342 Xhc->UsbDevContext[SlotId].InputContext = (VOID *)InputContext;
1343
1344 //
1345 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1346 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1347 // Context are affected by the command.
1348 //
1349 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1350
1351 //
1352 // 3) Initialize the Input Slot Context data structure
1353 //
1354 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1355 InputContext->Slot.Speed = DeviceSpeed + 1;
1356 InputContext->Slot.ContextEntries = 1;
1357 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1358
1359 if (RouteChart.Route.RouteString != 0) {
1360 //
1361 // The device is behind of hub device.
1362 //
1363 ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
1364 ASSERT (ParentSlotId != 0);
1365 //
1366 // if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1367 //
1368 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1369 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1370 (ParentDeviceContext->Slot.TTHubSlotId == 0))
1371 {
1372 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1373 //
1374 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1375 // environment from Full/Low speed signaling environment for a device
1376 //
1377 InputContext->Slot.TTPortNum = ParentPort;
1378 InputContext->Slot.TTHubSlotId = ParentSlotId;
1379 }
1380 } else {
1381 //
1382 // Inherit the TT parameters from parent device.
1383 //
1384 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
1385 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1386 //
1387 // If the device is a High speed device then down the speed to be the same as its parent Hub
1388 //
1389 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1390 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1391 }
1392 }
1393 }
1394
1395 //
1396 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1397 //
1398 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1399 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1400 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1401 //
1402 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1403 //
1404 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1405
1406 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1407 InputContext->EP[0].MaxPacketSize = 512;
1408 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1409 InputContext->EP[0].MaxPacketSize = 64;
1410 } else {
1411 InputContext->EP[0].MaxPacketSize = 8;
1412 }
1413
1414 //
1415 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1416 // 1KB, and Bulk and Isoch endpoints 3KB.
1417 //
1418 InputContext->EP[0].AverageTRBLength = 8;
1419 InputContext->EP[0].MaxBurstSize = 0;
1420 InputContext->EP[0].Interval = 0;
1421 InputContext->EP[0].MaxPStreams = 0;
1422 InputContext->EP[0].Mult = 0;
1423 InputContext->EP[0].CErr = 3;
1424
1425 //
1426 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1427 //
1428 PhyAddr = UsbHcGetPciAddrForHostAddr (
1429 Xhc->MemPool,
1430 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
1431 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,
1432 TRUE
1433 );
1434 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
1435 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1436
1437 //
1438 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1439 //
1440 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
1441 ASSERT (OutputContext != NULL);
1442 ASSERT (((UINTN)OutputContext & 0x3F) == 0);
1443 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
1444
1445 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1446 //
1447 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1448 // a pointer to the Output Device Context data structure (6.2.1).
1449 //
1450 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64), TRUE);
1451 //
1452 // Fill DCBAA with PCI device address
1453 //
1454 Xhc->DCBAA[SlotId] = (UINT64)(UINTN)PhyAddr;
1455
1456 //
1457 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1458 // Context data structure described above.
1459 //
1460 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1461 // to device.
1462 //
1463 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
1464 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1465 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64), TRUE);
1466 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
1467 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
1468 CmdTrbAddr.CycleBit = 1;
1469 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
1470 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
1471 Status = XhcPeiCmdTransfer (
1472 Xhc,
1473 (TRB_TEMPLATE *)(UINTN)&CmdTrbAddr,
1474 XHC_GENERIC_TIMEOUT,
1475 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1476 );
1477 if (!EFI_ERROR (Status)) {
1478 DeviceAddress = (UINT8)OutputContext->Slot.DeviceAddress;
1479 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));
1480 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1481 }
1482
1483 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));
1484 return Status;
1485}
1486
1498 IN PEI_XHC_DEV *Xhc,
1499 IN UINT8 SlotId
1500 )
1501{
1502 EFI_STATUS Status;
1503 TRB_TEMPLATE *EvtTrb;
1504 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
1505 UINT8 Index;
1506 VOID *RingSeg;
1507
1508 //
1509 // Disable the device slots occupied by these devices on its downstream ports.
1510 // Entry 0 is reserved.
1511 //
1512 for (Index = 0; Index < 255; Index++) {
1513 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1514 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1515 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword))
1516 {
1517 continue;
1518 }
1519
1520 Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1521
1522 if (EFI_ERROR (Status)) {
1523 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1524 Xhc->UsbDevContext[Index + 1].SlotId = 0;
1525 }
1526 }
1527
1528 //
1529 // Construct the disable slot command
1530 //
1531 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));
1532
1533 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1534 CmdTrbDisSlot.CycleBit = 1;
1535 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
1536 CmdTrbDisSlot.SlotId = SlotId;
1537 Status = XhcPeiCmdTransfer (
1538 Xhc,
1539 (TRB_TEMPLATE *)(UINTN)&CmdTrbDisSlot,
1540 XHC_GENERIC_TIMEOUT,
1541 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1542 );
1543 if (EFI_ERROR (Status)) {
1544 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
1545 return Status;
1546 }
1547
1548 //
1549 // Free the slot's device context entry
1550 //
1551 Xhc->DCBAA[SlotId] = 0;
1552
1553 //
1554 // Free the slot related data structure
1555 //
1556 for (Index = 0; Index < 31; Index++) {
1557 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1558 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1559 if (RingSeg != NULL) {
1560 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
1561 }
1562
1563 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1564 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
1565 }
1566 }
1567
1568 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1569 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1570 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1571 }
1572 }
1573
1574 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1575 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
1576 }
1577
1578 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1579 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
1580 }
1581
1582 //
1583 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1584 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1585 // remove urb from XHCI's asynchronous transfer list.
1586 //
1587 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1588 Xhc->UsbDevContext[SlotId].SlotId = 0;
1589
1590 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));
1591 return Status;
1592}
1593
1605 IN PEI_XHC_DEV *Xhc,
1606 IN UINT8 SlotId
1607 )
1608{
1609 EFI_STATUS Status;
1610 TRB_TEMPLATE *EvtTrb;
1611 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
1612 UINT8 Index;
1613 VOID *RingSeg;
1614
1615 //
1616 // Disable the device slots occupied by these devices on its downstream ports.
1617 // Entry 0 is reserved.
1618 //
1619 for (Index = 0; Index < 255; Index++) {
1620 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1621 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1622 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword))
1623 {
1624 continue;
1625 }
1626
1627 Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1628
1629 if (EFI_ERROR (Status)) {
1630 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1631 Xhc->UsbDevContext[Index + 1].SlotId = 0;
1632 }
1633 }
1634
1635 //
1636 // Construct the disable slot command
1637 //
1638 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));
1639
1640 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1641 CmdTrbDisSlot.CycleBit = 1;
1642 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
1643 CmdTrbDisSlot.SlotId = SlotId;
1644 Status = XhcPeiCmdTransfer (
1645 Xhc,
1646 (TRB_TEMPLATE *)(UINTN)&CmdTrbDisSlot,
1647 XHC_GENERIC_TIMEOUT,
1648 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1649 );
1650 if (EFI_ERROR (Status)) {
1651 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));
1652 return Status;
1653 }
1654
1655 //
1656 // Free the slot's device context entry
1657 //
1658 Xhc->DCBAA[SlotId] = 0;
1659
1660 //
1661 // Free the slot related data structure
1662 //
1663 for (Index = 0; Index < 31; Index++) {
1664 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1665 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1666 if (RingSeg != NULL) {
1667 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
1668 }
1669
1670 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1671 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
1672 }
1673 }
1674
1675 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1676 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1677 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1678 }
1679 }
1680
1681 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1682 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
1683 }
1684
1685 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1686 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
1687 }
1688
1689 //
1690 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1691 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1692 // remove urb from XHCI's asynchronous transfer list.
1693 //
1694 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1695 Xhc->UsbDevContext[SlotId].SlotId = 0;
1696
1697 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));
1698 return Status;
1699}
1700
1714 IN PEI_XHC_DEV *Xhc,
1715 IN UINT8 SlotId,
1716 IN UINT8 DeviceSpeed,
1717 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
1718 )
1719{
1720 EFI_STATUS Status;
1723 UINT8 Index;
1724 UINTN NumEp;
1725 UINTN EpIndex;
1726 UINT8 EpAddr;
1727 EFI_USB_DATA_DIRECTION Direction;
1728 UINT8 Dci;
1729 UINT8 MaxDci;
1730 EFI_PHYSICAL_ADDRESS PhyAddr;
1731 UINT8 Interval;
1732
1733 TRANSFER_RING *EndpointTransferRing;
1734 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
1735 INPUT_CONTEXT *InputContext;
1736 DEVICE_CONTEXT *OutputContext;
1738
1739 //
1740 // 4.6.6 Configure Endpoint
1741 //
1742 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
1743 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1744 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1745 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
1746
1747 ASSERT (ConfigDesc != NULL);
1748
1749 MaxDci = 0;
1750
1751 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
1752 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1753 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
1754 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
1755 }
1756
1757 NumEp = IfDesc->NumEndpoints;
1758 if ((NumEp == 0) && (MaxDci == 0)) {
1759 MaxDci = 1;
1760 }
1761
1762 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
1763 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1764 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1765 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1766 }
1767
1768 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
1769 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
1770
1771 Dci = XhcPeiEndpointToDci (EpAddr, Direction);
1772 if (Dci > MaxDci) {
1773 MaxDci = Dci;
1774 }
1775
1776 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
1777 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
1778
1779 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1780 //
1781 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1782 //
1783 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1784 } else {
1785 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
1786 }
1787
1788 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
1789 case USB_ENDPOINT_BULK:
1790 if (Direction == EfiUsbDataIn) {
1791 InputContext->EP[Dci-1].CErr = 3;
1792 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
1793 } else {
1794 InputContext->EP[Dci-1].CErr = 3;
1795 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
1796 }
1797
1798 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1799 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1800 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1801 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;
1802 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1803 }
1804
1805 break;
1806 case USB_ENDPOINT_ISO:
1807 if (Direction == EfiUsbDataIn) {
1808 InputContext->EP[Dci-1].CErr = 0;
1809 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
1810 } else {
1811 InputContext->EP[Dci-1].CErr = 0;
1812 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
1813 }
1814
1815 //
1816 // Get the bInterval from descriptor and init the the interval field of endpoint context.
1817 // Refer to XHCI 1.1 spec section 6.2.3.6.
1818 //
1819 if (DeviceSpeed == EFI_USB_SPEED_FULL) {
1820 Interval = EpDesc->Interval;
1821 ASSERT (Interval >= 1 && Interval <= 16);
1822 InputContext->EP[Dci-1].Interval = Interval + 2;
1823 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
1824 Interval = EpDesc->Interval;
1825 ASSERT (Interval >= 1 && Interval <= 16);
1826 InputContext->EP[Dci-1].Interval = Interval - 1;
1827 }
1828
1829 //
1830 // Do not support isochronous transfer now.
1831 //
1832 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1833 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1834 continue;
1835 case USB_ENDPOINT_INTERRUPT:
1836 if (Direction == EfiUsbDataIn) {
1837 InputContext->EP[Dci-1].CErr = 3;
1838 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
1839 } else {
1840 InputContext->EP[Dci-1].CErr = 3;
1841 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
1842 }
1843
1844 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
1845 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
1846 //
1847 // Get the bInterval from descriptor and init the interval field of endpoint context
1848 //
1849 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
1850 Interval = EpDesc->Interval;
1851 //
1852 // Calculate through the bInterval field of Endpoint descriptor.
1853 //
1854 ASSERT (Interval != 0);
1855 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32 ((UINT32)Interval) + 3;
1856 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
1857 Interval = EpDesc->Interval;
1858 ASSERT (Interval >= 1 && Interval <= 16);
1859 //
1860 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1861 //
1862 InputContext->EP[Dci-1].Interval = Interval - 1;
1863 }
1864
1865 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
1866 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1867 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;
1868 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
1869 }
1870
1871 break;
1872
1873 case USB_ENDPOINT_CONTROL:
1874 //
1875 // Do not support control transfer now.
1876 //
1877 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1878 default:
1879 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1880 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1881 continue;
1882 }
1883
1884 PhyAddr = UsbHcGetPciAddrForHostAddr (
1885 Xhc->MemPool,
1886 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
1887 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,
1888 TRUE
1889 );
1890 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
1891 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
1892 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
1893 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
1894
1895 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1896 }
1897
1898 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
1899 }
1900
1901 InputContext->InputControlContext.Dword2 |= BIT0;
1902 InputContext->Slot.ContextEntries = MaxDci;
1903 //
1904 // configure endpoint
1905 //
1906 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
1907 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT), TRUE);
1908 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
1909 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
1910 CmdTrbCfgEP.CycleBit = 1;
1911 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
1912 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
1913 DEBUG ((DEBUG_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));
1914 Status = XhcPeiCmdTransfer (
1915 Xhc,
1916 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,
1917 XHC_GENERIC_TIMEOUT,
1918 (TRB_TEMPLATE **)(UINTN)&EvtTrb
1919 );
1920 if (EFI_ERROR (Status)) {
1921 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
1922 }
1923
1924 return Status;
1925}
1926
1940 IN PEI_XHC_DEV *Xhc,
1941 IN UINT8 SlotId,
1942 IN UINT8 DeviceSpeed,
1943 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
1944 )
1945{
1946 EFI_STATUS Status;
1949 UINT8 Index;
1950 UINTN NumEp;
1951 UINTN EpIndex;
1952 UINT8 EpAddr;
1953 EFI_USB_DATA_DIRECTION Direction;
1954 UINT8 Dci;
1955 UINT8 MaxDci;
1956 EFI_PHYSICAL_ADDRESS PhyAddr;
1957 UINT8 Interval;
1958
1959 TRANSFER_RING *EndpointTransferRing;
1960 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
1961 INPUT_CONTEXT_64 *InputContext;
1962 DEVICE_CONTEXT_64 *OutputContext;
1964
1965 //
1966 // 4.6.6 Configure Endpoint
1967 //
1968 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
1969 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1970 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1971 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
1972
1973 ASSERT (ConfigDesc != NULL);
1974
1975 MaxDci = 0;
1976
1977 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
1978 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1979 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
1980 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
1981 }
1982
1983 NumEp = IfDesc->NumEndpoints;
1984 if ((NumEp == 0) && (MaxDci == 0)) {
1985 MaxDci = 1;
1986 }
1987
1988 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
1989 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1990 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1991 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1992 }
1993
1994 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
1995 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
1996
1997 Dci = XhcPeiEndpointToDci (EpAddr, Direction);
1998 ASSERT (Dci < 32);
1999 if (Dci > MaxDci) {
2000 MaxDci = Dci;
2001 }
2002
2003 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2004 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2005
2006 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2007 //
2008 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2009 //
2010 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2011 } else {
2012 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2013 }
2014
2015 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2016 case USB_ENDPOINT_BULK:
2017 if (Direction == EfiUsbDataIn) {
2018 InputContext->EP[Dci-1].CErr = 3;
2019 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2020 } else {
2021 InputContext->EP[Dci-1].CErr = 3;
2022 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2023 }
2024
2025 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2026 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2027 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2028 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;
2029 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2030 }
2031
2032 break;
2033 case USB_ENDPOINT_ISO:
2034 if (Direction == EfiUsbDataIn) {
2035 InputContext->EP[Dci-1].CErr = 0;
2036 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2037 } else {
2038 InputContext->EP[Dci-1].CErr = 0;
2039 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2040 }
2041
2042 //
2043 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2044 // Refer to XHCI 1.1 spec section 6.2.3.6.
2045 //
2046 if (DeviceSpeed == EFI_USB_SPEED_FULL) {
2047 Interval = EpDesc->Interval;
2048 ASSERT (Interval >= 1 && Interval <= 16);
2049 InputContext->EP[Dci-1].Interval = Interval + 2;
2050 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2051 Interval = EpDesc->Interval;
2052 ASSERT (Interval >= 1 && Interval <= 16);
2053 InputContext->EP[Dci-1].Interval = Interval - 1;
2054 }
2055
2056 //
2057 // Do not support isochronous transfer now.
2058 //
2059 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2060 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2061 continue;
2062 case USB_ENDPOINT_INTERRUPT:
2063 if (Direction == EfiUsbDataIn) {
2064 InputContext->EP[Dci-1].CErr = 3;
2065 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2066 } else {
2067 InputContext->EP[Dci-1].CErr = 3;
2068 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2069 }
2070
2071 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2072 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2073 //
2074 // Get the bInterval from descriptor and init the the interval field of endpoint context
2075 //
2076 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2077 Interval = EpDesc->Interval;
2078 //
2079 // Calculate through the bInterval field of Endpoint descriptor.
2080 //
2081 ASSERT (Interval != 0);
2082 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32 ((UINT32)Interval) + 3;
2083 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2084 Interval = EpDesc->Interval;
2085 ASSERT (Interval >= 1 && Interval <= 16);
2086 //
2087 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2088 //
2089 InputContext->EP[Dci-1].Interval = Interval - 1;
2090 }
2091
2092 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2093 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2094 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;
2095 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2096 }
2097
2098 break;
2099
2100 case USB_ENDPOINT_CONTROL:
2101 //
2102 // Do not support control transfer now.
2103 //
2104 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2105 default:
2106 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
2107 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2108 continue;
2109 }
2110
2111 PhyAddr = UsbHcGetPciAddrForHostAddr (
2112 Xhc->MemPool,
2113 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2114 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER,
2115 TRUE
2116 );
2117
2118 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
2119 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2120
2121 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2122 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2123
2124 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2125 }
2126
2127 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2128 }
2129
2130 InputContext->InputControlContext.Dword2 |= BIT0;
2131 InputContext->Slot.ContextEntries = MaxDci;
2132 //
2133 // configure endpoint
2134 //
2135 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2136 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64), TRUE);
2137 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
2138 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2139 CmdTrbCfgEP.CycleBit = 1;
2140 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2141 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2142 DEBUG ((DEBUG_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));
2143 Status = XhcPeiCmdTransfer (
2144 Xhc,
2145 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,
2146 XHC_GENERIC_TIMEOUT,
2147 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2148 );
2149 if (EFI_ERROR (Status)) {
2150 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
2151 }
2152
2153 return Status;
2154}
2155
2168 IN PEI_XHC_DEV *Xhc,
2169 IN UINT8 SlotId,
2170 IN UINT32 MaxPacketSize
2171 )
2172{
2173 EFI_STATUS Status;
2174 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2176 INPUT_CONTEXT *InputContext;
2177 EFI_PHYSICAL_ADDRESS PhyAddr;
2178
2179 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2180
2181 //
2182 // 4.6.7 Evaluate Context
2183 //
2184 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2185 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2186
2187 InputContext->InputControlContext.Dword2 |= BIT1;
2188 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2189
2190 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2191 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT), TRUE);
2192 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
2193 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2194 CmdTrbEvalu.CycleBit = 1;
2195 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2196 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2197 DEBUG ((DEBUG_INFO, "XhcEvaluateContext: Evaluate context\n"));
2198 Status = XhcPeiCmdTransfer (
2199 Xhc,
2200 (TRB_TEMPLATE *)(UINTN)&CmdTrbEvalu,
2201 XHC_GENERIC_TIMEOUT,
2202 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2203 );
2204 if (EFI_ERROR (Status)) {
2205 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
2206 }
2207
2208 return Status;
2209}
2210
2223 IN PEI_XHC_DEV *Xhc,
2224 IN UINT8 SlotId,
2225 IN UINT32 MaxPacketSize
2226 )
2227{
2228 EFI_STATUS Status;
2229 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2231 INPUT_CONTEXT_64 *InputContext;
2232 EFI_PHYSICAL_ADDRESS PhyAddr;
2233
2234 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2235
2236 //
2237 // 4.6.7 Evaluate Context
2238 //
2239 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2240 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2241
2242 InputContext->InputControlContext.Dword2 |= BIT1;
2243 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2244
2245 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2246 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64), TRUE);
2247 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
2248 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2249 CmdTrbEvalu.CycleBit = 1;
2250 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2251 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2252 DEBUG ((DEBUG_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));
2253 Status = XhcPeiCmdTransfer (
2254 Xhc,
2255 (TRB_TEMPLATE *)(UINTN)&CmdTrbEvalu,
2256 XHC_GENERIC_TIMEOUT,
2257 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2258 );
2259 if (EFI_ERROR (Status)) {
2260 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
2261 }
2262
2263 return Status;
2264}
2265
2280 IN PEI_XHC_DEV *Xhc,
2281 IN UINT8 SlotId,
2282 IN UINT8 PortNum,
2283 IN UINT8 TTT,
2284 IN UINT8 MTT
2285 )
2286{
2287 EFI_STATUS Status;
2289 INPUT_CONTEXT *InputContext;
2290 DEVICE_CONTEXT *OutputContext;
2291 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2292 EFI_PHYSICAL_ADDRESS PhyAddr;
2293
2294 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2295 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2296 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2297
2298 //
2299 // 4.6.7 Evaluate Context
2300 //
2301 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2302
2303 InputContext->InputControlContext.Dword2 |= BIT0;
2304
2305 //
2306 // Copy the slot context from OutputContext to Input context
2307 //
2308 CopyMem (&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
2309 InputContext->Slot.Hub = 1;
2310 InputContext->Slot.PortNum = PortNum;
2311 InputContext->Slot.TTT = TTT;
2312 InputContext->Slot.MTT = MTT;
2313
2314 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2315 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT), TRUE);
2316 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
2317 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2318 CmdTrbCfgEP.CycleBit = 1;
2319 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2320 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2321 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context\n"));
2322 Status = XhcPeiCmdTransfer (
2323 Xhc,
2324 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,
2325 XHC_GENERIC_TIMEOUT,
2326 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2327 );
2328 if (EFI_ERROR (Status)) {
2329 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
2330 }
2331
2332 return Status;
2333}
2334
2349 IN PEI_XHC_DEV *Xhc,
2350 IN UINT8 SlotId,
2351 IN UINT8 PortNum,
2352 IN UINT8 TTT,
2353 IN UINT8 MTT
2354 )
2355{
2356 EFI_STATUS Status;
2358 INPUT_CONTEXT_64 *InputContext;
2359 DEVICE_CONTEXT_64 *OutputContext;
2360 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2361 EFI_PHYSICAL_ADDRESS PhyAddr;
2362
2363 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2364 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2365 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2366
2367 //
2368 // 4.6.7 Evaluate Context
2369 //
2370 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2371
2372 InputContext->InputControlContext.Dword2 |= BIT0;
2373
2374 //
2375 // Copy the slot context from OutputContext to Input context
2376 //
2377 CopyMem (&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
2378 InputContext->Slot.Hub = 1;
2379 InputContext->Slot.PortNum = PortNum;
2380 InputContext->Slot.TTT = TTT;
2381 InputContext->Slot.MTT = MTT;
2382
2383 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2384 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64), TRUE);
2385 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
2386 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2387 CmdTrbCfgEP.CycleBit = 1;
2388 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2389 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2390 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context 64\n"));
2391 Status = XhcPeiCmdTransfer (
2392 Xhc,
2393 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,
2394 XHC_GENERIC_TIMEOUT,
2395 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2396 );
2397 if (EFI_ERROR (Status)) {
2398 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
2399 }
2400
2401 return Status;
2402}
2403
2416EFIAPI
2418 IN PEI_XHC_DEV *Xhc,
2419 IN UINT8 SlotId,
2420 IN UINT8 Dci
2421 )
2422{
2423 EFI_STATUS Status;
2425 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;
2426
2427 DEBUG ((DEBUG_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
2428
2429 //
2430 // Send stop endpoint command to transit Endpoint from running to stop state
2431 //
2432 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
2433 CmdTrbStopED.CycleBit = 1;
2434 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;
2435 CmdTrbStopED.EDID = Dci;
2436 CmdTrbStopED.SlotId = SlotId;
2437 Status = XhcPeiCmdTransfer (
2438 Xhc,
2439 (TRB_TEMPLATE *)(UINTN)&CmdTrbStopED,
2440 XHC_GENERIC_TIMEOUT,
2441 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2442 );
2443 if (EFI_ERROR (Status)) {
2444 DEBUG ((DEBUG_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
2445 }
2446
2447 return Status;
2448}
2449
2462EFIAPI
2464 IN PEI_XHC_DEV *Xhc,
2465 IN UINT8 SlotId,
2466 IN UINT8 Dci
2467 )
2468{
2469 EFI_STATUS Status;
2471 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
2472
2473 DEBUG ((DEBUG_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
2474
2475 //
2476 // Send stop endpoint command to transit Endpoint from running to stop state
2477 //
2478 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
2479 CmdTrbResetED.CycleBit = 1;
2480 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
2481 CmdTrbResetED.EDID = Dci;
2482 CmdTrbResetED.SlotId = SlotId;
2483 Status = XhcPeiCmdTransfer (
2484 Xhc,
2485 (TRB_TEMPLATE *)(UINTN)&CmdTrbResetED,
2486 XHC_GENERIC_TIMEOUT,
2487 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2488 );
2489 if (EFI_ERROR (Status)) {
2490 DEBUG ((DEBUG_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
2491 }
2492
2493 return Status;
2494}
2495
2510EFIAPI
2512 IN PEI_XHC_DEV *Xhc,
2513 IN UINT8 SlotId,
2514 IN UINT8 Dci,
2515 IN URB *Urb
2516 )
2517{
2518 EFI_STATUS Status;
2520 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
2521 EFI_PHYSICAL_ADDRESS PhyAddr;
2522
2523 DEBUG ((DEBUG_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
2524
2525 //
2526 // Send stop endpoint command to transit Endpoint from running to stop state
2527 //
2528 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
2529 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER), FALSE);
2530 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
2531 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2532 CmdSetTRDeq.CycleBit = 1;
2533 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
2534 CmdSetTRDeq.Endpoint = Dci;
2535 CmdSetTRDeq.SlotId = SlotId;
2536 Status = XhcPeiCmdTransfer (
2537 Xhc,
2538 (TRB_TEMPLATE *)(UINTN)&CmdSetTRDeq,
2539 XHC_GENERIC_TIMEOUT,
2540 (TRB_TEMPLATE **)(UINTN)&EvtTrb
2541 );
2542 if (EFI_ERROR (Status)) {
2543 DEBUG ((DEBUG_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
2544 }
2545
2546 return Status;
2547}
2548
2562 IN PEI_XHC_DEV *Xhc,
2563 IN EVENT_RING *EvtRing,
2564 OUT TRB_TEMPLATE **NewEvtTrb
2565 )
2566{
2567 ASSERT (EvtRing != NULL);
2568
2569 *NewEvtTrb = EvtRing->EventRingDequeue;
2570
2571 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
2572 return EFI_NOT_READY;
2573 }
2574
2575 EvtRing->EventRingDequeue++;
2576 //
2577 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2578 //
2579 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2580 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
2581 }
2582
2583 return EFI_SUCCESS;
2584}
2585
2597 IN PEI_XHC_DEV *Xhc,
2598 IN EVENT_RING *EvtRing
2599 )
2600{
2601 UINTN Index;
2602 TRB_TEMPLATE *EvtTrb;
2603
2604 ASSERT (EvtRing != NULL);
2605
2606 //
2607 // Calculate the EventRingEnqueue and EventRingCCS.
2608 // Note: only support single Segment
2609 //
2610 EvtTrb = EvtRing->EventRingDequeue;
2611
2612 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
2613 if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {
2614 break;
2615 }
2616
2617 EvtTrb++;
2618
2619 if ((UINTN)EvtTrb >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
2620 EvtTrb = EvtRing->EventRingSeg0;
2621 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
2622 }
2623 }
2624
2625 if (Index < EvtRing->TrbNumber) {
2626 EvtRing->EventRingEnqueue = EvtTrb;
2627 } else {
2628 ASSERT (FALSE);
2629 }
2630
2631 return EFI_SUCCESS;
2632}
2633
2641VOID
2643 IN PEI_XHC_DEV *Xhc,
2644 IN EVENT_RING *EventRing
2645 )
2646{
2647 if (EventRing->EventRingSeg0 == NULL) {
2648 return;
2649 }
2650
2651 //
2652 // Free EventRing Segment 0
2653 //
2654 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
2655
2656 //
2657 // Free ERST table
2658 //
2659 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
2660}
2661
2669VOID
2671 IN PEI_XHC_DEV *Xhc,
2672 OUT EVENT_RING *EventRing
2673 )
2674{
2675 VOID *Buf;
2677 UINTN Size;
2678 EFI_PHYSICAL_ADDRESS ERSTPhy;
2679 EFI_PHYSICAL_ADDRESS DequeuePhy;
2680
2681 ASSERT (EventRing != NULL);
2682
2683 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
2684 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
2685 ASSERT (Buf != NULL);
2686 ASSERT (((UINTN)Buf & 0x3F) == 0);
2687 ZeroMem (Buf, Size);
2688
2689 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size, TRUE);
2690
2691 EventRing->EventRingSeg0 = Buf;
2692 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
2693 EventRing->EventRingDequeue = (TRB_TEMPLATE *)EventRing->EventRingSeg0;
2694 EventRing->EventRingEnqueue = (TRB_TEMPLATE *)EventRing->EventRingSeg0;
2695
2696 //
2697 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2698 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2699 //
2700 EventRing->EventRingCCS = 1;
2701
2702 Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
2703 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
2704 ASSERT (Buf != NULL);
2705 ASSERT (((UINTN)Buf & 0x3F) == 0);
2706 ZeroMem (Buf, Size);
2707
2708 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf;
2709 EventRing->ERSTBase = ERSTBase;
2710 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);
2711 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);
2712 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
2713
2714 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size, TRUE);
2715
2716 //
2717 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2718 //
2720 Xhc,
2721 XHC_ERSTSZ_OFFSET,
2722 ERST_NUMBER
2723 );
2724 //
2725 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2726 //
2727 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2728 // So divide it to two 32-bytes width register access.
2729 //
2731 Xhc,
2732 XHC_ERDP_OFFSET,
2733 XHC_LOW_32BIT ((UINT64)(UINTN)DequeuePhy)
2734 );
2736 Xhc,
2737 XHC_ERDP_OFFSET + 4,
2738 XHC_HIGH_32BIT ((UINT64)(UINTN)DequeuePhy)
2739 );
2740 //
2741 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2742 //
2743 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2744 // So divide it to two 32-bytes width register access.
2745 //
2747 Xhc,
2748 XHC_ERSTBA_OFFSET,
2749 XHC_LOW_32BIT ((UINT64)(UINTN)ERSTPhy)
2750 );
2752 Xhc,
2753 XHC_ERSTBA_OFFSET + 4,
2754 XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTPhy)
2755 );
2756 //
2757 // Need set IMAN IE bit to enable the ring interrupt
2758 //
2759 XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
2760}
2761
2773 IN PEI_XHC_DEV *Xhc,
2774 IN TRANSFER_RING *TrsRing
2775 )
2776{
2777 UINTN Index;
2778 TRB_TEMPLATE *TrsTrb;
2779
2780 ASSERT (TrsRing != NULL);
2781 //
2782 // Calculate the latest RingEnqueue and RingPCS
2783 //
2784 TrsTrb = TrsRing->RingEnqueue;
2785 ASSERT (TrsTrb != NULL);
2786
2787 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
2788 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
2789 break;
2790 }
2791
2792 TrsTrb++;
2793 if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {
2794 ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);
2795 //
2796 // set cycle bit in Link TRB as normal
2797 //
2798 ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
2799 //
2800 // Toggle PCS maintained by software
2801 //
2802 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
2803 TrsTrb = (TRB_TEMPLATE *)TrsRing->RingSeg0; // Use host address
2804 }
2805 }
2806
2807 ASSERT (Index != TrsRing->TrbNumber);
2808
2809 if (TrsTrb != TrsRing->RingEnqueue) {
2810 TrsRing->RingEnqueue = TrsTrb;
2811 }
2812
2813 //
2814 // Clear the Trb context for enqueue, but reserve the PCS bit
2815 //
2816 TrsTrb->Parameter1 = 0;
2817 TrsTrb->Parameter2 = 0;
2818 TrsTrb->Status = 0;
2819 TrsTrb->RsvdZ1 = 0;
2820 TrsTrb->Type = 0;
2821 TrsTrb->Control = 0;
2822
2823 return EFI_SUCCESS;
2824}
2825
2834VOID
2836 IN PEI_XHC_DEV *Xhc,
2837 IN UINTN TrbNum,
2838 OUT TRANSFER_RING *TransferRing
2839 )
2840{
2841 VOID *Buf;
2842 LINK_TRB *EndTrb;
2843 EFI_PHYSICAL_ADDRESS PhyAddr;
2844
2845 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
2846 ASSERT (Buf != NULL);
2847 ASSERT (((UINTN)Buf & 0x3F) == 0);
2848 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
2849
2850 TransferRing->RingSeg0 = Buf;
2851 TransferRing->TrbNumber = TrbNum;
2852 TransferRing->RingEnqueue = (TRB_TEMPLATE *)TransferRing->RingSeg0;
2853 TransferRing->RingDequeue = (TRB_TEMPLATE *)TransferRing->RingSeg0;
2854 TransferRing->RingPCS = 1;
2855 //
2856 // 4.9.2 Transfer Ring Management
2857 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2858 // point to the first TRB in the ring.
2859 //
2860 EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
2861 EndTrb->Type = TRB_TYPE_LINK;
2862 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum, TRUE);
2863 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
2864 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
2865 //
2866 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2867 //
2868 EndTrb->TC = 1;
2869 //
2870 // Set Cycle bit as other TRB PCS init value
2871 //
2872 EndTrb->CycleBit = 0;
2873}
2874
2881VOID
2883 IN PEI_XHC_DEV *Xhc
2884 )
2885{
2886 VOID *Dcbaa;
2887 EFI_PHYSICAL_ADDRESS DcbaaPhy;
2888 UINTN Size;
2889 EFI_PHYSICAL_ADDRESS CmdRingPhy;
2890 UINT32 MaxScratchpadBufs;
2891 UINT64 *ScratchBuf;
2892 EFI_PHYSICAL_ADDRESS ScratchPhy;
2893 UINT64 *ScratchEntry;
2894 EFI_PHYSICAL_ADDRESS ScratchEntryPhy;
2895 UINT32 Index;
2896 UINTN *ScratchEntryMap;
2897 EFI_STATUS Status;
2898
2899 //
2900 // Initialize memory management.
2901 //
2902 Xhc->MemPool = UsbHcInitMemPool ();
2903 ASSERT (Xhc->MemPool != NULL);
2904
2905 //
2906 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2907 // to enable the device slots that system software is going to use.
2908 //
2909 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
2910 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
2911 XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);
2912
2913 //
2914 // The Device Context Base Address Array entry associated with each allocated Device Slot
2915 // shall contain a 64-bit pointer to the base of the associated Device Context.
2916 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2917 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2918 //
2919 Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);
2920 Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);
2921 ASSERT (Dcbaa != NULL);
2922
2923 //
2924 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2925 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2926 // mode (Run/Stop(R/S) ='1').
2927 //
2928 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
2929 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
2930 ASSERT (MaxScratchpadBufs <= 1023);
2931 if (MaxScratchpadBufs != 0) {
2932 //
2933 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
2934 //
2935 ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);
2936 ASSERT (ScratchEntryMap != NULL);
2937 Xhc->ScratchEntryMap = ScratchEntryMap;
2938
2939 //
2940 // Allocate the buffer to record the host address for each entry
2941 //
2942 ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
2943 ASSERT (ScratchEntry != NULL);
2944 Xhc->ScratchEntry = ScratchEntry;
2945
2946 ScratchPhy = 0;
2947 Status = UsbHcAllocateAlignedPages (
2948 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
2949 Xhc->PageSize,
2950 (VOID **)&ScratchBuf,
2951 &ScratchPhy,
2952 &Xhc->ScratchMap
2953 );
2954 ASSERT_EFI_ERROR (Status);
2955
2956 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
2957 Xhc->ScratchBuf = ScratchBuf;
2958
2959 //
2960 // Allocate each scratch buffer
2961 //
2962 for (Index = 0; Index < MaxScratchpadBufs; Index++) {
2963 ScratchEntryPhy = 0;
2964 Status = UsbHcAllocateAlignedPages (
2965 EFI_SIZE_TO_PAGES (Xhc->PageSize),
2966 Xhc->PageSize,
2967 (VOID **)&ScratchEntry[Index],
2968 &ScratchEntryPhy,
2969 (VOID **)&ScratchEntryMap[Index]
2970 );
2971 ASSERT_EFI_ERROR (Status);
2972 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);
2973 //
2974 // Fill with the PCI device address
2975 //
2976 *ScratchBuf++ = ScratchEntryPhy;
2977 }
2978
2979 //
2980 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2981 // Device Context Base Address Array points to the Scratchpad Buffer Array.
2982 //
2983 *(UINT64 *)Dcbaa = (UINT64)(UINTN)ScratchPhy;
2984 }
2985
2986 //
2987 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2988 // a 64-bit address pointing to where the Device Context Base Address Array is located.
2989 //
2990 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;
2991 //
2992 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2993 // So divide it to two 32-bytes width register access.
2994 //
2995 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size, TRUE);
2996 XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));
2997 XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
2998
2999 DEBUG ((DEBUG_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));
3000
3001 //
3002 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
3003 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
3004 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
3005 // always be '0'.
3006 //
3007 XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
3008 //
3009 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
3010 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
3011 // So we set RCS as inverted PCS init value to let Command Ring empty
3012 //
3013 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER, TRUE);
3014 ASSERT ((CmdRingPhy & 0x3F) == 0);
3015 CmdRingPhy |= XHC_CRCR_RCS;
3016 //
3017 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
3018 // So divide it to two 32-bytes width register access.
3019 //
3020 XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));
3021 XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
3022
3023 DEBUG ((DEBUG_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
3024
3025 //
3026 // Disable the 'interrupter enable' bit in USB_CMD
3027 // and clear IE & IP bit in all Interrupter X Management Registers.
3028 //
3029 XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
3030 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
3031 XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
3032 XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
3033 }
3034
3035 //
3036 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
3037 //
3038 XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);
3039 DEBUG ((DEBUG_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
3040}
3041
3048VOID
3050 IN PEI_XHC_DEV *Xhc
3051 )
3052{
3053 UINT32 Index;
3054 UINT64 *ScratchEntry;
3055
3056 if (Xhc->ScratchBuf != NULL) {
3057 ScratchEntry = Xhc->ScratchEntry;
3058 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
3059 //
3060 // Free Scratchpad Buffers
3061 //
3062 UsbHcFreeAlignedPages ((VOID *)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *)Xhc->ScratchEntryMap[Index]);
3063 }
3064
3065 //
3066 // Free Scratchpad Buffer Array
3067 //
3068 UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);
3069 FreePool (Xhc->ScratchEntryMap);
3070 FreePool (Xhc->ScratchEntry);
3071 }
3072
3073 if (Xhc->CmdRing.RingSeg0 != NULL) {
3074 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
3075 Xhc->CmdRing.RingSeg0 = NULL;
3076 }
3077
3078 XhcPeiFreeEventRing (Xhc, &Xhc->EventRing);
3079
3080 if (Xhc->DCBAA != NULL) {
3081 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));
3082 Xhc->DCBAA = NULL;
3083 }
3084
3085 //
3086 // Free memory pool at last
3087 //
3088 if (Xhc->MemPool != NULL) {
3089 UsbHcFreeMemPool (Xhc->MemPool);
3090 Xhc->MemPool = NULL;
3091 }
3092}
UINT64 UINTN
EFI_STATUS IoMmuUnmap(IN VOID *Mapping)
Definition: DmaMem.c:132
EFI_STATUS IoMmuMap(IN EDKII_IOMMU_OPERATION Operation, IN VOID *HostAddress, IN OUT UINTN *NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: DmaMem.c:60
UINTN EFIAPI MicroSecondDelay(IN UINTN MicroSeconds)
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
INTN EFIAPI HighBitSet32(IN UINT32 Operand)
Definition: HighBitSet32.c:27
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS UsbHcFreeMemPool(IN USBHC_MEM_POOL *Pool)
Definition: UsbHcMem.c:385
VOID UsbHcFreeMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:493
VOID * UsbHcAllocateMem(IN USBHC_MEM_POOL *Pool, IN UINTN Size)
Definition: UsbHcMem.c:419
USBHC_MEM_POOL * UsbHcInitMemPool(IN EFI_PCI_IO_PROTOCOL *PciIo, IN BOOLEAN Check4G, IN UINT32 Which4G)
Definition: UsbHcMem.c:348
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define USB_PORT_STAT_C_CONNECTION
#define EFI_USB_SPEED_SUPER
4.8 Gb/s, USB 3.0 XHCI HC.
#define USB_PORT_STAT_CONNECTION
EFI_USB_DATA_DIRECTION
Definition: UsbIo.h:44
EFI_STATUS(EFIAPI * EFI_ASYNC_USB_TRANSFER_CALLBACK)(IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Status)
Definition: UsbIo.h:80
EDKII_IOMMU_OPERATION
Definition: IoMmu.h:44
@ EdkiiIoMmuOperationBusMasterWrite
Definition: IoMmu.h:54
@ EdkiiIoMmuOperationBusMasterRead
Definition: IoMmu.h:49
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_PHYSICAL_ADDRESS UsbHcGetPciAddrForHostAddr(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size, IN BOOLEAN Alignment)
Definition: UsbHcMem.c:235
EFI_STATUS UsbHcAllocateAlignedPages(IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINTN Pages, IN UINTN Alignment, OUT VOID **HostAddress, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: UsbHcMem.c:637
EFI_PHYSICAL_ADDRESS UsbHcGetHostAddrForPciAddr(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size, IN BOOLEAN Alignment)
Definition: UsbHcMem.c:290
VOID UsbHcFreeAlignedPages(IN EFI_PCI_IO_PROTOCOL *PciIo, IN VOID *HostAddress, IN UINTN Pages, VOID *Mapping)
Definition: UsbHcMem.c:758
BOOLEAN XhcPeiIsHalt(IN PEI_XHC_DEV *Xhc)
Definition: XhcPeim.c:325
VOID XhcPeiClearRuntimeRegBit(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset, IN UINT32 Bit)
Definition: XhcPeim.c:302
UINT32 XhcPeiReadOpReg(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset)
Definition: XhcPeim.c:72
BOOLEAN XhcPeiIsSysError(IN PEI_XHC_DEV *Xhc)
Definition: XhcPeim.c:342
VOID XhcPeiWriteOpReg(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset, IN UINT32 Data)
Definition: XhcPeim.c:94
VOID XhcPeiSetRuntimeRegBit(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset, IN UINT32 Bit)
Definition: XhcPeim.c:280
UINT32 XhcPeiReadRuntimeReg(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset)
Definition: XhcPeim.c:237
VOID XhcPeiClearOpRegBit(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset, IN UINT32 Bit)
Definition: XhcPeim.c:136
VOID XhcPeiWriteDoorBellReg(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset, IN UINT32 Data)
Definition: XhcPeim.c:216
VOID XhcPeiWriteRuntimeReg(IN PEI_XHC_DEV *Xhc, IN UINT32 Offset, IN UINT32 Data)
Definition: XhcPeim.c:260
EFI_STATUS XhcPeiDisableSlotCmd64(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId)
Definition: XhciSched.c:1604
UINT8 XhcPeiRouteStringToSlotId(IN PEI_XHC_DEV *Xhc, IN USB_DEV_ROUTE RouteString)
Definition: XhciSched.c:1012
VOID XhcPeiInitSched(IN PEI_XHC_DEV *Xhc)
Definition: XhciSched.c:2882
EFI_STATUS XhcPeiEvaluateContext(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT32 MaxPacketSize)
Definition: XhciSched.c:2167
EFI_STATUS XhcPeiSetConfigCmd(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, IN USB_CONFIG_DESCRIPTOR *ConfigDesc)
Definition: XhciSched.c:1713
EFI_STATUS XhcPeiSetConfigCmd64(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, IN USB_CONFIG_DESCRIPTOR *ConfigDesc)
Definition: XhciSched.c:1939
EFI_STATUS XhcPeiCheckNewEvent(IN PEI_XHC_DEV *Xhc, IN EVENT_RING *EvtRing, OUT TRB_TEMPLATE **NewEvtTrb)
Definition: XhciSched.c:2561
EFI_STATUS XhcPeiRecoverHaltedEndpoint(IN PEI_XHC_DEV *Xhc, IN URB *Urb)
Definition: XhciSched.c:472
VOID XhcPeiRingDoorBell(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 Dci)
Definition: XhciSched.c:1044
VOID XhcPeiFreeSched(IN PEI_XHC_DEV *Xhc)
Definition: XhciSched.c:3049
EFI_STATUS XhcPeiConfigHubContext(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 PortNum, IN UINT8 TTT, IN UINT8 MTT)
Definition: XhciSched.c:2279
EFI_STATUS XhcPeiEvaluateContext64(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT32 MaxPacketSize)
Definition: XhciSched.c:2222
EFI_STATUS XhcPeiSyncTrsRing(IN PEI_XHC_DEV *Xhc, IN TRANSFER_RING *TrsRing)
Definition: XhciSched.c:2772
EFI_STATUS XhcPeiDisableSlotCmd(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId)
Definition: XhciSched.c:1497
VOID XhcPeiFreeUrb(IN PEI_XHC_DEV *Xhc, IN URB *Urb)
Definition: XhciSched.c:188
URB * XhcPeiCreateCmdTrb(IN PEI_XHC_DEV *Xhc, IN TRB_TEMPLATE *CmdTrb)
Definition: XhciSched.c:24
EFI_STATUS XhcPeiInitializeDeviceSlot64(IN PEI_XHC_DEV *Xhc, IN USB_DEV_ROUTE ParentRouteChart, IN UINT16 ParentPort, IN USB_DEV_ROUTE RouteChart, IN UINT8 DeviceSpeed)
Definition: XhciSched.c:1286
EFI_STATUS XhcPeiConfigHubContext64(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 PortNum, IN UINT8 TTT, IN UINT8 MTT)
Definition: XhciSched.c:2348
EFI_STATUS EFIAPI XhcPeiResetEndpoint(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 Dci)
Definition: XhciSched.c:2463
EFI_STATUS EFIAPI XhcPeiStopEndpoint(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 Dci)
Definition: XhciSched.c:2417
UINT8 XhcPeiBusDevAddrToSlotId(IN PEI_XHC_DEV *Xhc, IN UINT8 BusDevAddr)
Definition: XhciSched.c:979
EFI_STATUS XhcPeiCreateTransferTrb(IN PEI_XHC_DEV *Xhc, IN URB *Urb)
Definition: XhciSched.c:212
VOID XhcPeiFreeEventRing(IN PEI_XHC_DEV *Xhc, IN EVENT_RING *EventRing)
Definition: XhciSched.c:2642
EFI_STATUS XhcPeiSyncEventRing(IN PEI_XHC_DEV *Xhc, IN EVENT_RING *EvtRing)
Definition: XhciSched.c:2596
BOOLEAN XhcPeiCheckUrbResult(IN PEI_XHC_DEV *Xhc, IN URB *Urb)
Definition: XhciSched.c:623
URB * XhcPeiCreateUrb(IN PEI_XHC_DEV *Xhc, IN UINT8 BusAddr, IN UINT8 EpAddr, IN UINT8 DevSpeed, IN UINTN MaxPacket, IN UINTN Type, IN EFI_USB_DEVICE_REQUEST *Request, IN VOID *Data, IN UINTN DataLen, IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, IN VOID *Context)
Definition: XhciSched.c:131
EFI_STATUS XhcPeiInitializeDeviceSlot(IN PEI_XHC_DEV *Xhc, IN USB_DEV_ROUTE ParentRouteChart, IN UINT16 ParentPort, IN USB_DEV_ROUTE RouteChart, IN UINT8 DeviceSpeed)
Definition: XhciSched.c:1071
EFI_STATUS XhcPeiExecTransfer(IN PEI_XHC_DEV *Xhc, IN BOOLEAN CmdTransfer, IN URB *Urb, IN UINTN Timeout)
Definition: XhciSched.c:797
EFI_STATUS XhcPeiCmdTransfer(IN PEI_XHC_DEV *Xhc, IN TRB_TEMPLATE *CmdTrb, IN UINTN Timeout, OUT TRB_TEMPLATE **EvtTrb)
Definition: XhciSched.c:65
VOID XhcPeiCreateTransferRing(IN PEI_XHC_DEV *Xhc, IN UINTN TrbNum, OUT TRANSFER_RING *TransferRing)
Definition: XhciSched.c:2835
EFI_STATUS XhcPeiDequeueTrbFromEndpoint(IN PEI_XHC_DEV *Xhc, IN URB *Urb)
Definition: XhciSched.c:532
VOID XhcPeiCreateEventRing(IN PEI_XHC_DEV *Xhc, OUT EVENT_RING *EventRing)
Definition: XhciSched.c:2670
UINT8 XhcPeiEndpointToDci(IN UINT8 EpAddr, IN EFI_USB_DATA_DIRECTION Direction)
Definition: XhciSched.c:948
EFI_STATUS XhcPeiPollPortStatusChange(IN PEI_XHC_DEV *Xhc, IN USB_DEV_ROUTE ParentRouteChart, IN UINT8 Port, IN EFI_USB_PORT_STATUS *PortState)
Definition: XhciSched.c:863
EFI_STATUS EFIAPI XhcPeiSetTrDequeuePointer(IN PEI_XHC_DEV *Xhc, IN UINT8 SlotId, IN UINT8 Dci, IN URB *Urb)
Definition: XhciSched.c:2511
BOOLEAN XhcPeiIsTransferRingTrb(IN TRB_TEMPLATE *Trb, IN URB *Urb)
Definition: XhciSched.c:589
Definition: EhciUrb.h:200