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