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