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