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