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