]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
e6c0d1564241ac99a6e7f3d7bf7fdc86ac40a55c
[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 AsyncUrb = NULL;
926
927 if (Urb->Finished) {
928 goto EXIT;
929 }
930
931 EvtTrb = NULL;
932
933 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
934 Urb->Result |= EFI_USB_ERR_SYSTEM;
935 Status = EFI_DEVICE_ERROR;
936 goto EXIT;
937 }
938
939 //
940 // Traverse the event ring to find out all new events from the previous check.
941 //
942 XhcSyncEventRing (Xhc, &Xhc->EventRing);
943 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
944 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
945 if (Status == EFI_NOT_READY) {
946 //
947 // All new events are handled, return directly.
948 //
949 goto EXIT;
950 }
951
952 //
953 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
954 //
955 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
956 continue;
957 }
958
959 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
960
961 //
962 // Update the status of Urb according to the finished event regardless of whether
963 // the urb is current checked one or in the XHCI's async transfer list.
964 // This way is used to avoid that those completed async transfer events don't get
965 // handled in time and are flushed by newer coming events.
966 //
967 if (IsTransferRingTrb (TRBPtr, Urb)) {
968 CheckedUrb = Urb;
969 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
970 CheckedUrb = AsyncUrb;
971 } else {
972 continue;
973 }
974
975 switch (EvtTrb->Completecode) {
976 case TRB_COMPLETION_STALL_ERROR:
977 CheckedUrb->Result |= EFI_USB_ERR_STALL;
978 CheckedUrb->Finished = TRUE;
979 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
980 break;
981
982 case TRB_COMPLETION_BABBLE_ERROR:
983 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
984 CheckedUrb->Finished = TRUE;
985 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
986 break;
987
988 case TRB_COMPLETION_DATA_BUFFER_ERROR:
989 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
990 CheckedUrb->Finished = TRUE;
991 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
992 break;
993
994 case TRB_COMPLETION_USB_TRANSACTION_ERROR:
995 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
996 CheckedUrb->Finished = TRUE;
997 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
998 break;
999
1000 case TRB_COMPLETION_SHORT_PACKET:
1001 case TRB_COMPLETION_SUCCESS:
1002 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
1003 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));
1004 }
1005
1006 TRBType = (UINT8) (TRBPtr->Type);
1007 if ((TRBType == TRB_TYPE_DATA_STAGE) ||
1008 (TRBType == TRB_TYPE_NORMAL) ||
1009 (TRBType == TRB_TYPE_ISOCH)) {
1010 CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Lenth);
1011 }
1012
1013 break;
1014
1015 default:
1016 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
1017 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
1018 CheckedUrb->Finished = TRUE;
1019 break;
1020 }
1021
1022 //
1023 // Only check first and end Trb event address
1024 //
1025 if (TRBPtr == CheckedUrb->TrbStart) {
1026 CheckedUrb->StartDone = TRUE;
1027 }
1028
1029 if (TRBPtr == CheckedUrb->TrbEnd) {
1030 CheckedUrb->EndDone = TRUE;
1031 }
1032
1033 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
1034 CheckedUrb->Finished = TRUE;
1035 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;
1036 }
1037 }
1038
1039 EXIT:
1040
1041 //
1042 // Advance event ring to last available entry
1043 //
1044 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1045 // So divide it to two 32-bytes width register access.
1046 //
1047 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
1048 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
1049 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
1050
1051 if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Xhc->EventRing.EventRingDequeue & (~0x0F))) {
1052 //
1053 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1054 // So divide it to two 32-bytes width register access.
1055 //
1056 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (Xhc->EventRing.EventRingDequeue) | BIT3);
1057 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (Xhc->EventRing.EventRingDequeue));
1058 }
1059
1060 return Status;
1061 }
1062
1063
1064 /**
1065 Execute the transfer by polling the URB. This is a synchronous operation.
1066
1067 @param Xhc The XHCI Instance.
1068 @param CmdTransfer The executed URB is for cmd transfer or not.
1069 @param Urb The URB to execute.
1070 @param Timeout The time to wait before abort, in millisecond.
1071
1072 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1073 @return EFI_TIMEOUT The transfer failed due to time out.
1074 @return EFI_SUCCESS The transfer finished OK.
1075
1076 **/
1077 EFI_STATUS
1078 XhcExecTransfer (
1079 IN USB_XHCI_INSTANCE *Xhc,
1080 IN BOOLEAN CmdTransfer,
1081 IN URB *Urb,
1082 IN UINTN Timeout
1083 )
1084 {
1085 EFI_STATUS Status;
1086 UINTN Index;
1087 UINTN Loop;
1088 UINT8 SlotId;
1089 UINT8 Dci;
1090
1091 if (CmdTransfer) {
1092 SlotId = 0;
1093 Dci = 0;
1094 } else {
1095 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1096 if (SlotId == 0) {
1097 return EFI_DEVICE_ERROR;
1098 }
1099 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1100 ASSERT (Dci < 32);
1101 }
1102
1103 Status = EFI_SUCCESS;
1104 Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;
1105 if (Timeout == 0) {
1106 Loop = 0xFFFFFFFF;
1107 }
1108
1109 XhcRingDoorBell (Xhc, SlotId, Dci);
1110
1111 for (Index = 0; Index < Loop; Index++) {
1112 Status = XhcCheckUrbResult (Xhc, Urb);
1113 if (Urb->Finished) {
1114 break;
1115 }
1116 gBS->Stall (XHC_POLL_DELAY);
1117 }
1118
1119 if (Index == Loop) {
1120 Urb->Result = EFI_USB_ERR_TIMEOUT;
1121 }
1122
1123 return Status;
1124 }
1125
1126 /**
1127 Delete a single asynchronous interrupt transfer for
1128 the device and endpoint.
1129
1130 @param Xhc The XHCI Instance.
1131 @param BusAddr The logical device address assigned by UsbBus driver.
1132 @param EpNum The endpoint of the target.
1133
1134 @retval EFI_SUCCESS An asynchronous transfer is removed.
1135 @retval EFI_NOT_FOUND No transfer for the device is found.
1136
1137 **/
1138 EFI_STATUS
1139 XhciDelAsyncIntTransfer (
1140 IN USB_XHCI_INSTANCE *Xhc,
1141 IN UINT8 BusAddr,
1142 IN UINT8 EpNum
1143 )
1144 {
1145 LIST_ENTRY *Entry;
1146 LIST_ENTRY *Next;
1147 URB *Urb;
1148 EFI_USB_DATA_DIRECTION Direction;
1149
1150 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
1151 EpNum &= 0x0F;
1152
1153 Urb = NULL;
1154
1155 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1156 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1157 if ((Urb->Ep.BusAddr == BusAddr) &&
1158 (Urb->Ep.EpAddr == EpNum) &&
1159 (Urb->Ep.Direction == Direction)) {
1160 RemoveEntryList (&Urb->UrbList);
1161 FreePool (Urb->Data);
1162 FreePool (Urb);
1163 return EFI_SUCCESS;
1164 }
1165 }
1166
1167 return EFI_NOT_FOUND;
1168 }
1169
1170 /**
1171 Remove all the asynchronous interrutp transfers.
1172
1173 @param Xhc The XHCI Instance.
1174
1175 **/
1176 VOID
1177 XhciDelAllAsyncIntTransfers (
1178 IN USB_XHCI_INSTANCE *Xhc
1179 )
1180 {
1181 LIST_ENTRY *Entry;
1182 LIST_ENTRY *Next;
1183 URB *Urb;
1184
1185 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1186 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1187 RemoveEntryList (&Urb->UrbList);
1188 FreePool (Urb->Data);
1189 FreePool (Urb);
1190 }
1191 }
1192
1193 /**
1194 Update the queue head for next round of asynchronous transfer
1195
1196 @param Xhc The XHCI Instance.
1197 @param Urb The URB to update
1198
1199 **/
1200 VOID
1201 XhcUpdateAsyncRequest (
1202 IN USB_XHCI_INSTANCE *Xhc,
1203 IN URB *Urb
1204 )
1205 {
1206 EFI_STATUS Status;
1207
1208 if (Urb->Result == EFI_USB_NOERROR) {
1209 Status = XhcCreateTransferTrb (Xhc, Urb);
1210 if (EFI_ERROR (Status)) {
1211 return;
1212 }
1213 Status = RingIntTransferDoorBell (Xhc, Urb);
1214 if (EFI_ERROR (Status)) {
1215 return;
1216 }
1217 }
1218 }
1219
1220
1221 /**
1222 Interrupt transfer periodic check handler.
1223
1224 @param Event Interrupt event.
1225 @param Context Pointer to USB_XHCI_INSTANCE.
1226
1227 **/
1228 VOID
1229 EFIAPI
1230 XhcMonitorAsyncRequests (
1231 IN EFI_EVENT Event,
1232 IN VOID *Context
1233 )
1234 {
1235 USB_XHCI_INSTANCE *Xhc;
1236 LIST_ENTRY *Entry;
1237 LIST_ENTRY *Next;
1238 UINT8 *ProcBuf;
1239 URB *Urb;
1240 UINT8 SlotId;
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 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 ASSERT (EvtRing != NULL);
1628
1629 *NewEvtTrb = EvtRing->EventRingDequeue;
1630
1631 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
1632 return EFI_NOT_READY;
1633 }
1634
1635 EvtRing->EventRingDequeue++;
1636 //
1637 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1638 //
1639 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1640 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
1641 }
1642
1643 return EFI_SUCCESS;
1644 }
1645
1646 /**
1647 Ring the door bell to notify XHCI there is a transaction to be executed.
1648
1649 @param Xhc The XHCI Instance.
1650 @param SlotId The slot id of the target device.
1651 @param Dci The device context index of the target slot or endpoint.
1652
1653 @retval EFI_SUCCESS Successfully ring the door bell.
1654
1655 **/
1656 EFI_STATUS
1657 EFIAPI
1658 XhcRingDoorBell (
1659 IN USB_XHCI_INSTANCE *Xhc,
1660 IN UINT8 SlotId,
1661 IN UINT8 Dci
1662 )
1663 {
1664 if (SlotId == 0) {
1665 XhcWriteDoorBellReg (Xhc, 0, 0);
1666 } else {
1667 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1668 }
1669
1670 return EFI_SUCCESS;
1671 }
1672
1673 /**
1674 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1675
1676 @param Xhc The XHCI Instance.
1677 @param Urb The URB to be rung.
1678
1679 @retval EFI_SUCCESS Successfully ring the door bell.
1680
1681 **/
1682 EFI_STATUS
1683 RingIntTransferDoorBell (
1684 IN USB_XHCI_INSTANCE *Xhc,
1685 IN URB *Urb
1686 )
1687 {
1688 UINT8 SlotId;
1689 UINT8 Dci;
1690
1691 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1692 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1693 XhcRingDoorBell (Xhc, SlotId, Dci);
1694 return EFI_SUCCESS;
1695 }
1696
1697 /**
1698 Assign and initialize the device slot for a new device.
1699
1700 @param Xhc The XHCI Instance.
1701 @param ParentRouteChart The route string pointed to the parent device.
1702 @param ParentPort The port at which the device is located.
1703 @param RouteChart The route string pointed to the device.
1704 @param DeviceSpeed The device speed.
1705
1706 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1707
1708 **/
1709 EFI_STATUS
1710 EFIAPI
1711 XhcInitializeDeviceSlot (
1712 IN USB_XHCI_INSTANCE *Xhc,
1713 IN USB_DEV_ROUTE ParentRouteChart,
1714 IN UINT16 ParentPort,
1715 IN USB_DEV_ROUTE RouteChart,
1716 IN UINT8 DeviceSpeed
1717 )
1718 {
1719 EFI_STATUS Status;
1720 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1721 INPUT_CONTEXT *InputContext;
1722 DEVICE_CONTEXT *OutputContext;
1723 TRANSFER_RING *EndpointTransferRing;
1724 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1725 UINT8 DeviceAddress;
1726 CMD_TRB_ENABLE_SLOT CmdTrb;
1727 UINT8 SlotId;
1728 UINT8 ParentSlotId;
1729 DEVICE_CONTEXT *ParentDeviceContext;
1730
1731 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1732 CmdTrb.CycleBit = 1;
1733 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1734
1735 Status = XhcCmdTransfer (
1736 Xhc,
1737 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1738 XHC_GENERIC_TIMEOUT,
1739 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1740 );
1741 ASSERT_EFI_ERROR (Status);
1742 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1743 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1744 SlotId = (UINT8)EvtTrb->SlotId;
1745 ASSERT (SlotId != 0);
1746
1747 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1748 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1749 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1750 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1751 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1752
1753 //
1754 // 4.3.3 Device Slot Initialization
1755 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1756 //
1757 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));
1758 ASSERT (InputContext != NULL);
1759 ASSERT (((UINTN) InputContext & 0x3F) == 0);
1760 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1761
1762 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1763
1764 //
1765 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1766 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1767 // Context are affected by the command.
1768 //
1769 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1770
1771 //
1772 // 3) Initialize the Input Slot Context data structure
1773 //
1774 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1775 InputContext->Slot.Speed = DeviceSpeed + 1;
1776 InputContext->Slot.ContextEntries = 1;
1777 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1778
1779 if (RouteChart.Route.RouteString) {
1780 //
1781 // The device is behind of hub device.
1782 //
1783 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
1784 ASSERT (ParentSlotId != 0);
1785 //
1786 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1787 //
1788 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1789 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1790 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1791 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1792 //
1793 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1794 // environment from Full/Low speed signaling environment for a device
1795 //
1796 InputContext->Slot.TTPortNum = ParentPort;
1797 InputContext->Slot.TTHubSlotId = ParentSlotId;
1798 }
1799 } else {
1800 //
1801 // Inherit the TT parameters from parent device.
1802 //
1803 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
1804 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1805 //
1806 // If the device is a High speed device then down the speed to be the same as its parent Hub
1807 //
1808 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1809 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1810 }
1811 }
1812 }
1813
1814 //
1815 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1816 //
1817 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1818 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1819 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1820 //
1821 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1822 //
1823 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1824
1825 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1826 InputContext->EP[0].MaxPacketSize = 512;
1827 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1828 InputContext->EP[0].MaxPacketSize = 64;
1829 } else {
1830 InputContext->EP[0].MaxPacketSize = 8;
1831 }
1832 //
1833 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1834 // 1KB, and Bulk and Isoch endpoints 3KB.
1835 //
1836 InputContext->EP[0].AverageTRBLength = 8;
1837 InputContext->EP[0].MaxBurstSize = 0;
1838 InputContext->EP[0].Interval = 0;
1839 InputContext->EP[0].MaxPStreams = 0;
1840 InputContext->EP[0].Mult = 0;
1841 InputContext->EP[0].CErr = 3;
1842
1843 //
1844 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1845 //
1846 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;
1847 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);
1848
1849 //
1850 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1851 //
1852 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));
1853 ASSERT (OutputContext != NULL);
1854 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
1855 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
1856
1857 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1858 //
1859 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1860 // a pointer to the Output Device Context data structure (6.2.1).
1861 //
1862 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;
1863
1864 //
1865 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1866 // Context data structure described above.
1867 //
1868 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1869 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
1870 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
1871 CmdTrbAddr.CycleBit = 1;
1872 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
1873 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
1874 Status = XhcCmdTransfer (
1875 Xhc,
1876 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1877 XHC_GENERIC_TIMEOUT,
1878 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1879 );
1880 ASSERT (!EFI_ERROR(Status));
1881
1882 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
1883 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
1884
1885 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1886
1887 return Status;
1888 }
1889
1890 /**
1891 Assign and initialize the device slot for a new device.
1892
1893 @param Xhc The XHCI Instance.
1894 @param ParentRouteChart The route string pointed to the parent device.
1895 @param ParentPort The port at which the device is located.
1896 @param RouteChart The route string pointed to the device.
1897 @param DeviceSpeed The device speed.
1898
1899 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1900
1901 **/
1902 EFI_STATUS
1903 EFIAPI
1904 XhcInitializeDeviceSlot64 (
1905 IN USB_XHCI_INSTANCE *Xhc,
1906 IN USB_DEV_ROUTE ParentRouteChart,
1907 IN UINT16 ParentPort,
1908 IN USB_DEV_ROUTE RouteChart,
1909 IN UINT8 DeviceSpeed
1910 )
1911 {
1912 EFI_STATUS Status;
1913 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1914 INPUT_CONTEXT_64 *InputContext;
1915 DEVICE_CONTEXT_64 *OutputContext;
1916 TRANSFER_RING *EndpointTransferRing;
1917 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1918 UINT8 DeviceAddress;
1919 CMD_TRB_ENABLE_SLOT CmdTrb;
1920 UINT8 SlotId;
1921 UINT8 ParentSlotId;
1922 DEVICE_CONTEXT_64 *ParentDeviceContext;
1923
1924 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1925 CmdTrb.CycleBit = 1;
1926 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1927
1928 Status = XhcCmdTransfer (
1929 Xhc,
1930 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1931 XHC_GENERIC_TIMEOUT,
1932 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1933 );
1934 ASSERT_EFI_ERROR (Status);
1935 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1936 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1937 SlotId = (UINT8)EvtTrb->SlotId;
1938 ASSERT (SlotId != 0);
1939
1940 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1941 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1942 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1943 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1944 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1945
1946 //
1947 // 4.3.3 Device Slot Initialization
1948 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1949 //
1950 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64)));
1951 ASSERT (InputContext != NULL);
1952 ASSERT (((UINTN) InputContext & 0x3F) == 0);
1953 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1954
1955 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1956
1957 //
1958 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1959 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1960 // Context are affected by the command.
1961 //
1962 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1963
1964 //
1965 // 3) Initialize the Input Slot Context data structure
1966 //
1967 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1968 InputContext->Slot.Speed = DeviceSpeed + 1;
1969 InputContext->Slot.ContextEntries = 1;
1970 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1971
1972 if (RouteChart.Route.RouteString) {
1973 //
1974 // The device is behind of hub device.
1975 //
1976 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
1977 ASSERT (ParentSlotId != 0);
1978 //
1979 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1980 //
1981 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1982 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1983 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1984 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1985 //
1986 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1987 // environment from Full/Low speed signaling environment for a device
1988 //
1989 InputContext->Slot.TTPortNum = ParentPort;
1990 InputContext->Slot.TTHubSlotId = ParentSlotId;
1991 }
1992 } else {
1993 //
1994 // Inherit the TT parameters from parent device.
1995 //
1996 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
1997 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1998 //
1999 // If the device is a High speed device then down the speed to be the same as its parent Hub
2000 //
2001 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2002 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2003 }
2004 }
2005 }
2006
2007 //
2008 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2009 //
2010 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2011 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2012 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2013 //
2014 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2015 //
2016 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2017
2018 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2019 InputContext->EP[0].MaxPacketSize = 512;
2020 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2021 InputContext->EP[0].MaxPacketSize = 64;
2022 } else {
2023 InputContext->EP[0].MaxPacketSize = 8;
2024 }
2025 //
2026 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2027 // 1KB, and Bulk and Isoch endpoints 3KB.
2028 //
2029 InputContext->EP[0].AverageTRBLength = 8;
2030 InputContext->EP[0].MaxBurstSize = 0;
2031 InputContext->EP[0].Interval = 0;
2032 InputContext->EP[0].MaxPStreams = 0;
2033 InputContext->EP[0].Mult = 0;
2034 InputContext->EP[0].CErr = 3;
2035
2036 //
2037 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2038 //
2039 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;
2040 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);
2041
2042 //
2043 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2044 //
2045 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64)));
2046 ASSERT (OutputContext != NULL);
2047 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2048 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2049
2050 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2051 //
2052 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2053 // a pointer to the Output Device Context data structure (6.2.1).
2054 //
2055 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;
2056
2057 //
2058 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2059 // Context data structure described above.
2060 //
2061 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2062 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
2063 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
2064 CmdTrbAddr.CycleBit = 1;
2065 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2066 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2067 Status = XhcCmdTransfer (
2068 Xhc,
2069 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2070 XHC_GENERIC_TIMEOUT,
2071 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2072 );
2073 ASSERT (!EFI_ERROR(Status));
2074
2075 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2076 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2077
2078 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2079
2080 return Status;
2081 }
2082
2083
2084 /**
2085 Disable the specified device slot.
2086
2087 @param Xhc The XHCI Instance.
2088 @param SlotId The slot id to be disabled.
2089
2090 @retval EFI_SUCCESS Successfully disable the device slot.
2091
2092 **/
2093 EFI_STATUS
2094 EFIAPI
2095 XhcDisableSlotCmd (
2096 IN USB_XHCI_INSTANCE *Xhc,
2097 IN UINT8 SlotId
2098 )
2099 {
2100 EFI_STATUS Status;
2101 TRB_TEMPLATE *EvtTrb;
2102 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2103 UINT8 Index;
2104 VOID *RingSeg;
2105
2106 //
2107 // Disable the device slots occupied by these devices on its downstream ports.
2108 // Entry 0 is reserved.
2109 //
2110 for (Index = 0; Index < 255; Index++) {
2111 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2112 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2113 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2114 continue;
2115 }
2116
2117 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2118
2119 if (EFI_ERROR (Status)) {
2120 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2121 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2122 }
2123 }
2124
2125 //
2126 // Construct the disable slot command
2127 //
2128 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2129
2130 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2131 CmdTrbDisSlot.CycleBit = 1;
2132 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2133 CmdTrbDisSlot.SlotId = SlotId;
2134 Status = XhcCmdTransfer (
2135 Xhc,
2136 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2137 XHC_GENERIC_TIMEOUT,
2138 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2139 );
2140 ASSERT_EFI_ERROR(Status);
2141 //
2142 // Free the slot's device context entry
2143 //
2144 Xhc->DCBAA[SlotId] = 0;
2145
2146 //
2147 // Free the slot related data structure
2148 //
2149 for (Index = 0; Index < 31; Index++) {
2150 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2151 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2152 if (RingSeg != NULL) {
2153 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));
2154 }
2155 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2156 }
2157 }
2158
2159 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2160 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2161 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2162 }
2163 }
2164
2165 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2166 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));
2167 }
2168
2169 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2170 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));
2171 }
2172 //
2173 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2174 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2175 // remove urb from XHCI's asynchronous transfer list.
2176 //
2177 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2178 Xhc->UsbDevContext[SlotId].SlotId = 0;
2179
2180 return Status;
2181 }
2182
2183 /**
2184 Disable the specified device slot.
2185
2186 @param Xhc The XHCI Instance.
2187 @param SlotId The slot id to be disabled.
2188
2189 @retval EFI_SUCCESS Successfully disable the device slot.
2190
2191 **/
2192 EFI_STATUS
2193 EFIAPI
2194 XhcDisableSlotCmd64 (
2195 IN USB_XHCI_INSTANCE *Xhc,
2196 IN UINT8 SlotId
2197 )
2198 {
2199 EFI_STATUS Status;
2200 TRB_TEMPLATE *EvtTrb;
2201 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2202 UINT8 Index;
2203 VOID *RingSeg;
2204
2205 //
2206 // Disable the device slots occupied by these devices on its downstream ports.
2207 // Entry 0 is reserved.
2208 //
2209 for (Index = 0; Index < 255; Index++) {
2210 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2211 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2212 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2213 continue;
2214 }
2215
2216 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2217
2218 if (EFI_ERROR (Status)) {
2219 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2220 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2221 }
2222 }
2223
2224 //
2225 // Construct the disable slot command
2226 //
2227 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2228
2229 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2230 CmdTrbDisSlot.CycleBit = 1;
2231 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2232 CmdTrbDisSlot.SlotId = SlotId;
2233 Status = XhcCmdTransfer (
2234 Xhc,
2235 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2236 XHC_GENERIC_TIMEOUT,
2237 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2238 );
2239 ASSERT_EFI_ERROR(Status);
2240 //
2241 // Free the slot's device context entry
2242 //
2243 Xhc->DCBAA[SlotId] = 0;
2244
2245 //
2246 // Free the slot related data structure
2247 //
2248 for (Index = 0; Index < 31; Index++) {
2249 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2250 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2251 if (RingSeg != NULL) {
2252 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));
2253 }
2254 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2255 }
2256 }
2257
2258 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2259 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2260 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2261 }
2262 }
2263
2264 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2265 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64)));
2266 }
2267
2268 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2269 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64)));
2270 }
2271 //
2272 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2273 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2274 // remove urb from XHCI's asynchronous transfer list.
2275 //
2276 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2277 Xhc->UsbDevContext[SlotId].SlotId = 0;
2278
2279 return Status;
2280 }
2281
2282
2283 /**
2284 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2285
2286 @param Xhc The XHCI Instance.
2287 @param SlotId The slot id to be configured.
2288 @param DeviceSpeed The device's speed.
2289 @param ConfigDesc The pointer to the usb device configuration descriptor.
2290
2291 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2292
2293 **/
2294 EFI_STATUS
2295 EFIAPI
2296 XhcSetConfigCmd (
2297 IN USB_XHCI_INSTANCE *Xhc,
2298 IN UINT8 SlotId,
2299 IN UINT8 DeviceSpeed,
2300 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
2301 )
2302 {
2303 EFI_STATUS Status;
2304
2305 USB_INTERFACE_DESCRIPTOR *IfDesc;
2306 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2307 UINT8 Index;
2308 UINTN NumEp;
2309 UINTN EpIndex;
2310 UINT8 EpAddr;
2311 UINT8 Direction;
2312 UINT8 Dci;
2313 UINT8 MaxDci;
2314 UINT32 PhyAddr;
2315 UINT8 Interval;
2316
2317 TRANSFER_RING *EndpointTransferRing;
2318 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2319 INPUT_CONTEXT *InputContext;
2320 DEVICE_CONTEXT *OutputContext;
2321 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2322 //
2323 // 4.6.6 Configure Endpoint
2324 //
2325 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2326 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2327 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2328 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
2329
2330 ASSERT (ConfigDesc != NULL);
2331
2332 MaxDci = 0;
2333
2334 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2335 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2336 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
2337 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2338 }
2339
2340 NumEp = IfDesc->NumEndpoints;
2341
2342 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2343 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2344 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2345 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2346 }
2347
2348 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2349 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2350
2351 Dci = XhcEndpointToDci (EpAddr, Direction);
2352 ASSERT (Dci < 32);
2353 if (Dci > MaxDci) {
2354 MaxDci = Dci;
2355 }
2356
2357 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2358 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2359
2360 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2361 //
2362 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2363 //
2364 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2365 } else {
2366 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2367 }
2368
2369 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2370 case USB_ENDPOINT_BULK:
2371 if (Direction == EfiUsbDataIn) {
2372 InputContext->EP[Dci-1].CErr = 3;
2373 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2374 } else {
2375 InputContext->EP[Dci-1].CErr = 3;
2376 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2377 }
2378
2379 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2380 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2381 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2382 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2383 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2384 }
2385
2386 break;
2387 case USB_ENDPOINT_ISO:
2388 if (Direction == EfiUsbDataIn) {
2389 InputContext->EP[Dci-1].CErr = 0;
2390 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2391 } else {
2392 InputContext->EP[Dci-1].CErr = 0;
2393 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2394 }
2395 break;
2396 case USB_ENDPOINT_INTERRUPT:
2397 if (Direction == EfiUsbDataIn) {
2398 InputContext->EP[Dci-1].CErr = 3;
2399 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2400 } else {
2401 InputContext->EP[Dci-1].CErr = 3;
2402 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2403 }
2404 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2405 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2406 //
2407 // Get the bInterval from descriptor and init the the interval field of endpoint context
2408 //
2409 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2410 Interval = EpDesc->Interval;
2411 //
2412 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2413 //
2414 InputContext->EP[Dci-1].Interval = 6;
2415 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2416 Interval = EpDesc->Interval;
2417 ASSERT (Interval >= 1 && Interval <= 16);
2418 //
2419 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2420 //
2421 InputContext->EP[Dci-1].Interval = Interval - 1;
2422 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2423 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2424 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2425 InputContext->EP[Dci-1].CErr = 3;
2426 }
2427
2428 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2429 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2430 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2431 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2432 }
2433 break;
2434
2435 case USB_ENDPOINT_CONTROL:
2436 default:
2437 ASSERT (0);
2438 break;
2439 }
2440
2441 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2442 PhyAddr &= ~(0x0F);
2443 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2444 InputContext->EP[Dci-1].PtrLo = PhyAddr;
2445 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2446
2447 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2448 }
2449 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2450 }
2451
2452 InputContext->InputControlContext.Dword2 |= BIT0;
2453 InputContext->Slot.ContextEntries = MaxDci;
2454 //
2455 // configure endpoint
2456 //
2457 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2458 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2459 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2460 CmdTrbCfgEP.CycleBit = 1;
2461 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2462 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2463 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2464 Status = XhcCmdTransfer (
2465 Xhc,
2466 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2467 XHC_GENERIC_TIMEOUT,
2468 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2469 );
2470 ASSERT_EFI_ERROR(Status);
2471
2472 return Status;
2473 }
2474
2475 /**
2476 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2477
2478 @param Xhc The XHCI Instance.
2479 @param SlotId The slot id to be configured.
2480 @param DeviceSpeed The device's speed.
2481 @param ConfigDesc The pointer to the usb device configuration descriptor.
2482
2483 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2484
2485 **/
2486 EFI_STATUS
2487 EFIAPI
2488 XhcSetConfigCmd64 (
2489 IN USB_XHCI_INSTANCE *Xhc,
2490 IN UINT8 SlotId,
2491 IN UINT8 DeviceSpeed,
2492 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
2493 )
2494 {
2495 EFI_STATUS Status;
2496
2497 USB_INTERFACE_DESCRIPTOR *IfDesc;
2498 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2499 UINT8 Index;
2500 UINTN NumEp;
2501 UINTN EpIndex;
2502 UINT8 EpAddr;
2503 UINT8 Direction;
2504 UINT8 Dci;
2505 UINT8 MaxDci;
2506 UINT32 PhyAddr;
2507 UINT8 Interval;
2508
2509 TRANSFER_RING *EndpointTransferRing;
2510 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2511 INPUT_CONTEXT_64 *InputContext;
2512 DEVICE_CONTEXT_64 *OutputContext;
2513 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2514 //
2515 // 4.6.6 Configure Endpoint
2516 //
2517 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2518 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2519 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2520 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
2521
2522 ASSERT (ConfigDesc != NULL);
2523
2524 MaxDci = 0;
2525
2526 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2527 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2528 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
2529 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2530 }
2531
2532 NumEp = IfDesc->NumEndpoints;
2533
2534 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2535 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2536 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2537 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2538 }
2539
2540 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2541 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2542
2543 Dci = XhcEndpointToDci (EpAddr, Direction);
2544 ASSERT (Dci < 32);
2545 if (Dci > MaxDci) {
2546 MaxDci = Dci;
2547 }
2548
2549 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2550 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2551
2552 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2553 //
2554 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2555 //
2556 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2557 } else {
2558 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2559 }
2560
2561 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2562 case USB_ENDPOINT_BULK:
2563 if (Direction == EfiUsbDataIn) {
2564 InputContext->EP[Dci-1].CErr = 3;
2565 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2566 } else {
2567 InputContext->EP[Dci-1].CErr = 3;
2568 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2569 }
2570
2571 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2572 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2573 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2574 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2575 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2576 }
2577
2578 break;
2579 case USB_ENDPOINT_ISO:
2580 if (Direction == EfiUsbDataIn) {
2581 InputContext->EP[Dci-1].CErr = 0;
2582 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2583 } else {
2584 InputContext->EP[Dci-1].CErr = 0;
2585 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2586 }
2587 break;
2588 case USB_ENDPOINT_INTERRUPT:
2589 if (Direction == EfiUsbDataIn) {
2590 InputContext->EP[Dci-1].CErr = 3;
2591 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2592 } else {
2593 InputContext->EP[Dci-1].CErr = 3;
2594 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2595 }
2596 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2597 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2598 //
2599 // Get the bInterval from descriptor and init the the interval field of endpoint context
2600 //
2601 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2602 Interval = EpDesc->Interval;
2603 //
2604 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2605 //
2606 InputContext->EP[Dci-1].Interval = 6;
2607 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2608 Interval = EpDesc->Interval;
2609 ASSERT (Interval >= 1 && Interval <= 16);
2610 //
2611 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2612 //
2613 InputContext->EP[Dci-1].Interval = Interval - 1;
2614 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2615 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2616 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2617 InputContext->EP[Dci-1].CErr = 3;
2618 }
2619
2620 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2621 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2622 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2623 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2624 }
2625 break;
2626
2627 case USB_ENDPOINT_CONTROL:
2628 default:
2629 ASSERT (0);
2630 break;
2631 }
2632
2633 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2634 PhyAddr &= ~(0x0F);
2635 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2636 InputContext->EP[Dci-1].PtrLo = PhyAddr;
2637 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2638
2639 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2640 }
2641 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2642 }
2643
2644 InputContext->InputControlContext.Dword2 |= BIT0;
2645 InputContext->Slot.ContextEntries = MaxDci;
2646 //
2647 // configure endpoint
2648 //
2649 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2650 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2651 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2652 CmdTrbCfgEP.CycleBit = 1;
2653 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2654 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2655 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2656 Status = XhcCmdTransfer (
2657 Xhc,
2658 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2659 XHC_GENERIC_TIMEOUT,
2660 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2661 );
2662 ASSERT_EFI_ERROR(Status);
2663
2664 return Status;
2665 }
2666
2667
2668 /**
2669 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2670
2671 @param Xhc The XHCI Instance.
2672 @param SlotId The slot id to be evaluated.
2673 @param MaxPacketSize The max packet size supported by the device control transfer.
2674
2675 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2676
2677 **/
2678 EFI_STATUS
2679 EFIAPI
2680 XhcEvaluateContext (
2681 IN USB_XHCI_INSTANCE *Xhc,
2682 IN UINT8 SlotId,
2683 IN UINT32 MaxPacketSize
2684 )
2685 {
2686 EFI_STATUS Status;
2687 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2688 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2689 INPUT_CONTEXT *InputContext;
2690
2691 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2692
2693 //
2694 // 4.6.7 Evaluate Context
2695 //
2696 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2697 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2698
2699 InputContext->InputControlContext.Dword2 |= BIT1;
2700 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2701
2702 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2703 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);
2704 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);
2705 CmdTrbEvalu.CycleBit = 1;
2706 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2707 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2708 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
2709 Status = XhcCmdTransfer (
2710 Xhc,
2711 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2712 XHC_GENERIC_TIMEOUT,
2713 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2714 );
2715 ASSERT (!EFI_ERROR(Status));
2716
2717 return Status;
2718 }
2719
2720 /**
2721 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2722
2723 @param Xhc The XHCI Instance.
2724 @param SlotId The slot id to be evaluated.
2725 @param MaxPacketSize The max packet size supported by the device control transfer.
2726
2727 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2728
2729 **/
2730 EFI_STATUS
2731 EFIAPI
2732 XhcEvaluateContext64 (
2733 IN USB_XHCI_INSTANCE *Xhc,
2734 IN UINT8 SlotId,
2735 IN UINT32 MaxPacketSize
2736 )
2737 {
2738 EFI_STATUS Status;
2739 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2740 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2741 INPUT_CONTEXT_64 *InputContext;
2742
2743 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2744
2745 //
2746 // 4.6.7 Evaluate Context
2747 //
2748 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2749 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2750
2751 InputContext->InputControlContext.Dword2 |= BIT1;
2752 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2753
2754 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2755 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);
2756 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);
2757 CmdTrbEvalu.CycleBit = 1;
2758 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2759 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2760 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
2761 Status = XhcCmdTransfer (
2762 Xhc,
2763 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2764 XHC_GENERIC_TIMEOUT,
2765 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2766 );
2767 ASSERT (!EFI_ERROR(Status));
2768
2769 return Status;
2770 }
2771
2772
2773 /**
2774 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2775
2776 @param Xhc The XHCI Instance.
2777 @param SlotId The slot id to be configured.
2778 @param PortNum The total number of downstream port supported by the hub.
2779 @param TTT The TT think time of the hub device.
2780 @param MTT The multi-TT of the hub device.
2781
2782 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2783
2784 **/
2785 EFI_STATUS
2786 XhcConfigHubContext (
2787 IN USB_XHCI_INSTANCE *Xhc,
2788 IN UINT8 SlotId,
2789 IN UINT8 PortNum,
2790 IN UINT8 TTT,
2791 IN UINT8 MTT
2792 )
2793 {
2794 EFI_STATUS Status;
2795
2796 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2797 INPUT_CONTEXT *InputContext;
2798 DEVICE_CONTEXT *OutputContext;
2799 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2800
2801 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2802 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2803 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2804
2805 //
2806 // 4.6.7 Evaluate Context
2807 //
2808 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2809
2810 InputContext->InputControlContext.Dword2 |= BIT0;
2811
2812 //
2813 // Copy the slot context from OutputContext to Input context
2814 //
2815 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
2816 InputContext->Slot.Hub = 1;
2817 InputContext->Slot.PortNum = PortNum;
2818 InputContext->Slot.TTT = TTT;
2819 InputContext->Slot.MTT = MTT;
2820
2821 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2822 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2823 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2824 CmdTrbCfgEP.CycleBit = 1;
2825 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2826 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2827 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2828 Status = XhcCmdTransfer (
2829 Xhc,
2830 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2831 XHC_GENERIC_TIMEOUT,
2832 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2833 );
2834 ASSERT (!EFI_ERROR(Status));
2835
2836 return Status;
2837 }
2838
2839 /**
2840 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2841
2842 @param Xhc The XHCI Instance.
2843 @param SlotId The slot id to be configured.
2844 @param PortNum The total number of downstream port supported by the hub.
2845 @param TTT The TT think time of the hub device.
2846 @param MTT The multi-TT of the hub device.
2847
2848 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2849
2850 **/
2851 EFI_STATUS
2852 XhcConfigHubContext64 (
2853 IN USB_XHCI_INSTANCE *Xhc,
2854 IN UINT8 SlotId,
2855 IN UINT8 PortNum,
2856 IN UINT8 TTT,
2857 IN UINT8 MTT
2858 )
2859 {
2860 EFI_STATUS Status;
2861
2862 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2863 INPUT_CONTEXT_64 *InputContext;
2864 DEVICE_CONTEXT_64 *OutputContext;
2865 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2866
2867 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2868 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2869 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2870
2871 //
2872 // 4.6.7 Evaluate Context
2873 //
2874 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2875
2876 InputContext->InputControlContext.Dword2 |= BIT0;
2877
2878 //
2879 // Copy the slot context from OutputContext to Input context
2880 //
2881 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
2882 InputContext->Slot.Hub = 1;
2883 InputContext->Slot.PortNum = PortNum;
2884 InputContext->Slot.TTT = TTT;
2885 InputContext->Slot.MTT = MTT;
2886
2887 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2888 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2889 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2890 CmdTrbCfgEP.CycleBit = 1;
2891 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2892 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2893 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2894 Status = XhcCmdTransfer (
2895 Xhc,
2896 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2897 XHC_GENERIC_TIMEOUT,
2898 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2899 );
2900 ASSERT (!EFI_ERROR(Status));
2901
2902 return Status;
2903 }
2904
2905