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