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