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