]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
dea5b1af1884b8426b3bc888c44dd4d790205cf1
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
1 /** @file
2
3 XHCI transfer scheduling routines.
4
5 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Xhci.h"
17
18 /**
19 Create a command transfer TRB to support XHCI command interfaces.
20
21 @param Xhc The XHCI Instance.
22 @param CmdTrb The cmd TRB to be executed.
23
24 @return Created URB or NULL.
25
26 **/
27 URB*
28 XhcCreateCmdTrb (
29 IN USB_XHCI_INSTANCE *Xhc,
30 IN TRB_TEMPLATE *CmdTrb
31 )
32 {
33 URB *Urb;
34
35 Urb = AllocateZeroPool (sizeof (URB));
36 if (Urb == NULL) {
37 return NULL;
38 }
39
40 Urb->Signature = XHC_URB_SIG;
41
42 Urb->Ring = &Xhc->CmdRing;
43 XhcSyncTrsRing (Xhc, Urb->Ring);
44 Urb->TrbNum = 1;
45 Urb->TrbStart = Urb->Ring->RingEnqueue;
46 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
47 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
48 Urb->TrbEnd = Urb->TrbStart;
49
50 return Urb;
51 }
52
53 /**
54 Execute a XHCI cmd TRB pointed by CmdTrb.
55
56 @param Xhc The XHCI Instance.
57 @param CmdTrb The cmd TRB to be executed.
58 @param Timeout Indicates the maximum time, in millisecond, which the
59 transfer is allowed to complete.
60 @param EvtTrb The event TRB corresponding to the cmd TRB.
61
62 @retval EFI_SUCCESS The transfer was completed successfully.
63 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
64 @retval EFI_TIMEOUT The transfer failed due to timeout.
65 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
66
67 **/
68 EFI_STATUS
69 EFIAPI
70 XhcCmdTransfer (
71 IN USB_XHCI_INSTANCE *Xhc,
72 IN TRB_TEMPLATE *CmdTrb,
73 IN UINTN Timeout,
74 OUT TRB_TEMPLATE **EvtTrb
75 )
76 {
77 EFI_STATUS Status;
78 URB *Urb;
79
80 //
81 // Validate the parameters
82 //
83 if ((Xhc == NULL) || (CmdTrb == NULL)) {
84 return EFI_INVALID_PARAMETER;
85 }
86
87 Status = EFI_DEVICE_ERROR;
88
89 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
90 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));
91 goto ON_EXIT;
92 }
93
94 //
95 // Create a new URB, then poll the execution status.
96 //
97 Urb = XhcCreateCmdTrb (Xhc, CmdTrb);
98
99 if (Urb == NULL) {
100 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));
101 Status = EFI_OUT_OF_RESOURCES;
102 goto ON_EXIT;
103 }
104
105 Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);
106 *EvtTrb = Urb->EvtTrb;
107
108 if (Urb->Result == EFI_USB_NOERROR) {
109 Status = EFI_SUCCESS;
110 }
111
112 XhcFreeUrb (Xhc, Urb);
113
114 ON_EXIT:
115 return Status;
116 }
117
118 /**
119 Create a new URB for a new transaction.
120
121 @param Xhc The XHCI Instance
122 @param BusAddr The logical device address assigned by UsbBus driver
123 @param EpAddr Endpoint addrress
124 @param DevSpeed The device speed
125 @param MaxPacket The max packet length of the endpoint
126 @param Type The transaction type
127 @param Request The standard USB request for control transfer
128 @param Data The user data to transfer
129 @param DataLen The length of data buffer
130 @param Callback The function to call when data is transferred
131 @param Context The context to the callback
132
133 @return Created URB or NULL
134
135 **/
136 URB*
137 XhcCreateUrb (
138 IN USB_XHCI_INSTANCE *Xhc,
139 IN UINT8 BusAddr,
140 IN UINT8 EpAddr,
141 IN UINT8 DevSpeed,
142 IN UINTN MaxPacket,
143 IN UINTN Type,
144 IN EFI_USB_DEVICE_REQUEST *Request,
145 IN VOID *Data,
146 IN UINTN DataLen,
147 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
148 IN VOID *Context
149 )
150 {
151 USB_ENDPOINT *Ep;
152 EFI_STATUS Status;
153 URB *Urb;
154
155 Urb = AllocateZeroPool (sizeof (URB));
156 if (Urb == NULL) {
157 return NULL;
158 }
159
160 Urb->Signature = XHC_URB_SIG;
161 InitializeListHead (&Urb->UrbList);
162
163 Ep = &Urb->Ep;
164 Ep->BusAddr = BusAddr;
165 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);
166 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
167 Ep->DevSpeed = DevSpeed;
168 Ep->MaxPacket = MaxPacket;
169 Ep->Type = Type;
170
171 Urb->Request = Request;
172 Urb->Data = Data;
173 Urb->DataLen = DataLen;
174 Urb->Callback = Callback;
175 Urb->Context = Context;
176
177 Status = XhcCreateTransferTrb (Xhc, Urb);
178 ASSERT_EFI_ERROR (Status);
179 if (EFI_ERROR (Status)) {
180 DEBUG ((EFI_D_ERROR, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status));
181 FreePool (Urb);
182 Urb = NULL;
183 }
184
185 return Urb;
186 }
187
188 /**
189 Free an allocated URB.
190
191 @param Xhc The XHCI device.
192 @param Urb The URB to free.
193
194 **/
195 VOID
196 XhcFreeUrb (
197 IN USB_XHCI_INSTANCE *Xhc,
198 IN URB *Urb
199 )
200 {
201 if ((Xhc == NULL) || (Urb == NULL)) {
202 return;
203 }
204
205 if (Urb->DataMap != NULL) {
206 Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);
207 }
208
209 FreePool (Urb);
210 }
211
212 /**
213 Create a transfer TRB.
214
215 @param Xhc The XHCI Instance
216 @param Urb The urb used to construct the transfer TRB.
217
218 @return Created TRB or NULL
219
220 **/
221 EFI_STATUS
222 XhcCreateTransferTrb (
223 IN USB_XHCI_INSTANCE *Xhc,
224 IN URB *Urb
225 )
226 {
227 VOID *OutputContext;
228 TRANSFER_RING *EPRing;
229 UINT8 EPType;
230 UINT8 SlotId;
231 UINT8 Dci;
232 TRB *TrbStart;
233 UINTN TotalLen;
234 UINTN Len;
235 UINTN TrbNum;
236 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
237 EFI_PHYSICAL_ADDRESS PhyAddr;
238 VOID *Map;
239 EFI_STATUS Status;
240
241 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
242 if (SlotId == 0) {
243 return EFI_DEVICE_ERROR;
244 }
245
246 Urb->Finished = FALSE;
247 Urb->StartDone = FALSE;
248 Urb->EndDone = FALSE;
249 Urb->Completed = 0;
250 Urb->Result = EFI_USB_NOERROR;
251
252 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
253 ASSERT (Dci < 32);
254 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
255 Urb->Ring = EPRing;
256 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
257 if (Xhc->HcCParams.Data.Csz == 0) {
258 EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
259 } else {
260 EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
261 }
262
263 if (Urb->Data != NULL) {
264 if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {
265 MapOp = EfiPciIoOperationBusMasterWrite;
266 } else {
267 MapOp = EfiPciIoOperationBusMasterRead;
268 }
269
270 Len = Urb->DataLen;
271 Status = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
272
273 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
274 DEBUG ((EFI_D_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
275 return EFI_OUT_OF_RESOURCES;
276 }
277
278 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
279 Urb->DataMap = Map;
280 }
281
282 //
283 // Construct the TRB
284 //
285 XhcSyncTrsRing (Xhc, EPRing);
286 Urb->TrbStart = EPRing->RingEnqueue;
287 switch (EPType) {
288 case ED_CONTROL_BIDIR:
289 //
290 // For control transfer, create SETUP_STAGE_TRB first.
291 //
292 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
293 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
294 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;
295 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;
296 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;
297 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;
298 TrbStart->TrbCtrSetup.Lenth = 8;
299 TrbStart->TrbCtrSetup.IntTarget = 0;
300 TrbStart->TrbCtrSetup.IOC = 1;
301 TrbStart->TrbCtrSetup.IDT = 1;
302 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;
303 if (Urb->Ep.Direction == EfiUsbDataIn) {
304 TrbStart->TrbCtrSetup.TRT = 3;
305 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
306 TrbStart->TrbCtrSetup.TRT = 2;
307 } else {
308 TrbStart->TrbCtrSetup.TRT = 0;
309 }
310 //
311 // Update the cycle bit
312 //
313 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
314 Urb->TrbNum++;
315
316 //
317 // For control transfer, create DATA_STAGE_TRB.
318 //
319 if (Urb->DataLen > 0) {
320 XhcSyncTrsRing (Xhc, EPRing);
321 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
322 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->DataPhy);
323 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->DataPhy);
324 TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;
325 TrbStart->TrbCtrData.TDSize = 0;
326 TrbStart->TrbCtrData.IntTarget = 0;
327 TrbStart->TrbCtrData.ISP = 1;
328 TrbStart->TrbCtrData.IOC = 1;
329 TrbStart->TrbCtrData.IDT = 0;
330 TrbStart->TrbCtrData.CH = 0;
331 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;
332 if (Urb->Ep.Direction == EfiUsbDataIn) {
333 TrbStart->TrbCtrData.DIR = 1;
334 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
335 TrbStart->TrbCtrData.DIR = 0;
336 } else {
337 TrbStart->TrbCtrData.DIR = 0;
338 }
339 //
340 // Update the cycle bit
341 //
342 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
343 Urb->TrbNum++;
344 }
345 //
346 // For control transfer, create STATUS_STAGE_TRB.
347 // Get the pointer to next TRB for status stage use
348 //
349 XhcSyncTrsRing (Xhc, EPRing);
350 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
351 TrbStart->TrbCtrStatus.IntTarget = 0;
352 TrbStart->TrbCtrStatus.IOC = 1;
353 TrbStart->TrbCtrStatus.CH = 0;
354 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;
355 if (Urb->Ep.Direction == EfiUsbDataIn) {
356 TrbStart->TrbCtrStatus.DIR = 0;
357 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
358 TrbStart->TrbCtrStatus.DIR = 1;
359 } else {
360 TrbStart->TrbCtrStatus.DIR = 0;
361 }
362 //
363 // Update the cycle bit
364 //
365 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
366 //
367 // Update the enqueue pointer
368 //
369 XhcSyncTrsRing (Xhc, EPRing);
370 Urb->TrbNum++;
371 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
372
373 break;
374
375 case ED_BULK_OUT:
376 case ED_BULK_IN:
377 TotalLen = 0;
378 Len = 0;
379 TrbNum = 0;
380 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
381 while (TotalLen < Urb->DataLen) {
382 if ((TotalLen + 0x10000) >= Urb->DataLen) {
383 Len = Urb->DataLen - TotalLen;
384 } else {
385 Len = 0x10000;
386 }
387 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
388 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
389 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
390 TrbStart->TrbNormal.Lenth = (UINT32) Len;
391 TrbStart->TrbNormal.TDSize = 0;
392 TrbStart->TrbNormal.IntTarget = 0;
393 TrbStart->TrbNormal.ISP = 1;
394 TrbStart->TrbNormal.IOC = 1;
395 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
396 //
397 // Update the cycle bit
398 //
399 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
400
401 XhcSyncTrsRing (Xhc, EPRing);
402 TrbNum++;
403 TotalLen += Len;
404 }
405
406 Urb->TrbNum = TrbNum;
407 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
408 break;
409
410 case ED_INTERRUPT_OUT:
411 case ED_INTERRUPT_IN:
412 TotalLen = 0;
413 Len = 0;
414 TrbNum = 0;
415 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
416 while (TotalLen < Urb->DataLen) {
417 if ((TotalLen + 0x10000) >= Urb->DataLen) {
418 Len = Urb->DataLen - TotalLen;
419 } else {
420 Len = 0x10000;
421 }
422 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
423 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
424 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
425 TrbStart->TrbNormal.Lenth = (UINT32) Len;
426 TrbStart->TrbNormal.TDSize = 0;
427 TrbStart->TrbNormal.IntTarget = 0;
428 TrbStart->TrbNormal.ISP = 1;
429 TrbStart->TrbNormal.IOC = 1;
430 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
431 //
432 // Update the cycle bit
433 //
434 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
435
436 XhcSyncTrsRing (Xhc, EPRing);
437 TrbNum++;
438 TotalLen += Len;
439 }
440
441 Urb->TrbNum = TrbNum;
442 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
443 break;
444
445 default:
446 DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
447 ASSERT (FALSE);
448 break;
449 }
450
451 return EFI_SUCCESS;
452 }
453
454
455 /**
456 Initialize the XHCI host controller for schedule.
457
458 @param Xhc The XHCI Instance to be initialized.
459
460 **/
461 VOID
462 XhcInitSched (
463 IN USB_XHCI_INSTANCE *Xhc
464 )
465 {
466 VOID *Dcbaa;
467 EFI_PHYSICAL_ADDRESS DcbaaPhy;
468 UINT64 CmdRing;
469 EFI_PHYSICAL_ADDRESS CmdRingPhy;
470 UINTN Entries;
471 UINT32 MaxScratchpadBufs;
472 UINT64 *ScratchBuf;
473 EFI_PHYSICAL_ADDRESS ScratchPhy;
474 UINT64 *ScratchEntry;
475 EFI_PHYSICAL_ADDRESS ScratchEntryPhy;
476 UINT32 Index;
477 UINTN *ScratchEntryMap;
478 EFI_STATUS Status;
479
480 //
481 // Initialize memory management.
482 //
483 Xhc->MemPool = UsbHcInitMemPool (Xhc->PciIo);
484 ASSERT (Xhc->MemPool != NULL);
485
486 //
487 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
488 // to enable the device slots that system software is going to use.
489 //
490 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
491 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
492 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);
493
494 //
495 // The Device Context Base Address Array entry associated with each allocated Device Slot
496 // shall contain a 64-bit pointer to the base of the associated Device Context.
497 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
498 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
499 //
500 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);
501 Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries);
502 ASSERT (Dcbaa != NULL);
503 ZeroMem (Dcbaa, Entries);
504
505 //
506 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
507 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
508 // mode (Run/Stop(R/S) ='1').
509 //
510 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
511 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
512 ASSERT (MaxScratchpadBufs <= 1023);
513 if (MaxScratchpadBufs != 0) {
514 //
515 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
516 //
517 ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);
518 ASSERT (ScratchEntryMap != NULL);
519 Xhc->ScratchEntryMap = ScratchEntryMap;
520
521 //
522 // Allocate the buffer to record the host address for each entry
523 //
524 ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
525 ASSERT (ScratchEntry != NULL);
526 Xhc->ScratchEntry = ScratchEntry;
527
528 Status = UsbHcAllocateAlignedPages (
529 Xhc->PciIo,
530 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
531 Xhc->PageSize,
532 (VOID **) &ScratchBuf,
533 &ScratchPhy,
534 &Xhc->ScratchMap
535 );
536 ASSERT_EFI_ERROR (Status);
537
538 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
539 Xhc->ScratchBuf = ScratchBuf;
540
541 //
542 // Allocate each scratch buffer
543 //
544 for (Index = 0; Index < MaxScratchpadBufs; Index++) {
545 Status = UsbHcAllocateAlignedPages (
546 Xhc->PciIo,
547 EFI_SIZE_TO_PAGES (Xhc->PageSize),
548 Xhc->PageSize,
549 (VOID **) &ScratchEntry[Index],
550 &ScratchEntryPhy,
551 (VOID **) &ScratchEntryMap[Index]
552 );
553 ASSERT_EFI_ERROR (Status);
554 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);
555 //
556 // Fill with the PCI device address
557 //
558 *ScratchBuf++ = ScratchEntryPhy;
559 }
560 //
561 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
562 // Device Context Base Address Array points to the Scratchpad Buffer Array.
563 //
564 *(UINT64 *)Dcbaa = (UINT64)(UINTN) ScratchPhy;
565 }
566
567 //
568 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
569 // a 64-bit address pointing to where the Device Context Base Address Array is located.
570 //
571 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;
572 //
573 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
574 // So divide it to two 32-bytes width register access.
575 //
576 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);
577 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(DcbaaPhy));
578 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
579
580 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));
581
582 //
583 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
584 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
585 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
586 // always be '0'.
587 //
588 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
589 //
590 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
591 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
592 // So we set RCS as inverted PCS init value to let Command Ring empty
593 //
594 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;
595 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN) CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
596 ASSERT ((CmdRingPhy & 0x3F) == 0);
597 CmdRingPhy |= XHC_CRCR_RCS;
598 //
599 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
600 // So divide it to two 32-bytes width register access.
601 //
602 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));
603 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
604
605 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
606
607 //
608 // Disable the 'interrupter enable' bit in USB_CMD
609 // and clear IE & IP bit in all Interrupter X Management Registers.
610 //
611 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
612 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
613 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
614 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
615 }
616
617 //
618 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
619 //
620 CreateEventRing (Xhc, &Xhc->EventRing);
621 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
622 }
623
624 /**
625 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
626 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
627 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
628 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
629 Stopped to the Running state.
630
631 @param Xhc The XHCI Instance.
632 @param Urb The urb which makes the endpoint halted.
633
634 @retval EFI_SUCCESS The recovery is successful.
635 @retval Others Failed to recovery halted endpoint.
636
637 **/
638 EFI_STATUS
639 EFIAPI
640 XhcRecoverHaltedEndpoint (
641 IN USB_XHCI_INSTANCE *Xhc,
642 IN URB *Urb
643 )
644 {
645 EFI_STATUS Status;
646 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
647 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
648 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
649 UINT8 Dci;
650 UINT8 SlotId;
651 EFI_PHYSICAL_ADDRESS PhyAddr;
652
653 Status = EFI_SUCCESS;
654 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
655 if (SlotId == 0) {
656 return EFI_DEVICE_ERROR;
657 }
658 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
659 ASSERT (Dci < 32);
660
661 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));
662
663 //
664 // 1) Send Reset endpoint command to transit from halt to stop state
665 //
666 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
667 CmdTrbResetED.CycleBit = 1;
668 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
669 CmdTrbResetED.EDID = Dci;
670 CmdTrbResetED.SlotId = SlotId;
671 Status = XhcCmdTransfer (
672 Xhc,
673 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
674 XHC_GENERIC_TIMEOUT,
675 (TRB_TEMPLATE **) (UINTN) &EvtTrb
676 );
677 if (EFI_ERROR(Status)) {
678 DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
679 goto Done;
680 }
681
682 //
683 // 2)Set dequeue pointer
684 //
685 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
686 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
687 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
688 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);
689 CmdSetTRDeq.CycleBit = 1;
690 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
691 CmdSetTRDeq.Endpoint = Dci;
692 CmdSetTRDeq.SlotId = SlotId;
693 Status = XhcCmdTransfer (
694 Xhc,
695 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
696 XHC_GENERIC_TIMEOUT,
697 (TRB_TEMPLATE **) (UINTN) &EvtTrb
698 );
699 if (EFI_ERROR(Status)) {
700 DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
701 goto Done;
702 }
703
704 //
705 // 3)Ring the doorbell to transit from stop to active
706 //
707 XhcRingDoorBell (Xhc, SlotId, Dci);
708
709 Done:
710 return Status;
711 }
712
713 /**
714 Create XHCI event ring.
715
716 @param Xhc The XHCI Instance.
717 @param EventRing The created event ring.
718
719 **/
720 VOID
721 CreateEventRing (
722 IN USB_XHCI_INSTANCE *Xhc,
723 OUT EVENT_RING *EventRing
724 )
725 {
726 VOID *Buf;
727 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
728 UINTN Size;
729 EFI_PHYSICAL_ADDRESS ERSTPhy;
730 EFI_PHYSICAL_ADDRESS DequeuePhy;
731
732 ASSERT (EventRing != NULL);
733
734 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
735 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
736 ASSERT (Buf != NULL);
737 ASSERT (((UINTN) Buf & 0x3F) == 0);
738 ZeroMem (Buf, Size);
739
740 EventRing->EventRingSeg0 = Buf;
741 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
742 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
743 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
744
745 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
746
747 //
748 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
749 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
750 //
751 EventRing->EventRingCCS = 1;
752
753 Size = EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
754 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
755 ASSERT (Buf != NULL);
756 ASSERT (((UINTN) Buf & 0x3F) == 0);
757 ZeroMem (Buf, Size);
758
759 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
760 EventRing->ERSTBase = ERSTBase;
761 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);
762 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);
763 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
764
765 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);
766
767 //
768 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
769 //
770 XhcWriteRuntimeReg (
771 Xhc,
772 XHC_ERSTSZ_OFFSET,
773 ERST_NUMBER
774 );
775 //
776 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
777 //
778 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
779 // So divide it to two 32-bytes width register access.
780 //
781 XhcWriteRuntimeReg (
782 Xhc,
783 XHC_ERDP_OFFSET,
784 XHC_LOW_32BIT((UINT64)(UINTN)DequeuePhy)
785 );
786 XhcWriteRuntimeReg (
787 Xhc,
788 XHC_ERDP_OFFSET + 4,
789 XHC_HIGH_32BIT((UINT64)(UINTN)DequeuePhy)
790 );
791 //
792 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
793 //
794 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
795 // So divide it to two 32-bytes width register access.
796 //
797 XhcWriteRuntimeReg (
798 Xhc,
799 XHC_ERSTBA_OFFSET,
800 XHC_LOW_32BIT((UINT64)(UINTN)ERSTPhy)
801 );
802 XhcWriteRuntimeReg (
803 Xhc,
804 XHC_ERSTBA_OFFSET + 4,
805 XHC_HIGH_32BIT((UINT64)(UINTN)ERSTPhy)
806 );
807 //
808 // Need set IMAN IE bit to enble the ring interrupt
809 //
810 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
811 }
812
813 /**
814 Create XHCI transfer ring.
815
816 @param Xhc The XHCI Instance.
817 @param TrbNum The number of TRB in the ring.
818 @param TransferRing The created transfer ring.
819
820 **/
821 VOID
822 CreateTransferRing (
823 IN USB_XHCI_INSTANCE *Xhc,
824 IN UINTN TrbNum,
825 OUT TRANSFER_RING *TransferRing
826 )
827 {
828 VOID *Buf;
829 LINK_TRB *EndTrb;
830 EFI_PHYSICAL_ADDRESS PhyAddr;
831
832 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
833 ASSERT (Buf != NULL);
834 ASSERT (((UINTN) Buf & 0x3F) == 0);
835 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
836
837 TransferRing->RingSeg0 = Buf;
838 TransferRing->TrbNumber = TrbNum;
839 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
840 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
841 TransferRing->RingPCS = 1;
842 //
843 // 4.9.2 Transfer Ring Management
844 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
845 // point to the first TRB in the ring.
846 //
847 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
848 EndTrb->Type = TRB_TYPE_LINK;
849 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
850 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
851 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
852 //
853 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
854 //
855 EndTrb->TC = 1;
856 //
857 // Set Cycle bit as other TRB PCS init value
858 //
859 EndTrb->CycleBit = 0;
860 }
861
862 /**
863 Free XHCI event ring.
864
865 @param Xhc The XHCI Instance.
866 @param EventRing The event ring to be freed.
867
868 **/
869 EFI_STATUS
870 EFIAPI
871 XhcFreeEventRing (
872 IN USB_XHCI_INSTANCE *Xhc,
873 IN EVENT_RING *EventRing
874 )
875 {
876 if(EventRing->EventRingSeg0 == NULL) {
877 return EFI_SUCCESS;
878 }
879
880 //
881 // Free EventRing Segment 0
882 //
883 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
884
885 //
886 // Free ESRT table
887 //
888 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
889 return EFI_SUCCESS;
890 }
891
892 /**
893 Free the resouce allocated at initializing schedule.
894
895 @param Xhc The XHCI Instance.
896
897 **/
898 VOID
899 XhcFreeSched (
900 IN USB_XHCI_INSTANCE *Xhc
901 )
902 {
903 UINT32 Index;
904 UINT64 *ScratchEntry;
905
906 if (Xhc->ScratchBuf != NULL) {
907 ScratchEntry = Xhc->ScratchEntry;
908 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
909 //
910 // Free Scratchpad Buffers
911 //
912 UsbHcFreeAlignedPages (Xhc->PciIo, (VOID*)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);
913 }
914 //
915 // Free Scratchpad Buffer Array
916 //
917 UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);
918 FreePool (Xhc->ScratchEntryMap);
919 FreePool (Xhc->ScratchEntry);
920 }
921
922 if (Xhc->CmdRing.RingSeg0 != NULL) {
923 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
924 Xhc->CmdRing.RingSeg0 = NULL;
925 }
926
927 XhcFreeEventRing (Xhc,&Xhc->EventRing);
928
929 if (Xhc->DCBAA != NULL) {
930 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));
931 Xhc->DCBAA = NULL;
932 }
933
934 //
935 // Free memory pool at last
936 //
937 if (Xhc->MemPool != NULL) {
938 UsbHcFreeMemPool (Xhc->MemPool);
939 Xhc->MemPool = NULL;
940 }
941 }
942
943 /**
944 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
945
946 @param Xhc The XHCI Instance.
947 @param Trb The TRB to be checked.
948 @param Urb The pointer to the matched Urb.
949
950 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
951 @retval FALSE The Trb is not matched with any URBs in the async list.
952
953 **/
954 BOOLEAN
955 IsAsyncIntTrb (
956 IN USB_XHCI_INSTANCE *Xhc,
957 IN TRB_TEMPLATE *Trb,
958 OUT URB **Urb
959 )
960 {
961 LIST_ENTRY *Entry;
962 LIST_ENTRY *Next;
963 TRB_TEMPLATE *CheckedTrb;
964 URB *CheckedUrb;
965 UINTN Index;
966
967 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
968 CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
969 CheckedTrb = CheckedUrb->TrbStart;
970 for (Index = 0; Index < CheckedUrb->TrbNum; Index++) {
971 if (Trb == CheckedTrb) {
972 *Urb = CheckedUrb;
973 return TRUE;
974 }
975 CheckedTrb++;
976 if ((UINTN)CheckedTrb >= ((UINTN) CheckedUrb->Ring->RingSeg0 + sizeof (TRB_TEMPLATE) * CheckedUrb->Ring->TrbNumber)) {
977 CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;
978 }
979 }
980 }
981
982 return FALSE;
983 }
984
985 /**
986 Check if the Trb is a transaction of the URB.
987
988 @param Trb The TRB to be checked
989 @param Urb The transfer ring to be checked.
990
991 @retval TRUE It is a transaction of the URB.
992 @retval FALSE It is not any transaction of the URB.
993
994 **/
995 BOOLEAN
996 IsTransferRingTrb (
997 IN TRB_TEMPLATE *Trb,
998 IN URB *Urb
999 )
1000 {
1001 TRB_TEMPLATE *CheckedTrb;
1002 UINTN Index;
1003
1004 CheckedTrb = Urb->Ring->RingSeg0;
1005
1006 ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
1007
1008 for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
1009 if (Trb == CheckedTrb) {
1010 return TRUE;
1011 }
1012 CheckedTrb++;
1013 }
1014
1015 return FALSE;
1016 }
1017
1018 /**
1019 Check the URB's execution result and update the URB's
1020 result accordingly.
1021
1022 @param Xhc The XHCI Instance.
1023 @param Urb The URB to check result.
1024
1025 @return Whether the result of URB transfer is finialized.
1026
1027 **/
1028 EFI_STATUS
1029 XhcCheckUrbResult (
1030 IN USB_XHCI_INSTANCE *Xhc,
1031 IN URB *Urb
1032 )
1033 {
1034 EVT_TRB_TRANSFER *EvtTrb;
1035 TRB_TEMPLATE *TRBPtr;
1036 UINTN Index;
1037 UINT8 TRBType;
1038 EFI_STATUS Status;
1039 URB *AsyncUrb;
1040 URB *CheckedUrb;
1041 UINT64 XhcDequeue;
1042 UINT32 High;
1043 UINT32 Low;
1044 EFI_PHYSICAL_ADDRESS PhyAddr;
1045
1046 ASSERT ((Xhc != NULL) && (Urb != NULL));
1047
1048 Status = EFI_SUCCESS;
1049 AsyncUrb = NULL;
1050
1051 if (Urb->Finished) {
1052 goto EXIT;
1053 }
1054
1055 EvtTrb = NULL;
1056
1057 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1058 Urb->Result |= EFI_USB_ERR_SYSTEM;
1059 Status = EFI_DEVICE_ERROR;
1060 goto EXIT;
1061 }
1062
1063 //
1064 // Traverse the event ring to find out all new events from the previous check.
1065 //
1066 XhcSyncEventRing (Xhc, &Xhc->EventRing);
1067 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
1068 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
1069 if (Status == EFI_NOT_READY) {
1070 //
1071 // All new events are handled, return directly.
1072 //
1073 goto EXIT;
1074 }
1075
1076 //
1077 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1078 //
1079 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
1080 continue;
1081 }
1082
1083 //
1084 // Need convert pci device address to host address
1085 //
1086 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
1087 TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
1088
1089 //
1090 // Update the status of Urb according to the finished event regardless of whether
1091 // the urb is current checked one or in the XHCI's async transfer list.
1092 // This way is used to avoid that those completed async transfer events don't get
1093 // handled in time and are flushed by newer coming events.
1094 //
1095 if (IsTransferRingTrb (TRBPtr, Urb)) {
1096 CheckedUrb = Urb;
1097 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
1098 CheckedUrb = AsyncUrb;
1099 } else {
1100 continue;
1101 }
1102
1103 switch (EvtTrb->Completecode) {
1104 case TRB_COMPLETION_STALL_ERROR:
1105 CheckedUrb->Result |= EFI_USB_ERR_STALL;
1106 CheckedUrb->Finished = TRUE;
1107 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1108 break;
1109
1110 case TRB_COMPLETION_BABBLE_ERROR:
1111 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
1112 CheckedUrb->Finished = TRUE;
1113 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1114 break;
1115
1116 case TRB_COMPLETION_DATA_BUFFER_ERROR:
1117 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
1118 CheckedUrb->Finished = TRUE;
1119 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
1120 break;
1121
1122 case TRB_COMPLETION_USB_TRANSACTION_ERROR:
1123 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
1124 CheckedUrb->Finished = TRUE;
1125 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
1126 break;
1127
1128 case TRB_COMPLETION_SHORT_PACKET:
1129 case TRB_COMPLETION_SUCCESS:
1130 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
1131 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));
1132 }
1133
1134 TRBType = (UINT8) (TRBPtr->Type);
1135 if ((TRBType == TRB_TYPE_DATA_STAGE) ||
1136 (TRBType == TRB_TYPE_NORMAL) ||
1137 (TRBType == TRB_TYPE_ISOCH)) {
1138 CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Lenth);
1139 }
1140
1141 break;
1142
1143 default:
1144 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
1145 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
1146 CheckedUrb->Finished = TRUE;
1147 break;
1148 }
1149
1150 //
1151 // Only check first and end Trb event address
1152 //
1153 if (TRBPtr == CheckedUrb->TrbStart) {
1154 CheckedUrb->StartDone = TRUE;
1155 }
1156
1157 if (TRBPtr == CheckedUrb->TrbEnd) {
1158 CheckedUrb->EndDone = TRUE;
1159 }
1160
1161 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
1162 CheckedUrb->Finished = TRUE;
1163 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;
1164 }
1165 }
1166
1167 EXIT:
1168
1169 //
1170 // Advance event ring to last available entry
1171 //
1172 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1173 // So divide it to two 32-bytes width register access.
1174 //
1175 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
1176 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
1177 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
1178
1179 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
1180
1181 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
1182 //
1183 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1184 // So divide it to two 32-bytes width register access.
1185 //
1186 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
1187 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
1188 }
1189
1190 return Status;
1191 }
1192
1193
1194 /**
1195 Execute the transfer by polling the URB. This is a synchronous operation.
1196
1197 @param Xhc The XHCI Instance.
1198 @param CmdTransfer The executed URB is for cmd transfer or not.
1199 @param Urb The URB to execute.
1200 @param Timeout The time to wait before abort, in millisecond.
1201
1202 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1203 @return EFI_TIMEOUT The transfer failed due to time out.
1204 @return EFI_SUCCESS The transfer finished OK.
1205
1206 **/
1207 EFI_STATUS
1208 XhcExecTransfer (
1209 IN USB_XHCI_INSTANCE *Xhc,
1210 IN BOOLEAN CmdTransfer,
1211 IN URB *Urb,
1212 IN UINTN Timeout
1213 )
1214 {
1215 EFI_STATUS Status;
1216 UINTN Index;
1217 UINTN Loop;
1218 UINT8 SlotId;
1219 UINT8 Dci;
1220
1221 if (CmdTransfer) {
1222 SlotId = 0;
1223 Dci = 0;
1224 } else {
1225 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1226 if (SlotId == 0) {
1227 return EFI_DEVICE_ERROR;
1228 }
1229 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1230 ASSERT (Dci < 32);
1231 }
1232
1233 Status = EFI_SUCCESS;
1234 Loop = Timeout * XHC_1_MILLISECOND;
1235 if (Timeout == 0) {
1236 Loop = 0xFFFFFFFF;
1237 }
1238
1239 XhcRingDoorBell (Xhc, SlotId, Dci);
1240
1241 for (Index = 0; Index < Loop; Index++) {
1242 Status = XhcCheckUrbResult (Xhc, Urb);
1243 if (Urb->Finished) {
1244 break;
1245 }
1246 gBS->Stall (XHC_1_MICROSECOND);
1247 }
1248
1249 if (Index == Loop) {
1250 Urb->Result = EFI_USB_ERR_TIMEOUT;
1251 }
1252
1253 return Status;
1254 }
1255
1256 /**
1257 Delete a single asynchronous interrupt transfer for
1258 the device and endpoint.
1259
1260 @param Xhc The XHCI Instance.
1261 @param BusAddr The logical device address assigned by UsbBus driver.
1262 @param EpNum The endpoint of the target.
1263
1264 @retval EFI_SUCCESS An asynchronous transfer is removed.
1265 @retval EFI_NOT_FOUND No transfer for the device is found.
1266
1267 **/
1268 EFI_STATUS
1269 XhciDelAsyncIntTransfer (
1270 IN USB_XHCI_INSTANCE *Xhc,
1271 IN UINT8 BusAddr,
1272 IN UINT8 EpNum
1273 )
1274 {
1275 LIST_ENTRY *Entry;
1276 LIST_ENTRY *Next;
1277 URB *Urb;
1278 EFI_USB_DATA_DIRECTION Direction;
1279
1280 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
1281 EpNum &= 0x0F;
1282
1283 Urb = NULL;
1284
1285 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1286 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1287 if ((Urb->Ep.BusAddr == BusAddr) &&
1288 (Urb->Ep.EpAddr == EpNum) &&
1289 (Urb->Ep.Direction == Direction)) {
1290 RemoveEntryList (&Urb->UrbList);
1291 FreePool (Urb->Data);
1292 XhcFreeUrb (Xhc, Urb);
1293 return EFI_SUCCESS;
1294 }
1295 }
1296
1297 return EFI_NOT_FOUND;
1298 }
1299
1300 /**
1301 Remove all the asynchronous interrutp transfers.
1302
1303 @param Xhc The XHCI Instance.
1304
1305 **/
1306 VOID
1307 XhciDelAllAsyncIntTransfers (
1308 IN USB_XHCI_INSTANCE *Xhc
1309 )
1310 {
1311 LIST_ENTRY *Entry;
1312 LIST_ENTRY *Next;
1313 URB *Urb;
1314
1315 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1316 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1317 RemoveEntryList (&Urb->UrbList);
1318 FreePool (Urb->Data);
1319 XhcFreeUrb (Xhc, Urb);
1320 }
1321 }
1322
1323 /**
1324 Update the queue head for next round of asynchronous transfer
1325
1326 @param Xhc The XHCI Instance.
1327 @param Urb The URB to update
1328
1329 **/
1330 VOID
1331 XhcUpdateAsyncRequest (
1332 IN USB_XHCI_INSTANCE *Xhc,
1333 IN URB *Urb
1334 )
1335 {
1336 EFI_STATUS Status;
1337
1338 if (Urb->Result == EFI_USB_NOERROR) {
1339 Status = XhcCreateTransferTrb (Xhc, Urb);
1340 if (EFI_ERROR (Status)) {
1341 return;
1342 }
1343 Status = RingIntTransferDoorBell (Xhc, Urb);
1344 if (EFI_ERROR (Status)) {
1345 return;
1346 }
1347 }
1348 }
1349
1350 /**
1351 Flush data from PCI controller specific address to mapped system
1352 memory address.
1353
1354 @param Xhc The XHCI device.
1355 @param Urb The URB to unmap.
1356
1357 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1358 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1359
1360 **/
1361 EFI_STATUS
1362 XhcFlushAsyncIntMap (
1363 IN USB_XHCI_INSTANCE *Xhc,
1364 IN URB *Urb
1365 )
1366 {
1367 EFI_STATUS Status;
1368 EFI_PHYSICAL_ADDRESS PhyAddr;
1369 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
1370 EFI_PCI_IO_PROTOCOL *PciIo;
1371 UINTN Len;
1372 VOID *Map;
1373
1374 PciIo = Xhc->PciIo;
1375 Len = Urb->DataLen;
1376
1377 if (Urb->Ep.Direction == EfiUsbDataIn) {
1378 MapOp = EfiPciIoOperationBusMasterWrite;
1379 } else {
1380 MapOp = EfiPciIoOperationBusMasterRead;
1381 }
1382
1383 if (Urb->DataMap != NULL) {
1384 Status = PciIo->Unmap (PciIo, Urb->DataMap);
1385 if (EFI_ERROR (Status)) {
1386 goto ON_ERROR;
1387 }
1388 }
1389
1390 Urb->DataMap = NULL;
1391
1392 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
1393 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
1394 goto ON_ERROR;
1395 }
1396
1397 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
1398 Urb->DataMap = Map;
1399 return EFI_SUCCESS;
1400
1401 ON_ERROR:
1402 return EFI_DEVICE_ERROR;
1403 }
1404
1405 /**
1406 Interrupt transfer periodic check handler.
1407
1408 @param Event Interrupt event.
1409 @param Context Pointer to USB_XHCI_INSTANCE.
1410
1411 **/
1412 VOID
1413 EFIAPI
1414 XhcMonitorAsyncRequests (
1415 IN EFI_EVENT Event,
1416 IN VOID *Context
1417 )
1418 {
1419 USB_XHCI_INSTANCE *Xhc;
1420 LIST_ENTRY *Entry;
1421 LIST_ENTRY *Next;
1422 UINT8 *ProcBuf;
1423 URB *Urb;
1424 UINT8 SlotId;
1425 EFI_STATUS Status;
1426 EFI_TPL OldTpl;
1427
1428 OldTpl = gBS->RaiseTPL (XHC_TPL);
1429
1430 Xhc = (USB_XHCI_INSTANCE*) Context;
1431
1432 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1433 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1434
1435 //
1436 // Make sure that the device is available before every check.
1437 //
1438 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1439 if (SlotId == 0) {
1440 continue;
1441 }
1442
1443 //
1444 // Check the result of URB execution. If it is still
1445 // active, check the next one.
1446 //
1447 XhcCheckUrbResult (Xhc, Urb);
1448
1449 if (!Urb->Finished) {
1450 continue;
1451 }
1452
1453 //
1454 // Flush any PCI posted write transactions from a PCI host
1455 // bridge to system memory.
1456 //
1457 Status = XhcFlushAsyncIntMap (Xhc, Urb);
1458 if (EFI_ERROR (Status)) {
1459 DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1460 }
1461
1462 //
1463 // Allocate a buffer then copy the transferred data for user.
1464 // If failed to allocate the buffer, update the URB for next
1465 // round of transfer. Ignore the data of this round.
1466 //
1467 ProcBuf = NULL;
1468 if (Urb->Result == EFI_USB_NOERROR) {
1469 ASSERT (Urb->Completed <= Urb->DataLen);
1470
1471 ProcBuf = AllocateZeroPool (Urb->Completed);
1472
1473 if (ProcBuf == NULL) {
1474 XhcUpdateAsyncRequest (Xhc, Urb);
1475 continue;
1476 }
1477
1478 CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1479 }
1480
1481 //
1482 // Leave error recovery to its related device driver. A
1483 // common case of the error recovery is to re-submit the
1484 // interrupt transfer which is linked to the head of the
1485 // list. This function scans from head to tail. So the
1486 // re-submitted interrupt transfer's callback function
1487 // will not be called again in this round. Don't touch this
1488 // URB after the callback, it may have been removed by the
1489 // callback.
1490 //
1491 if (Urb->Callback != NULL) {
1492 //
1493 // Restore the old TPL, USB bus maybe connect device in
1494 // his callback. Some drivers may has a lower TPL restriction.
1495 //
1496 gBS->RestoreTPL (OldTpl);
1497 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1498 OldTpl = gBS->RaiseTPL (XHC_TPL);
1499 }
1500
1501 if (ProcBuf != NULL) {
1502 gBS->FreePool (ProcBuf);
1503 }
1504
1505 XhcUpdateAsyncRequest (Xhc, Urb);
1506 }
1507 gBS->RestoreTPL (OldTpl);
1508 }
1509
1510 /**
1511 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1512
1513 @param Xhc The XHCI Instance.
1514 @param ParentRouteChart The route string pointed to the parent device if it exists.
1515 @param Port The port to be polled.
1516 @param PortState The port state.
1517
1518 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1519 @retval Others Should not appear.
1520
1521 **/
1522 EFI_STATUS
1523 EFIAPI
1524 XhcPollPortStatusChange (
1525 IN USB_XHCI_INSTANCE *Xhc,
1526 IN USB_DEV_ROUTE ParentRouteChart,
1527 IN UINT8 Port,
1528 IN EFI_USB_PORT_STATUS *PortState
1529 )
1530 {
1531 EFI_STATUS Status;
1532 UINT8 Speed;
1533 UINT8 SlotId;
1534 USB_DEV_ROUTE RouteChart;
1535
1536 Status = EFI_SUCCESS;
1537
1538 if (ParentRouteChart.Dword == 0) {
1539 RouteChart.Route.RouteString = 0;
1540 RouteChart.Route.RootPortNum = Port + 1;
1541 RouteChart.Route.TierNum = 1;
1542 } else {
1543 if(Port < 14) {
1544 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
1545 } else {
1546 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
1547 }
1548 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
1549 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
1550 }
1551
1552 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
1553 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
1554 //
1555 // Has a device attached, Identify device speed after port is enabled.
1556 //
1557 Speed = EFI_USB_SPEED_FULL;
1558 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
1559 Speed = EFI_USB_SPEED_LOW;
1560 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
1561 Speed = EFI_USB_SPEED_HIGH;
1562 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
1563 Speed = EFI_USB_SPEED_SUPER;
1564 }
1565 //
1566 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1567 //
1568 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1569 if (SlotId == 0) {
1570 if (Xhc->HcCParams.Data.Csz == 0) {
1571 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1572 } else {
1573 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1574 }
1575 }
1576 } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {
1577 //
1578 // Device is detached. Disable the allocated device slot and release resource.
1579 //
1580 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1581 if (SlotId != 0) {
1582 if (Xhc->HcCParams.Data.Csz == 0) {
1583 Status = XhcDisableSlotCmd (Xhc, SlotId);
1584 } else {
1585 Status = XhcDisableSlotCmd64 (Xhc, SlotId);
1586 }
1587 }
1588 }
1589 return Status;
1590 }
1591
1592
1593 /**
1594 Calculate the device context index by endpoint address and direction.
1595
1596 @param EpAddr The target endpoint number.
1597 @param Direction The direction of the target endpoint.
1598
1599 @return The device context index of endpoint.
1600
1601 **/
1602 UINT8
1603 XhcEndpointToDci (
1604 IN UINT8 EpAddr,
1605 IN UINT8 Direction
1606 )
1607 {
1608 UINT8 Index;
1609
1610 if (EpAddr == 0) {
1611 return 1;
1612 } else {
1613 Index = (UINT8) (2 * EpAddr);
1614 if (Direction == EfiUsbDataIn) {
1615 Index += 1;
1616 }
1617 return Index;
1618 }
1619 }
1620
1621 /**
1622 Find out the actual device address according to the requested device address from UsbBus.
1623
1624 @param Xhc The XHCI Instance.
1625 @param BusDevAddr The requested device address by UsbBus upper driver.
1626
1627 @return The actual device address assigned to the device.
1628
1629 **/
1630 UINT8
1631 EFIAPI
1632 XhcBusDevAddrToSlotId (
1633 IN USB_XHCI_INSTANCE *Xhc,
1634 IN UINT8 BusDevAddr
1635 )
1636 {
1637 UINT8 Index;
1638
1639 for (Index = 0; Index < 255; Index++) {
1640 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1641 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1642 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
1643 break;
1644 }
1645 }
1646
1647 if (Index == 255) {
1648 return 0;
1649 }
1650
1651 return Xhc->UsbDevContext[Index + 1].SlotId;
1652 }
1653
1654 /**
1655 Find out the slot id according to the device's route string.
1656
1657 @param Xhc The XHCI Instance.
1658 @param RouteString The route string described the device location.
1659
1660 @return The slot id used by the device.
1661
1662 **/
1663 UINT8
1664 EFIAPI
1665 XhcRouteStringToSlotId (
1666 IN USB_XHCI_INSTANCE *Xhc,
1667 IN USB_DEV_ROUTE RouteString
1668 )
1669 {
1670 UINT8 Index;
1671
1672 for (Index = 0; Index < 255; Index++) {
1673 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1674 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1675 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
1676 break;
1677 }
1678 }
1679
1680 if (Index == 255) {
1681 return 0;
1682 }
1683
1684 return Xhc->UsbDevContext[Index + 1].SlotId;
1685 }
1686
1687 /**
1688 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1689
1690 @param Xhc The XHCI Instance.
1691 @param EvtRing The event ring to sync.
1692
1693 @retval EFI_SUCCESS The event ring is synchronized successfully.
1694
1695 **/
1696 EFI_STATUS
1697 EFIAPI
1698 XhcSyncEventRing (
1699 IN USB_XHCI_INSTANCE *Xhc,
1700 IN EVENT_RING *EvtRing
1701 )
1702 {
1703 UINTN Index;
1704 TRB_TEMPLATE *EvtTrb1;
1705
1706 ASSERT (EvtRing != NULL);
1707
1708 //
1709 // Calculate the EventRingEnqueue and EventRingCCS.
1710 // Note: only support single Segment
1711 //
1712 EvtTrb1 = EvtRing->EventRingDequeue;
1713
1714 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
1715 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
1716 break;
1717 }
1718
1719 EvtTrb1++;
1720
1721 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1722 EvtTrb1 = EvtRing->EventRingSeg0;
1723 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
1724 }
1725 }
1726
1727 if (Index < EvtRing->TrbNumber) {
1728 EvtRing->EventRingEnqueue = EvtTrb1;
1729 } else {
1730 ASSERT (FALSE);
1731 }
1732
1733 return EFI_SUCCESS;
1734 }
1735
1736 /**
1737 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1738
1739 @param Xhc The XHCI Instance.
1740 @param TrsRing The transfer ring to sync.
1741
1742 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1743
1744 **/
1745 EFI_STATUS
1746 EFIAPI
1747 XhcSyncTrsRing (
1748 IN USB_XHCI_INSTANCE *Xhc,
1749 IN TRANSFER_RING *TrsRing
1750 )
1751 {
1752 UINTN Index;
1753 TRB_TEMPLATE *TrsTrb;
1754
1755 ASSERT (TrsRing != NULL);
1756 //
1757 // Calculate the latest RingEnqueue and RingPCS
1758 //
1759 TrsTrb = TrsRing->RingEnqueue;
1760 ASSERT (TrsTrb != NULL);
1761
1762 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
1763 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
1764 break;
1765 }
1766 TrsTrb++;
1767 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
1768 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
1769 //
1770 // set cycle bit in Link TRB as normal
1771 //
1772 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
1773 //
1774 // Toggle PCS maintained by software
1775 //
1776 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
1777 TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address
1778 }
1779 }
1780
1781 ASSERT (Index != TrsRing->TrbNumber);
1782
1783 if (TrsTrb != TrsRing->RingEnqueue) {
1784 TrsRing->RingEnqueue = TrsTrb;
1785 }
1786
1787 //
1788 // Clear the Trb context for enqueue, but reserve the PCS bit
1789 //
1790 TrsTrb->Parameter1 = 0;
1791 TrsTrb->Parameter2 = 0;
1792 TrsTrb->Status = 0;
1793 TrsTrb->RsvdZ1 = 0;
1794 TrsTrb->Type = 0;
1795 TrsTrb->Control = 0;
1796
1797 return EFI_SUCCESS;
1798 }
1799
1800 /**
1801 Check if there is a new generated event.
1802
1803 @param Xhc The XHCI Instance.
1804 @param EvtRing The event ring to check.
1805 @param NewEvtTrb The new event TRB found.
1806
1807 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1808 @retval EFI_NOT_READY The event ring has no new event.
1809
1810 **/
1811 EFI_STATUS
1812 EFIAPI
1813 XhcCheckNewEvent (
1814 IN USB_XHCI_INSTANCE *Xhc,
1815 IN EVENT_RING *EvtRing,
1816 OUT TRB_TEMPLATE **NewEvtTrb
1817 )
1818 {
1819 ASSERT (EvtRing != NULL);
1820
1821 *NewEvtTrb = EvtRing->EventRingDequeue;
1822
1823 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
1824 return EFI_NOT_READY;
1825 }
1826
1827 EvtRing->EventRingDequeue++;
1828 //
1829 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1830 //
1831 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1832 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
1833 }
1834
1835 return EFI_SUCCESS;
1836 }
1837
1838 /**
1839 Ring the door bell to notify XHCI there is a transaction to be executed.
1840
1841 @param Xhc The XHCI Instance.
1842 @param SlotId The slot id of the target device.
1843 @param Dci The device context index of the target slot or endpoint.
1844
1845 @retval EFI_SUCCESS Successfully ring the door bell.
1846
1847 **/
1848 EFI_STATUS
1849 EFIAPI
1850 XhcRingDoorBell (
1851 IN USB_XHCI_INSTANCE *Xhc,
1852 IN UINT8 SlotId,
1853 IN UINT8 Dci
1854 )
1855 {
1856 if (SlotId == 0) {
1857 XhcWriteDoorBellReg (Xhc, 0, 0);
1858 } else {
1859 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1860 }
1861
1862 return EFI_SUCCESS;
1863 }
1864
1865 /**
1866 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1867
1868 @param Xhc The XHCI Instance.
1869 @param Urb The URB to be rung.
1870
1871 @retval EFI_SUCCESS Successfully ring the door bell.
1872
1873 **/
1874 EFI_STATUS
1875 RingIntTransferDoorBell (
1876 IN USB_XHCI_INSTANCE *Xhc,
1877 IN URB *Urb
1878 )
1879 {
1880 UINT8 SlotId;
1881 UINT8 Dci;
1882
1883 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1884 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1885 XhcRingDoorBell (Xhc, SlotId, Dci);
1886 return EFI_SUCCESS;
1887 }
1888
1889 /**
1890 Assign and initialize the device slot for a new device.
1891
1892 @param Xhc The XHCI Instance.
1893 @param ParentRouteChart The route string pointed to the parent device.
1894 @param ParentPort The port at which the device is located.
1895 @param RouteChart The route string pointed to the device.
1896 @param DeviceSpeed The device speed.
1897
1898 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1899
1900 **/
1901 EFI_STATUS
1902 EFIAPI
1903 XhcInitializeDeviceSlot (
1904 IN USB_XHCI_INSTANCE *Xhc,
1905 IN USB_DEV_ROUTE ParentRouteChart,
1906 IN UINT16 ParentPort,
1907 IN USB_DEV_ROUTE RouteChart,
1908 IN UINT8 DeviceSpeed
1909 )
1910 {
1911 EFI_STATUS Status;
1912 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1913 INPUT_CONTEXT *InputContext;
1914 DEVICE_CONTEXT *OutputContext;
1915 TRANSFER_RING *EndpointTransferRing;
1916 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1917 UINT8 DeviceAddress;
1918 CMD_TRB_ENABLE_SLOT CmdTrb;
1919 UINT8 SlotId;
1920 UINT8 ParentSlotId;
1921 DEVICE_CONTEXT *ParentDeviceContext;
1922 EFI_PHYSICAL_ADDRESS PhyAddr;
1923
1924 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1925 CmdTrb.CycleBit = 1;
1926 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1927
1928 Status = XhcCmdTransfer (
1929 Xhc,
1930 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1931 XHC_GENERIC_TIMEOUT,
1932 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1933 );
1934 if (EFI_ERROR (Status)) {
1935 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
1936 return Status;
1937 }
1938 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1939 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1940 SlotId = (UINT8)EvtTrb->SlotId;
1941 ASSERT (SlotId != 0);
1942
1943 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1944 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1945 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1946 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1947 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1948
1949 //
1950 // 4.3.3 Device Slot Initialization
1951 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1952 //
1953 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
1954 ASSERT (InputContext != NULL);
1955 ASSERT (((UINTN) InputContext & 0x3F) == 0);
1956 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1957
1958 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1959
1960 //
1961 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1962 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1963 // Context are affected by the command.
1964 //
1965 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1966
1967 //
1968 // 3) Initialize the Input Slot Context data structure
1969 //
1970 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1971 InputContext->Slot.Speed = DeviceSpeed + 1;
1972 InputContext->Slot.ContextEntries = 1;
1973 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1974
1975 if (RouteChart.Route.RouteString) {
1976 //
1977 // The device is behind of hub device.
1978 //
1979 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
1980 ASSERT (ParentSlotId != 0);
1981 //
1982 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1983 //
1984 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1985 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1986 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1987 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1988 //
1989 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1990 // environment from Full/Low speed signaling environment for a device
1991 //
1992 InputContext->Slot.TTPortNum = ParentPort;
1993 InputContext->Slot.TTHubSlotId = ParentSlotId;
1994 }
1995 } else {
1996 //
1997 // Inherit the TT parameters from parent device.
1998 //
1999 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
2000 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2001 //
2002 // If the device is a High speed device then down the speed to be the same as its parent Hub
2003 //
2004 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2005 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2006 }
2007 }
2008 }
2009
2010 //
2011 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2012 //
2013 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2014 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2015 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2016 //
2017 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2018 //
2019 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2020
2021 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2022 InputContext->EP[0].MaxPacketSize = 512;
2023 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2024 InputContext->EP[0].MaxPacketSize = 64;
2025 } else {
2026 InputContext->EP[0].MaxPacketSize = 8;
2027 }
2028 //
2029 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2030 // 1KB, and Bulk and Isoch endpoints 3KB.
2031 //
2032 InputContext->EP[0].AverageTRBLength = 8;
2033 InputContext->EP[0].MaxBurstSize = 0;
2034 InputContext->EP[0].Interval = 0;
2035 InputContext->EP[0].MaxPStreams = 0;
2036 InputContext->EP[0].Mult = 0;
2037 InputContext->EP[0].CErr = 3;
2038
2039 //
2040 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2041 //
2042 PhyAddr = UsbHcGetPciAddrForHostAddr (
2043 Xhc->MemPool,
2044 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2045 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2046 );
2047 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2048 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2049
2050 //
2051 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2052 //
2053 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
2054 ASSERT (OutputContext != NULL);
2055 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2056 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
2057
2058 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2059 //
2060 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2061 // a pointer to the Output Device Context data structure (6.2.1).
2062 //
2063 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
2064 //
2065 // Fill DCBAA with PCI device address
2066 //
2067 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2068
2069 //
2070 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2071 // Context data structure described above.
2072 //
2073 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2074 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2075 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
2076 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2077 CmdTrbAddr.CycleBit = 1;
2078 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2079 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2080 Status = XhcCmdTransfer (
2081 Xhc,
2082 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2083 XHC_GENERIC_TIMEOUT,
2084 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2085 );
2086 if (!EFI_ERROR (Status)) {
2087 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
2088 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2089 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2090 }
2091
2092 return Status;
2093 }
2094
2095 /**
2096 Assign and initialize the device slot for a new device.
2097
2098 @param Xhc The XHCI Instance.
2099 @param ParentRouteChart The route string pointed to the parent device.
2100 @param ParentPort The port at which the device is located.
2101 @param RouteChart The route string pointed to the device.
2102 @param DeviceSpeed The device speed.
2103
2104 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2105
2106 **/
2107 EFI_STATUS
2108 EFIAPI
2109 XhcInitializeDeviceSlot64 (
2110 IN USB_XHCI_INSTANCE *Xhc,
2111 IN USB_DEV_ROUTE ParentRouteChart,
2112 IN UINT16 ParentPort,
2113 IN USB_DEV_ROUTE RouteChart,
2114 IN UINT8 DeviceSpeed
2115 )
2116 {
2117 EFI_STATUS Status;
2118 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2119 INPUT_CONTEXT_64 *InputContext;
2120 DEVICE_CONTEXT_64 *OutputContext;
2121 TRANSFER_RING *EndpointTransferRing;
2122 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
2123 UINT8 DeviceAddress;
2124 CMD_TRB_ENABLE_SLOT CmdTrb;
2125 UINT8 SlotId;
2126 UINT8 ParentSlotId;
2127 DEVICE_CONTEXT_64 *ParentDeviceContext;
2128 EFI_PHYSICAL_ADDRESS PhyAddr;
2129
2130 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
2131 CmdTrb.CycleBit = 1;
2132 CmdTrb.Type = TRB_TYPE_EN_SLOT;
2133
2134 Status = XhcCmdTransfer (
2135 Xhc,
2136 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
2137 XHC_GENERIC_TIMEOUT,
2138 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2139 );
2140 if (EFI_ERROR (Status)) {
2141 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
2142 return Status;
2143 }
2144 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
2145 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
2146 SlotId = (UINT8)EvtTrb->SlotId;
2147 ASSERT (SlotId != 0);
2148
2149 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
2150 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
2151 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
2152 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
2153 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
2154
2155 //
2156 // 4.3.3 Device Slot Initialization
2157 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2158 //
2159 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
2160 ASSERT (InputContext != NULL);
2161 ASSERT (((UINTN) InputContext & 0x3F) == 0);
2162 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2163
2164 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
2165
2166 //
2167 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2168 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2169 // Context are affected by the command.
2170 //
2171 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
2172
2173 //
2174 // 3) Initialize the Input Slot Context data structure
2175 //
2176 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
2177 InputContext->Slot.Speed = DeviceSpeed + 1;
2178 InputContext->Slot.ContextEntries = 1;
2179 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
2180
2181 if (RouteChart.Route.RouteString) {
2182 //
2183 // The device is behind of hub device.
2184 //
2185 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
2186 ASSERT (ParentSlotId != 0);
2187 //
2188 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2189 //
2190 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
2191 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
2192 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
2193 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
2194 //
2195 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2196 // environment from Full/Low speed signaling environment for a device
2197 //
2198 InputContext->Slot.TTPortNum = ParentPort;
2199 InputContext->Slot.TTHubSlotId = ParentSlotId;
2200 }
2201 } else {
2202 //
2203 // Inherit the TT parameters from parent device.
2204 //
2205 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
2206 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2207 //
2208 // If the device is a High speed device then down the speed to be the same as its parent Hub
2209 //
2210 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2211 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2212 }
2213 }
2214 }
2215
2216 //
2217 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2218 //
2219 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2220 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2221 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2222 //
2223 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2224 //
2225 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2226
2227 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2228 InputContext->EP[0].MaxPacketSize = 512;
2229 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2230 InputContext->EP[0].MaxPacketSize = 64;
2231 } else {
2232 InputContext->EP[0].MaxPacketSize = 8;
2233 }
2234 //
2235 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2236 // 1KB, and Bulk and Isoch endpoints 3KB.
2237 //
2238 InputContext->EP[0].AverageTRBLength = 8;
2239 InputContext->EP[0].MaxBurstSize = 0;
2240 InputContext->EP[0].Interval = 0;
2241 InputContext->EP[0].MaxPStreams = 0;
2242 InputContext->EP[0].Mult = 0;
2243 InputContext->EP[0].CErr = 3;
2244
2245 //
2246 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2247 //
2248 PhyAddr = UsbHcGetPciAddrForHostAddr (
2249 Xhc->MemPool,
2250 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
2251 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2252 );
2253 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
2254 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2255
2256 //
2257 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2258 //
2259 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
2260 ASSERT (OutputContext != NULL);
2261 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2262 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2263
2264 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2265 //
2266 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2267 // a pointer to the Output Device Context data structure (6.2.1).
2268 //
2269 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
2270 //
2271 // Fill DCBAA with PCI device address
2272 //
2273 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
2274
2275 //
2276 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2277 // Context data structure described above.
2278 //
2279 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2280 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2281 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
2282 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2283 CmdTrbAddr.CycleBit = 1;
2284 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2285 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2286 Status = XhcCmdTransfer (
2287 Xhc,
2288 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2289 XHC_GENERIC_TIMEOUT,
2290 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2291 );
2292 if (!EFI_ERROR (Status)) {
2293 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2294 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2295 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2296 }
2297 return Status;
2298 }
2299
2300
2301 /**
2302 Disable the specified device slot.
2303
2304 @param Xhc The XHCI Instance.
2305 @param SlotId The slot id to be disabled.
2306
2307 @retval EFI_SUCCESS Successfully disable the device slot.
2308
2309 **/
2310 EFI_STATUS
2311 EFIAPI
2312 XhcDisableSlotCmd (
2313 IN USB_XHCI_INSTANCE *Xhc,
2314 IN UINT8 SlotId
2315 )
2316 {
2317 EFI_STATUS Status;
2318 TRB_TEMPLATE *EvtTrb;
2319 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2320 UINT8 Index;
2321 VOID *RingSeg;
2322
2323 //
2324 // Disable the device slots occupied by these devices on its downstream ports.
2325 // Entry 0 is reserved.
2326 //
2327 for (Index = 0; Index < 255; Index++) {
2328 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2329 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2330 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2331 continue;
2332 }
2333
2334 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2335
2336 if (EFI_ERROR (Status)) {
2337 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2338 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2339 }
2340 }
2341
2342 //
2343 // Construct the disable slot command
2344 //
2345 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2346
2347 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2348 CmdTrbDisSlot.CycleBit = 1;
2349 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2350 CmdTrbDisSlot.SlotId = SlotId;
2351 Status = XhcCmdTransfer (
2352 Xhc,
2353 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2354 XHC_GENERIC_TIMEOUT,
2355 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2356 );
2357 if (EFI_ERROR (Status)) {
2358 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2359 return Status;
2360 }
2361 //
2362 // Free the slot's device context entry
2363 //
2364 Xhc->DCBAA[SlotId] = 0;
2365
2366 //
2367 // Free the slot related data structure
2368 //
2369 for (Index = 0; Index < 31; Index++) {
2370 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2371 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2372 if (RingSeg != NULL) {
2373 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2374 }
2375 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2376 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2377 }
2378 }
2379
2380 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2381 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2382 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2383 }
2384 }
2385
2386 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2387 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
2388 }
2389
2390 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2391 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
2392 }
2393 //
2394 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2395 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2396 // remove urb from XHCI's asynchronous transfer list.
2397 //
2398 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2399 Xhc->UsbDevContext[SlotId].SlotId = 0;
2400
2401 return Status;
2402 }
2403
2404 /**
2405 Disable the specified device slot.
2406
2407 @param Xhc The XHCI Instance.
2408 @param SlotId The slot id to be disabled.
2409
2410 @retval EFI_SUCCESS Successfully disable the device slot.
2411
2412 **/
2413 EFI_STATUS
2414 EFIAPI
2415 XhcDisableSlotCmd64 (
2416 IN USB_XHCI_INSTANCE *Xhc,
2417 IN UINT8 SlotId
2418 )
2419 {
2420 EFI_STATUS Status;
2421 TRB_TEMPLATE *EvtTrb;
2422 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2423 UINT8 Index;
2424 VOID *RingSeg;
2425
2426 //
2427 // Disable the device slots occupied by these devices on its downstream ports.
2428 // Entry 0 is reserved.
2429 //
2430 for (Index = 0; Index < 255; Index++) {
2431 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2432 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2433 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2434 continue;
2435 }
2436
2437 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2438
2439 if (EFI_ERROR (Status)) {
2440 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2441 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2442 }
2443 }
2444
2445 //
2446 // Construct the disable slot command
2447 //
2448 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2449
2450 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2451 CmdTrbDisSlot.CycleBit = 1;
2452 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2453 CmdTrbDisSlot.SlotId = SlotId;
2454 Status = XhcCmdTransfer (
2455 Xhc,
2456 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2457 XHC_GENERIC_TIMEOUT,
2458 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2459 );
2460 if (EFI_ERROR (Status)) {
2461 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
2462 return Status;
2463 }
2464 //
2465 // Free the slot's device context entry
2466 //
2467 Xhc->DCBAA[SlotId] = 0;
2468
2469 //
2470 // Free the slot related data structure
2471 //
2472 for (Index = 0; Index < 31; Index++) {
2473 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2474 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2475 if (RingSeg != NULL) {
2476 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
2477 }
2478 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2479 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
2480 }
2481 }
2482
2483 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2484 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2485 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2486 }
2487 }
2488
2489 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2490 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
2491 }
2492
2493 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2494 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
2495 }
2496 //
2497 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2498 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2499 // remove urb from XHCI's asynchronous transfer list.
2500 //
2501 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2502 Xhc->UsbDevContext[SlotId].SlotId = 0;
2503
2504 return Status;
2505 }
2506
2507
2508 /**
2509 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2510
2511 @param Xhc The XHCI Instance.
2512 @param SlotId The slot id to be configured.
2513 @param DeviceSpeed The device's speed.
2514 @param ConfigDesc The pointer to the usb device configuration descriptor.
2515
2516 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2517
2518 **/
2519 EFI_STATUS
2520 EFIAPI
2521 XhcSetConfigCmd (
2522 IN USB_XHCI_INSTANCE *Xhc,
2523 IN UINT8 SlotId,
2524 IN UINT8 DeviceSpeed,
2525 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
2526 )
2527 {
2528 EFI_STATUS Status;
2529 USB_INTERFACE_DESCRIPTOR *IfDesc;
2530 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2531 UINT8 Index;
2532 UINTN NumEp;
2533 UINTN EpIndex;
2534 UINT8 EpAddr;
2535 UINT8 Direction;
2536 UINT8 Dci;
2537 UINT8 MaxDci;
2538 EFI_PHYSICAL_ADDRESS PhyAddr;
2539 UINT8 Interval;
2540
2541 TRANSFER_RING *EndpointTransferRing;
2542 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2543 INPUT_CONTEXT *InputContext;
2544 DEVICE_CONTEXT *OutputContext;
2545 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2546 //
2547 // 4.6.6 Configure Endpoint
2548 //
2549 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2550 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2551 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2552 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
2553
2554 ASSERT (ConfigDesc != NULL);
2555
2556 MaxDci = 0;
2557
2558 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2559 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2560 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
2561 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2562 }
2563
2564 NumEp = IfDesc->NumEndpoints;
2565
2566 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2567 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2568 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2569 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2570 }
2571
2572 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2573 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2574
2575 Dci = XhcEndpointToDci (EpAddr, Direction);
2576 ASSERT (Dci < 32);
2577 if (Dci > MaxDci) {
2578 MaxDci = Dci;
2579 }
2580
2581 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2582 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2583
2584 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2585 //
2586 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2587 //
2588 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2589 } else {
2590 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2591 }
2592
2593 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2594 case USB_ENDPOINT_BULK:
2595 if (Direction == EfiUsbDataIn) {
2596 InputContext->EP[Dci-1].CErr = 3;
2597 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2598 } else {
2599 InputContext->EP[Dci-1].CErr = 3;
2600 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2601 }
2602
2603 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2604 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2605 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2606 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2607 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2608 }
2609
2610 break;
2611 case USB_ENDPOINT_ISO:
2612 if (Direction == EfiUsbDataIn) {
2613 InputContext->EP[Dci-1].CErr = 0;
2614 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2615 } else {
2616 InputContext->EP[Dci-1].CErr = 0;
2617 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2618 }
2619 break;
2620 case USB_ENDPOINT_INTERRUPT:
2621 if (Direction == EfiUsbDataIn) {
2622 InputContext->EP[Dci-1].CErr = 3;
2623 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2624 } else {
2625 InputContext->EP[Dci-1].CErr = 3;
2626 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2627 }
2628 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2629 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2630 //
2631 // Get the bInterval from descriptor and init the the interval field of endpoint context
2632 //
2633 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2634 Interval = EpDesc->Interval;
2635 //
2636 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2637 //
2638 InputContext->EP[Dci-1].Interval = 6;
2639 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2640 Interval = EpDesc->Interval;
2641 ASSERT (Interval >= 1 && Interval <= 16);
2642 //
2643 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2644 //
2645 InputContext->EP[Dci-1].Interval = Interval - 1;
2646 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2647 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2648 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2649 InputContext->EP[Dci-1].CErr = 3;
2650 }
2651
2652 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2653 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2654 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2655 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2656 }
2657 break;
2658
2659 case USB_ENDPOINT_CONTROL:
2660 default:
2661 ASSERT (0);
2662 break;
2663 }
2664
2665 PhyAddr = UsbHcGetPciAddrForHostAddr (
2666 Xhc->MemPool,
2667 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2668 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2669 );
2670 PhyAddr &= ~(0x0F);
2671 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2672 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2673 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2674
2675 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2676 }
2677 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2678 }
2679
2680 InputContext->InputControlContext.Dword2 |= BIT0;
2681 InputContext->Slot.ContextEntries = MaxDci;
2682 //
2683 // configure endpoint
2684 //
2685 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2686 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2687 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
2688 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2689 CmdTrbCfgEP.CycleBit = 1;
2690 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2691 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2692 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2693 Status = XhcCmdTransfer (
2694 Xhc,
2695 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2696 XHC_GENERIC_TIMEOUT,
2697 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2698 );
2699 if (EFI_ERROR (Status)) {
2700 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
2701 }
2702 return Status;
2703 }
2704
2705 /**
2706 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2707
2708 @param Xhc The XHCI Instance.
2709 @param SlotId The slot id to be configured.
2710 @param DeviceSpeed The device's speed.
2711 @param ConfigDesc The pointer to the usb device configuration descriptor.
2712
2713 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2714
2715 **/
2716 EFI_STATUS
2717 EFIAPI
2718 XhcSetConfigCmd64 (
2719 IN USB_XHCI_INSTANCE *Xhc,
2720 IN UINT8 SlotId,
2721 IN UINT8 DeviceSpeed,
2722 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
2723 )
2724 {
2725 EFI_STATUS Status;
2726 USB_INTERFACE_DESCRIPTOR *IfDesc;
2727 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2728 UINT8 Index;
2729 UINTN NumEp;
2730 UINTN EpIndex;
2731 UINT8 EpAddr;
2732 UINT8 Direction;
2733 UINT8 Dci;
2734 UINT8 MaxDci;
2735 EFI_PHYSICAL_ADDRESS PhyAddr;
2736 UINT8 Interval;
2737
2738 TRANSFER_RING *EndpointTransferRing;
2739 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2740 INPUT_CONTEXT_64 *InputContext;
2741 DEVICE_CONTEXT_64 *OutputContext;
2742 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2743 //
2744 // 4.6.6 Configure Endpoint
2745 //
2746 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2747 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2748 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2749 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
2750
2751 ASSERT (ConfigDesc != NULL);
2752
2753 MaxDci = 0;
2754
2755 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2756 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2757 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
2758 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2759 }
2760
2761 NumEp = IfDesc->NumEndpoints;
2762
2763 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2764 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2765 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2766 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2767 }
2768
2769 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2770 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2771
2772 Dci = XhcEndpointToDci (EpAddr, Direction);
2773 ASSERT (Dci < 32);
2774 if (Dci > MaxDci) {
2775 MaxDci = Dci;
2776 }
2777
2778 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2779 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2780
2781 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2782 //
2783 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2784 //
2785 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2786 } else {
2787 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2788 }
2789
2790 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2791 case USB_ENDPOINT_BULK:
2792 if (Direction == EfiUsbDataIn) {
2793 InputContext->EP[Dci-1].CErr = 3;
2794 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2795 } else {
2796 InputContext->EP[Dci-1].CErr = 3;
2797 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2798 }
2799
2800 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2801 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2802 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2803 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2804 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2805 }
2806
2807 break;
2808 case USB_ENDPOINT_ISO:
2809 if (Direction == EfiUsbDataIn) {
2810 InputContext->EP[Dci-1].CErr = 0;
2811 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2812 } else {
2813 InputContext->EP[Dci-1].CErr = 0;
2814 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2815 }
2816 break;
2817 case USB_ENDPOINT_INTERRUPT:
2818 if (Direction == EfiUsbDataIn) {
2819 InputContext->EP[Dci-1].CErr = 3;
2820 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2821 } else {
2822 InputContext->EP[Dci-1].CErr = 3;
2823 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2824 }
2825 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2826 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2827 //
2828 // Get the bInterval from descriptor and init the the interval field of endpoint context
2829 //
2830 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2831 Interval = EpDesc->Interval;
2832 //
2833 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2834 //
2835 InputContext->EP[Dci-1].Interval = 6;
2836 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2837 Interval = EpDesc->Interval;
2838 ASSERT (Interval >= 1 && Interval <= 16);
2839 //
2840 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2841 //
2842 InputContext->EP[Dci-1].Interval = Interval - 1;
2843 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2844 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2845 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2846 InputContext->EP[Dci-1].CErr = 3;
2847 }
2848
2849 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2850 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2851 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2852 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2853 }
2854 break;
2855
2856 case USB_ENDPOINT_CONTROL:
2857 default:
2858 ASSERT (0);
2859 break;
2860 }
2861
2862 PhyAddr = UsbHcGetPciAddrForHostAddr (
2863 Xhc->MemPool,
2864 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
2865 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
2866 );
2867
2868 PhyAddr &= ~(0x0F);
2869 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2870
2871 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
2872 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
2873
2874 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2875 }
2876 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2877 }
2878
2879 InputContext->InputControlContext.Dword2 |= BIT0;
2880 InputContext->Slot.ContextEntries = MaxDci;
2881 //
2882 // configure endpoint
2883 //
2884 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2885 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2886 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
2887 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2888 CmdTrbCfgEP.CycleBit = 1;
2889 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2890 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2891 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2892 Status = XhcCmdTransfer (
2893 Xhc,
2894 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2895 XHC_GENERIC_TIMEOUT,
2896 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2897 );
2898 if (EFI_ERROR (Status)) {
2899 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
2900 }
2901
2902 return Status;
2903 }
2904
2905
2906 /**
2907 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2908
2909 @param Xhc The XHCI Instance.
2910 @param SlotId The slot id to be evaluated.
2911 @param MaxPacketSize The max packet size supported by the device control transfer.
2912
2913 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2914
2915 **/
2916 EFI_STATUS
2917 EFIAPI
2918 XhcEvaluateContext (
2919 IN USB_XHCI_INSTANCE *Xhc,
2920 IN UINT8 SlotId,
2921 IN UINT32 MaxPacketSize
2922 )
2923 {
2924 EFI_STATUS Status;
2925 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2926 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2927 INPUT_CONTEXT *InputContext;
2928 EFI_PHYSICAL_ADDRESS PhyAddr;
2929
2930 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2931
2932 //
2933 // 4.6.7 Evaluate Context
2934 //
2935 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2936 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2937
2938 InputContext->InputControlContext.Dword2 |= BIT1;
2939 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2940
2941 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2942 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
2943 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
2944 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
2945 CmdTrbEvalu.CycleBit = 1;
2946 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2947 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2948 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
2949 Status = XhcCmdTransfer (
2950 Xhc,
2951 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2952 XHC_GENERIC_TIMEOUT,
2953 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2954 );
2955 if (EFI_ERROR (Status)) {
2956 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
2957 }
2958 return Status;
2959 }
2960
2961 /**
2962 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2963
2964 @param Xhc The XHCI Instance.
2965 @param SlotId The slot id to be evaluated.
2966 @param MaxPacketSize The max packet size supported by the device control transfer.
2967
2968 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2969
2970 **/
2971 EFI_STATUS
2972 EFIAPI
2973 XhcEvaluateContext64 (
2974 IN USB_XHCI_INSTANCE *Xhc,
2975 IN UINT8 SlotId,
2976 IN UINT32 MaxPacketSize
2977 )
2978 {
2979 EFI_STATUS Status;
2980 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2981 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2982 INPUT_CONTEXT_64 *InputContext;
2983 EFI_PHYSICAL_ADDRESS PhyAddr;
2984
2985 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2986
2987 //
2988 // 4.6.7 Evaluate Context
2989 //
2990 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2991 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2992
2993 InputContext->InputControlContext.Dword2 |= BIT1;
2994 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2995
2996 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2997 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
2998 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
2999 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3000 CmdTrbEvalu.CycleBit = 1;
3001 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
3002 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3003 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
3004 Status = XhcCmdTransfer (
3005 Xhc,
3006 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
3007 XHC_GENERIC_TIMEOUT,
3008 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3009 );
3010 if (EFI_ERROR (Status)) {
3011 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
3012 }
3013 return Status;
3014 }
3015
3016
3017 /**
3018 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3019
3020 @param Xhc The XHCI Instance.
3021 @param SlotId The slot id to be configured.
3022 @param PortNum The total number of downstream port supported by the hub.
3023 @param TTT The TT think time of the hub device.
3024 @param MTT The multi-TT of the hub device.
3025
3026 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3027
3028 **/
3029 EFI_STATUS
3030 XhcConfigHubContext (
3031 IN USB_XHCI_INSTANCE *Xhc,
3032 IN UINT8 SlotId,
3033 IN UINT8 PortNum,
3034 IN UINT8 TTT,
3035 IN UINT8 MTT
3036 )
3037 {
3038 EFI_STATUS Status;
3039 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3040 INPUT_CONTEXT *InputContext;
3041 DEVICE_CONTEXT *OutputContext;
3042 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3043 EFI_PHYSICAL_ADDRESS PhyAddr;
3044
3045 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3046 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3047 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3048
3049 //
3050 // 4.6.7 Evaluate Context
3051 //
3052 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
3053
3054 InputContext->InputControlContext.Dword2 |= BIT0;
3055
3056 //
3057 // Copy the slot context from OutputContext to Input context
3058 //
3059 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
3060 InputContext->Slot.Hub = 1;
3061 InputContext->Slot.PortNum = PortNum;
3062 InputContext->Slot.TTT = TTT;
3063 InputContext->Slot.MTT = MTT;
3064
3065 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3066 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
3067 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3068 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3069 CmdTrbCfgEP.CycleBit = 1;
3070 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3071 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3072 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
3073 Status = XhcCmdTransfer (
3074 Xhc,
3075 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3076 XHC_GENERIC_TIMEOUT,
3077 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3078 );
3079 if (EFI_ERROR (Status)) {
3080 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
3081 }
3082 return Status;
3083 }
3084
3085 /**
3086 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3087
3088 @param Xhc The XHCI Instance.
3089 @param SlotId The slot id to be configured.
3090 @param PortNum The total number of downstream port supported by the hub.
3091 @param TTT The TT think time of the hub device.
3092 @param MTT The multi-TT of the hub device.
3093
3094 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3095
3096 **/
3097 EFI_STATUS
3098 XhcConfigHubContext64 (
3099 IN USB_XHCI_INSTANCE *Xhc,
3100 IN UINT8 SlotId,
3101 IN UINT8 PortNum,
3102 IN UINT8 TTT,
3103 IN UINT8 MTT
3104 )
3105 {
3106 EFI_STATUS Status;
3107 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
3108 INPUT_CONTEXT_64 *InputContext;
3109 DEVICE_CONTEXT_64 *OutputContext;
3110 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
3111 EFI_PHYSICAL_ADDRESS PhyAddr;
3112
3113 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
3114 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
3115 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
3116
3117 //
3118 // 4.6.7 Evaluate Context
3119 //
3120 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
3121
3122 InputContext->InputControlContext.Dword2 |= BIT0;
3123
3124 //
3125 // Copy the slot context from OutputContext to Input context
3126 //
3127 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
3128 InputContext->Slot.Hub = 1;
3129 InputContext->Slot.PortNum = PortNum;
3130 InputContext->Slot.TTT = TTT;
3131 InputContext->Slot.MTT = MTT;
3132
3133 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
3134 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
3135 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
3136 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
3137 CmdTrbCfgEP.CycleBit = 1;
3138 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
3139 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
3140 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
3141 Status = XhcCmdTransfer (
3142 Xhc,
3143 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
3144 XHC_GENERIC_TIMEOUT,
3145 (TRB_TEMPLATE **) (UINTN) &EvtTrb
3146 );
3147 if (EFI_ERROR (Status)) {
3148 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
3149 }
3150 return Status;
3151 }
3152
3153