]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg: Remove variables that are set, but not used
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
1 /** @file
2
3 XHCI transfer scheduling routines.
4
5 Copyright (c) 2011, 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->CmdEventRing;
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->CmdEventRing);
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 DevAddr The device address
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 DevAddr,
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->DevAddr = DevAddr;
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 DEVICE_CONTEXT *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 = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);
215 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
216 ASSERT (Dci < 32);
217 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
218 Urb->Ring = EPRing;
219 OutputContext = (DEVICE_CONTEXT *)(UINTN) Xhc->DCBAA[SlotId];
220 EPType = (UINT8) OutputContext->EP[Dci-1].EPType;
221
222 //
223 // Construct the TRB
224 //
225 XhcSyncTrsRing (Xhc, EPRing);
226 Urb->TrbStart = EPRing->RingEnqueue;
227 switch (EPType) {
228 case ED_CONTROL_BIDIR:
229 Urb->EvtRing = &Xhc->CtrlTrEventRing;
230 XhcSyncEventRing (Xhc, Urb->EvtRing);
231 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
232 //
233 // For control transfer, create SETUP_STAGE_TRB first.
234 //
235 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
236 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
237 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;
238 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;
239 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;
240 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;
241 TrbStart->TrbCtrSetup.Lenth = 8;
242 TrbStart->TrbCtrSetup.IntTarget = Urb->EvtRing->EventInterrupter;
243 TrbStart->TrbCtrSetup.IOC = 1;
244 TrbStart->TrbCtrSetup.IDT = 1;
245 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;
246 if (Urb->Ep.Direction == EfiUsbDataIn) {
247 TrbStart->TrbCtrSetup.TRT = 3;
248 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
249 TrbStart->TrbCtrSetup.TRT = 2;
250 } else {
251 TrbStart->TrbCtrSetup.TRT = 0;
252 }
253 //
254 // Update the cycle bit
255 //
256 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
257 Urb->TrbNum++;
258
259 //
260 // For control transfer, create DATA_STAGE_TRB.
261 //
262 if (Urb->DataLen > 0) {
263 XhcSyncTrsRing (Xhc, EPRing);
264 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
265 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->Data);
266 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data);
267 TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;
268 TrbStart->TrbCtrData.TDSize = 0;
269 TrbStart->TrbCtrData.IntTarget = Urb->EvtRing->EventInterrupter;
270 TrbStart->TrbCtrData.ISP = 1;
271 TrbStart->TrbCtrData.IOC = 1;
272 TrbStart->TrbCtrData.IDT = 0;
273 TrbStart->TrbCtrData.CH = 0;
274 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;
275 if (Urb->Ep.Direction == EfiUsbDataIn) {
276 TrbStart->TrbCtrData.DIR = 1;
277 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
278 TrbStart->TrbCtrData.DIR = 0;
279 } else {
280 TrbStart->TrbCtrData.DIR = 0;
281 }
282 //
283 // Update the cycle bit
284 //
285 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
286 Urb->TrbNum++;
287 }
288 //
289 // For control transfer, create STATUS_STAGE_TRB.
290 // Get the pointer to next TRB for status stage use
291 //
292 XhcSyncTrsRing (Xhc, EPRing);
293 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
294 TrbStart->TrbCtrStatus.IntTarget = Urb->EvtRing->EventInterrupter;
295 TrbStart->TrbCtrStatus.IOC = 1;
296 TrbStart->TrbCtrStatus.CH = 0;
297 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;
298 if (Urb->Ep.Direction == EfiUsbDataIn) {
299 TrbStart->TrbCtrStatus.DIR = 0;
300 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
301 TrbStart->TrbCtrStatus.DIR = 1;
302 } else {
303 TrbStart->TrbCtrStatus.DIR = 0;
304 }
305 //
306 // Update the cycle bit
307 //
308 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
309 //
310 // Update the enqueue pointer
311 //
312 XhcSyncTrsRing (Xhc, EPRing);
313 Urb->TrbNum++;
314 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
315
316 break;
317
318 case ED_BULK_OUT:
319 case ED_BULK_IN:
320 Urb->EvtRing = &Xhc->BulkTrEventRing;
321 XhcSyncEventRing (Xhc, Urb->EvtRing);
322 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
323
324 TotalLen = 0;
325 Len = 0;
326 TrbNum = 0;
327 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
328 while (TotalLen < Urb->DataLen) {
329 if ((TotalLen + 0x10000) >= Urb->DataLen) {
330 Len = Urb->DataLen - TotalLen;
331 } else {
332 Len = 0x10000;
333 }
334 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
335 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);
336 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);
337 TrbStart->TrbNormal.Lenth = (UINT32) Len;
338 TrbStart->TrbNormal.TDSize = 0;
339 TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter;
340 TrbStart->TrbNormal.ISP = 1;
341 TrbStart->TrbNormal.IOC = 1;
342 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
343 //
344 // Update the cycle bit
345 //
346 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
347
348 XhcSyncTrsRing (Xhc, EPRing);
349 TrbNum++;
350 TotalLen += Len;
351 }
352
353 Urb->TrbNum = TrbNum;
354 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
355 break;
356
357 case ED_INTERRUPT_OUT:
358 case ED_INTERRUPT_IN:
359 if (Urb->Ep.Type == XHC_INT_TRANSFER_ASYNC) {
360 Urb->EvtRing = &Xhc->AsynIntTrEventRing;
361 } else if(Urb->Ep.Type == XHC_INT_TRANSFER_SYNC){
362 Urb->EvtRing = &Xhc->IntTrEventRing;
363 } else {
364 DEBUG ((EFI_D_ERROR, "EP Interrupt type error!\n"));
365 ASSERT(FALSE);
366 }
367 XhcSyncEventRing (Xhc, Urb->EvtRing);
368 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
369
370 TotalLen = 0;
371 Len = 0;
372 TrbNum = 0;
373 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
374 while (TotalLen < Urb->DataLen) {
375 if ((TotalLen + 0x10000) >= Urb->DataLen) {
376 Len = Urb->DataLen - TotalLen;
377 } else {
378 Len = 0x10000;
379 }
380 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
381 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);
382 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);
383 TrbStart->TrbNormal.Lenth = (UINT32) Len;
384 TrbStart->TrbNormal.TDSize = 0;
385 TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter;
386 TrbStart->TrbNormal.ISP = 1;
387 TrbStart->TrbNormal.IOC = 1;
388 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
389 //
390 // Update the cycle bit
391 //
392 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
393
394 XhcSyncTrsRing (Xhc, EPRing);
395 TrbNum++;
396 TotalLen += Len;
397 }
398
399 Urb->TrbNum = TrbNum;
400 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
401 break;
402
403 default:
404 DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
405 ASSERT (FALSE);
406 break;
407 }
408
409 return EFI_SUCCESS;
410 }
411
412
413 /**
414 Initialize the XHCI host controller for schedule.
415
416 @param Xhc The XHCI Instance to be initialized.
417
418 **/
419 VOID
420 XhcInitSched (
421 IN USB_XHCI_INSTANCE *Xhc
422 )
423 {
424 VOID *Dcbaa;
425 UINT64 CmdRing;
426 UINTN Entries;
427 UINT32 MaxScratchpadBufs;
428 UINT64 *ScratchBuf;
429 UINT64 *ScratchEntryBuf;
430 UINT32 Index;
431
432 //
433 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
434 // to enable the device slots that system software is going to use.
435 //
436 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
437 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
438 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);
439
440 //
441 // The Device Context Base Address Array entry associated with each allocated Device Slot
442 // shall contain a 64-bit pointer to the base of the associated Device Context.
443 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
444 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
445 //
446 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);
447 Dcbaa = AllocatePages (EFI_SIZE_TO_PAGES (Entries));
448 ASSERT (Dcbaa != NULL);
449 ZeroMem (Dcbaa, Entries);
450
451 //
452 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
453 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
454 // mode (Run/Stop(R/S) ='1').
455 //
456 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
457 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
458 ASSERT (MaxScratchpadBufs <= 1023);
459 if (MaxScratchpadBufs != 0) {
460 ScratchBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)), Xhc->PageSize);
461 ASSERT (ScratchBuf != NULL);
462 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
463 Xhc->ScratchBuf = ScratchBuf;
464
465 for (Index = 0; Index < MaxScratchpadBufs; Index++) {
466 ScratchEntryBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc->PageSize), Xhc->PageSize);
467 ASSERT (ScratchEntryBuf != NULL);
468 ZeroMem (ScratchEntryBuf, Xhc->PageSize);
469 *ScratchBuf++ = (UINT64)(UINTN)ScratchEntryBuf;
470 }
471
472 //
473 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
474 // Device Context Base Address Array points to the Scratchpad Buffer Array.
475 //
476 *(UINT64 *)Dcbaa = (UINT64)(UINTN)Xhc->ScratchBuf;
477 }
478
479 //
480 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
481 // a 64-bit address pointing to where the Device Context Base Address Array is located.
482 //
483 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;
484 XhcWriteOpReg64 (Xhc, XHC_DCBAAP_OFFSET, (UINT64)(UINTN)Xhc->DCBAA);
485 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));
486
487 //
488 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
489 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
490 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
491 // always be '0'.
492 //
493 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
494 //
495 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
496 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
497 // So we set RCS as inverted PCS init value to let Command Ring empty
498 //
499 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;
500 ASSERT ((CmdRing & 0x3F) == 0);
501 CmdRing |= XHC_CRCR_RCS;
502 XhcWriteOpReg64 (Xhc, XHC_CRCR_OFFSET, 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, CMD_INTER, &Xhc->CmdEventRing);
520 CreateEventRing (Xhc, CTRL_INTER, &Xhc->CtrlTrEventRing);
521 CreateEventRing (Xhc, BULK_INTER, &Xhc->BulkTrEventRing);
522 CreateEventRing (Xhc, INT_INTER, &Xhc->IntTrEventRing);
523 CreateEventRing (Xhc, INT_INTER_ASYNC, &Xhc->AsynIntTrEventRing);
524 }
525
526 /**
527 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
528 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
529 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
530 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
531 Stopped to the Running state.
532
533 @param Xhc The XHCI Instance.
534 @param Urb The urb which makes the endpoint halted.
535
536 @retval EFI_SUCCESS The recovery is successful.
537 @retval Others Failed to recovery halted endpoint.
538
539 **/
540 EFI_STATUS
541 EFIAPI
542 XhcRecoverHaltedEndpoint (
543 IN USB_XHCI_INSTANCE *Xhc,
544 IN URB *Urb
545 )
546 {
547 EFI_STATUS Status;
548 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
549 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
550 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
551 UINT8 Dci;
552 UINT8 SlotId;
553
554 Status = EFI_SUCCESS;
555 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);
556 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
557
558 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));
559
560 //
561 // 1) Send Reset endpoint command to transit from halt to stop state
562 //
563 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
564 CmdTrbResetED.CycleBit = 1;
565 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
566 CmdTrbResetED.EDID = Dci;
567 CmdTrbResetED.SlotId = SlotId;
568 Status = XhcCmdTransfer (
569 Xhc,
570 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
571 XHC_GENERIC_TIMEOUT,
572 (TRB_TEMPLATE **) (UINTN) &EvtTrb
573 );
574 ASSERT (!EFI_ERROR(Status));
575
576 //
577 // 2)Set dequeue pointer
578 //
579 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
580 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (Urb->Ring->RingEnqueue) | Urb->Ring->RingPCS;
581 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (Urb->Ring->RingEnqueue);
582 CmdSetTRDeq.CycleBit = 1;
583 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
584 CmdSetTRDeq.Endpoint = Dci;
585 CmdSetTRDeq.SlotId = SlotId;
586 Status = XhcCmdTransfer (
587 Xhc,
588 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
589 XHC_GENERIC_TIMEOUT,
590 (TRB_TEMPLATE **) (UINTN) &EvtTrb
591 );
592 ASSERT (!EFI_ERROR(Status));
593
594 //
595 // 3)Ring the doorbell to transit from stop to active
596 //
597 XhcRingDoorBell (Xhc, SlotId, Dci);
598
599 return Status;
600 }
601
602 /**
603 Create XHCI event ring.
604
605 @param Xhc The XHCI Instance.
606 @param EventInterrupter The interrupter of event.
607 @param EventRing The created event ring.
608
609 **/
610 VOID
611 CreateEventRing (
612 IN USB_XHCI_INSTANCE *Xhc,
613 IN UINT8 EventInterrupter,
614 OUT EVENT_RING *EventRing
615 )
616 {
617 VOID *Buf;
618 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
619
620 ASSERT (EventRing != NULL);
621
622 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));
623 ASSERT (Buf != NULL);
624 ASSERT (((UINTN) Buf & 0x3F) == 0);
625 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
626
627 EventRing->EventRingSeg0 = Buf;
628 EventRing->EventInterrupter = EventInterrupter;
629 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
630 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
631 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
632 //
633 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
634 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
635 //
636 EventRing->EventRingCCS = 1;
637
638 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));
639 ASSERT (Buf != NULL);
640 ASSERT (((UINTN) Buf & 0x3F) == 0);
641 ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
642
643 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
644 EventRing->ERSTBase = ERSTBase;
645 ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
646 ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
647 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
648
649 //
650 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
651 //
652 XhcWriteRuntimeReg (
653 Xhc,
654 XHC_ERSTSZ_OFFSET + (32 * EventRing->EventInterrupter),
655 ERST_NUMBER
656 );
657 //
658 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
659 //
660 XhcWriteRuntimeReg64 (
661 Xhc,
662 XHC_ERDP_OFFSET + (32 * EventRing->EventInterrupter),
663 (UINT64)(UINTN)EventRing->EventRingDequeue
664 );
665 //
666 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
667 //
668 XhcWriteRuntimeReg64 (
669 Xhc,
670 XHC_ERSTBA_OFFSET + (32 * EventRing->EventInterrupter),
671 (UINT64)(UINTN)ERSTBase
672 );
673 //
674 // Need set IMAN IE bit to enble the ring interrupt
675 //
676 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (32 * EventRing->EventInterrupter), XHC_IMAN_IE);
677 }
678
679 /**
680 Create XHCI transfer ring.
681
682 @param Xhc The XHCI Instance.
683 @param TrbNum The number of TRB in the ring.
684 @param TransferRing The created transfer ring.
685
686 **/
687 VOID
688 CreateTransferRing (
689 IN USB_XHCI_INSTANCE *Xhc,
690 IN UINTN TrbNum,
691 OUT TRANSFER_RING *TransferRing
692 )
693 {
694 VOID *Buf;
695 LINK_TRB *EndTrb;
696
697 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TrbNum));
698 ASSERT (Buf != NULL);
699 ASSERT (((UINTN) Buf & 0x3F) == 0);
700 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
701
702 TransferRing->RingSeg0 = Buf;
703 TransferRing->TrbNumber = TrbNum;
704 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
705 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
706 TransferRing->RingPCS = 1;
707 //
708 // 4.9.2 Transfer Ring Management
709 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
710 // point to the first TRB in the ring.
711 //
712 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
713 EndTrb->Type = TRB_TYPE_LINK;
714 EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
715 EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
716 //
717 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
718 //
719 EndTrb->TC = 1;
720 //
721 // Set Cycle bit as other TRB PCS init value
722 //
723 EndTrb->CycleBit = 0;
724 }
725
726 /**
727 Free XHCI event ring.
728
729 @param Xhc The XHCI Instance.
730 @param EventRing The event ring to be freed.
731
732 **/
733 EFI_STATUS
734 EFIAPI
735 XhcFreeEventRing (
736 IN USB_XHCI_INSTANCE *Xhc,
737 IN EVENT_RING *EventRing
738 )
739 {
740 UINT8 Index;
741 EVENT_RING_SEG_TABLE_ENTRY *TablePtr;
742 VOID *RingBuf;
743 EVENT_RING_SEG_TABLE_ENTRY *EventRingPtr;
744
745 if(EventRing->EventRingSeg0 == NULL) {
746 return EFI_SUCCESS;
747 }
748
749 //
750 // Get the Event Ring Segment Table base address
751 //
752 TablePtr = (EVENT_RING_SEG_TABLE_ENTRY *)(EventRing->ERSTBase);
753
754 //
755 // Get all the TRBs Ring and release
756 //
757 for (Index = 0; Index < ERST_NUMBER; Index++) {
758 EventRingPtr = TablePtr + Index;
759 RingBuf = (VOID *)(UINTN)(EventRingPtr->PtrLo | ((UINT64)EventRingPtr->PtrHi << 32));
760
761 if(RingBuf != NULL) {
762 FreePages (RingBuf, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));
763 ZeroMem (EventRingPtr, sizeof (EVENT_RING_SEG_TABLE_ENTRY));
764 }
765 }
766
767 FreePages (TablePtr, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));
768 return EFI_SUCCESS;
769 }
770
771 /**
772 Free the resouce allocated at initializing schedule.
773
774 @param Xhc The XHCI Instance.
775
776 **/
777 VOID
778 XhcFreeSched (
779 IN USB_XHCI_INSTANCE *Xhc
780 )
781 {
782 UINT32 Index;
783 UINT64 *ScratchBuf;
784
785 if (Xhc->ScratchBuf != NULL) {
786 ScratchBuf = Xhc->ScratchBuf;
787 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
788 FreeAlignedPages ((VOID*)(UINTN)*ScratchBuf++, EFI_SIZE_TO_PAGES (Xhc->PageSize));
789 }
790 FreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));
791 }
792
793 if (Xhc->DCBAA != NULL) {
794 FreePages (Xhc->DCBAA, EFI_SIZE_TO_PAGES((Xhc->MaxSlotsEn + 1) * sizeof(UINT64)));
795 Xhc->DCBAA = NULL;
796 }
797
798 if (Xhc->CmdRing.RingSeg0 != NULL){
799 FreePages (Xhc->CmdRing.RingSeg0, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER));
800 Xhc->CmdRing.RingSeg0 = NULL;
801 }
802
803 XhcFreeEventRing (Xhc,&Xhc->CmdEventRing);
804 XhcFreeEventRing (Xhc,&Xhc->CtrlTrEventRing);
805 XhcFreeEventRing (Xhc,&Xhc->BulkTrEventRing);
806 XhcFreeEventRing (Xhc,&Xhc->AsynIntTrEventRing);
807 XhcFreeEventRing (Xhc,&Xhc->IntTrEventRing);
808 }
809
810 /**
811 Check if it is ring TRB.
812
813 @param Ring The transfer ring
814 @param Trb The TRB to check if it's in the transfer ring
815
816 @retval TRUE It is in the ring
817 @retval FALSE It is not in the ring
818
819 **/
820 BOOLEAN
821 IsTransferRingTrb (
822 IN TRANSFER_RING *Ring,
823 IN TRB_TEMPLATE *Trb
824 )
825 {
826 BOOLEAN Flag;
827 TRB_TEMPLATE *Trb1;
828 UINTN Index;
829
830 Trb1 = Ring->RingSeg0;
831 Flag = FALSE;
832
833 ASSERT (Ring->TrbNumber == CMD_RING_TRB_NUMBER || Ring->TrbNumber == TR_RING_TRB_NUMBER);
834
835 for (Index = 0; Index < Ring->TrbNumber; Index++) {
836 if (Trb == Trb1) {
837 Flag = TRUE;
838 break;
839 }
840 Trb1++;
841 }
842
843 return Flag;
844 }
845
846 /**
847 Check the URB's execution result and update the URB's
848 result accordingly.
849
850 @param Xhc The XHCI Instance.
851 @param Urb The URB to check result.
852
853 @return Whether the result of URB transfer is finialized.
854
855 **/
856 EFI_STATUS
857 XhcCheckUrbResult (
858 IN USB_XHCI_INSTANCE *Xhc,
859 IN URB *Urb
860 )
861 {
862 BOOLEAN StartDone;
863 BOOLEAN EndDone;
864 EVT_TRB_TRANSFER *EvtTrb;
865 TRB_TEMPLATE *TRBPtr;
866 UINTN Index;
867 UINT8 TRBType;
868 EFI_STATUS Status;
869
870 ASSERT ((Xhc != NULL) && (Urb != NULL));
871
872 Urb->Completed = 0;
873 Urb->Result = EFI_USB_NOERROR;
874 Status = EFI_SUCCESS;
875 EvtTrb = NULL;
876
877 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
878 Urb->Result |= EFI_USB_ERR_SYSTEM;
879 Status = EFI_DEVICE_ERROR;
880 goto EXIT;
881 }
882
883 //
884 // Restore the EventRingDequeue and poll the transfer event ring from beginning
885 //
886 StartDone = FALSE;
887 EndDone = FALSE;
888 Urb->EvtRing->EventRingDequeue = Urb->EvtTrbStart;
889 for (Index = 0; Index < Urb->EvtRing->TrbNumber; Index++) {
890 XhcSyncEventRing (Xhc, Urb->EvtRing);
891 Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, ((TRB_TEMPLATE **)&EvtTrb));
892 if (Status == EFI_NOT_READY) {
893 Urb->Result |= EFI_USB_ERR_TIMEOUT;
894 goto EXIT;
895 }
896
897 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | (UINT64) EvtTrb->TRBPtrHi << 32);
898
899 switch (EvtTrb->Completecode) {
900 case TRB_COMPLETION_STALL_ERROR:
901 Urb->Result |= EFI_USB_ERR_STALL;
902 Status = EFI_DEVICE_ERROR;
903 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
904 goto EXIT;
905 break;
906
907 case TRB_COMPLETION_BABBLE_ERROR:
908 Urb->Result |= EFI_USB_ERR_BABBLE;
909 Status = EFI_DEVICE_ERROR;
910 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
911 goto EXIT;
912 break;
913
914 case TRB_COMPLETION_DATA_BUFFER_ERROR:
915 Urb->Result |= EFI_USB_ERR_BUFFER;
916 Status = EFI_DEVICE_ERROR;
917 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
918 goto EXIT;
919 break;
920
921 case TRB_COMPLETION_USB_TRANSACTION_ERROR:
922 Urb->Result |= EFI_USB_ERR_TIMEOUT;
923 Status = EFI_DEVICE_ERROR;
924 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
925 goto EXIT;
926 break;
927
928 case TRB_COMPLETION_SHORT_PACKET:
929 case TRB_COMPLETION_SUCCESS:
930 if (IsTransferRingTrb (Urb->Ring, TRBPtr)) {
931 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
932 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));
933 }
934 TRBType = (UINT8) (TRBPtr->Type);
935 if ((TRBType == TRB_TYPE_DATA_STAGE) ||
936 (TRBType == TRB_TYPE_NORMAL) ||
937 (TRBType == TRB_TYPE_ISOCH)) {
938 Urb->Completed += (Urb->DataLen - EvtTrb->Lenth);
939 }
940 }
941 Status = EFI_SUCCESS;
942 break;
943
944 default:
945 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
946 Urb->Result |= EFI_USB_ERR_TIMEOUT;
947 Status = EFI_DEVICE_ERROR;
948 goto EXIT;
949 break;
950 }
951
952 //
953 // Only check first and end Trb event address
954 //
955 if (TRBPtr == Urb->TrbStart) {
956 StartDone = TRUE;
957 }
958
959 if (TRBPtr == Urb->TrbEnd) {
960 EndDone = TRUE;
961 }
962
963 if (StartDone && EndDone) {
964 break;
965 }
966 }
967
968 EXIT:
969 return Status;
970 }
971
972
973 /**
974 Execute the transfer by polling the URB. This is a synchronous operation.
975
976 @param Xhc The XHCI Instance.
977 @param CmdTransfer The executed URB is for cmd transfer or not.
978 @param Urb The URB to execute.
979 @param Timeout The time to wait before abort, in millisecond.
980
981 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
982 @return EFI_TIMEOUT The transfer failed due to time out.
983 @return EFI_SUCCESS The transfer finished OK.
984
985 **/
986 EFI_STATUS
987 XhcExecTransfer (
988 IN USB_XHCI_INSTANCE *Xhc,
989 IN BOOLEAN CmdTransfer,
990 IN URB *Urb,
991 IN UINTN Timeout
992 )
993 {
994 EFI_STATUS Status;
995 UINTN Index;
996 UINTN Loop;
997 UINT8 SlotId;
998 UINT8 Dci;
999
1000 if (CmdTransfer) {
1001 SlotId = 0;
1002 Dci = 0;
1003 } else {
1004 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);
1005 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1006 }
1007
1008 Status = EFI_SUCCESS;
1009 Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;
1010 if (Timeout == 0) {
1011 Loop = 0xFFFFFFFF;
1012 }
1013
1014 XhcRingDoorBell (Xhc, SlotId, Dci);
1015
1016 for (Index = 0; Index < Loop; Index++) {
1017 Status = XhcCheckUrbResult (Xhc, Urb);
1018 if ((Status != EFI_NOT_READY)) {
1019 break;
1020 }
1021 gBS->Stall (XHC_POLL_DELAY);
1022 }
1023
1024 return Status;
1025 }
1026
1027 /**
1028 Delete a single asynchronous interrupt transfer for
1029 the device and endpoint.
1030
1031 @param Xhc The XHCI Instance.
1032 @param DevAddr The address of the target device.
1033 @param EpNum The endpoint of the target.
1034
1035 @retval EFI_SUCCESS An asynchronous transfer is removed.
1036 @retval EFI_NOT_FOUND No transfer for the device is found.
1037
1038 **/
1039 EFI_STATUS
1040 XhciDelAsyncIntTransfer (
1041 IN USB_XHCI_INSTANCE *Xhc,
1042 IN UINT8 DevAddr,
1043 IN UINT8 EpNum
1044 )
1045 {
1046 LIST_ENTRY *Entry;
1047 LIST_ENTRY *Next;
1048 URB *Urb;
1049 EFI_USB_DATA_DIRECTION Direction;
1050
1051 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
1052 EpNum &= 0x0F;
1053
1054 Urb = NULL;
1055
1056 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1057 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1058 if ((Urb->Ep.DevAddr == DevAddr) &&
1059 (Urb->Ep.EpAddr == EpNum) &&
1060 (Urb->Ep.Direction == Direction)) {
1061 RemoveEntryList (&Urb->UrbList);
1062 FreePool (Urb->Data);
1063 FreePool (Urb);
1064 return EFI_SUCCESS;
1065 }
1066 }
1067
1068 return EFI_NOT_FOUND;
1069 }
1070
1071 /**
1072 Remove all the asynchronous interrutp transfers.
1073
1074 @param Xhc The XHCI Instance.
1075
1076 **/
1077 VOID
1078 XhciDelAllAsyncIntTransfers (
1079 IN USB_XHCI_INSTANCE *Xhc
1080 )
1081 {
1082 LIST_ENTRY *Entry;
1083 LIST_ENTRY *Next;
1084 URB *Urb;
1085
1086 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1087 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1088 RemoveEntryList (&Urb->UrbList);
1089 FreePool (Urb->Data);
1090 FreePool (Urb);
1091 }
1092 }
1093
1094 /**
1095 Update the queue head for next round of asynchronous transfer
1096
1097 @param Xhc The XHCI Instance.
1098 @param Urb The URB to update
1099
1100 **/
1101 VOID
1102 XhcUpdateAsyncRequest (
1103 IN USB_XHCI_INSTANCE *Xhc,
1104 IN URB *Urb
1105 )
1106 {
1107 EFI_STATUS Status;
1108
1109 if (Urb->Result == EFI_USB_NOERROR) {
1110 Status = XhcCreateTransferTrb (Xhc, Urb);
1111 ASSERT_EFI_ERROR (Status);
1112 Status = RingIntTransferDoorBell (Xhc, Urb);
1113 ASSERT_EFI_ERROR (Status);
1114 }
1115 }
1116
1117
1118 /**
1119 Interrupt transfer periodic check handler.
1120
1121 @param Event Interrupt event.
1122 @param Context Pointer to USB_XHCI_INSTANCE.
1123
1124 **/
1125 VOID
1126 EFIAPI
1127 XhcMonitorAsyncRequests (
1128 IN EFI_EVENT Event,
1129 IN VOID *Context
1130 )
1131 {
1132 USB_XHCI_INSTANCE *Xhc;
1133 LIST_ENTRY *Entry;
1134 LIST_ENTRY *Next;
1135 UINT8 *ProcBuf;
1136 URB *Urb;
1137 UINT8 SlotId;
1138 EFI_STATUS Status;
1139 EFI_TPL OldTpl;
1140
1141 OldTpl = gBS->RaiseTPL (XHC_TPL);
1142
1143 Xhc = (USB_XHCI_INSTANCE*) Context;
1144
1145 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1146 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1147
1148 //
1149 // Make sure that the device is available before every check.
1150 //
1151 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);
1152 if (SlotId == 0) {
1153 continue;
1154 }
1155
1156 //
1157 // Check the result of URB execution. If it is still
1158 // active, check the next one.
1159 //
1160 Status = XhcCheckUrbResult (Xhc, Urb);
1161
1162 if (Status == EFI_NOT_READY) {
1163 continue;
1164 }
1165
1166 //
1167 // Allocate a buffer then copy the transferred data for user.
1168 // If failed to allocate the buffer, update the URB for next
1169 // round of transfer. Ignore the data of this round.
1170 //
1171 ProcBuf = NULL;
1172 if (Urb->Result == EFI_USB_NOERROR) {
1173 ASSERT (Urb->Completed <= Urb->DataLen);
1174
1175 ProcBuf = AllocateZeroPool (Urb->Completed);
1176
1177 if (ProcBuf == NULL) {
1178 XhcUpdateAsyncRequest (Xhc, Urb);
1179 continue;
1180 }
1181
1182 CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1183 }
1184
1185 XhcUpdateAsyncRequest (Xhc, Urb);
1186
1187 //
1188 // Leave error recovery to its related device driver. A
1189 // common case of the error recovery is to re-submit the
1190 // interrupt transfer which is linked to the head of the
1191 // list. This function scans from head to tail. So the
1192 // re-submitted interrupt transfer's callback function
1193 // will not be called again in this round. Don't touch this
1194 // URB after the callback, it may have been removed by the
1195 // callback.
1196 //
1197 if (Urb->Callback != NULL) {
1198 //
1199 // Restore the old TPL, USB bus maybe connect device in
1200 // his callback. Some drivers may has a lower TPL restriction.
1201 //
1202 gBS->RestoreTPL (OldTpl);
1203 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1204 OldTpl = gBS->RaiseTPL (XHC_TPL);
1205 }
1206
1207 if (ProcBuf != NULL) {
1208 gBS->FreePool (ProcBuf);
1209 }
1210 }
1211 gBS->RestoreTPL (OldTpl);
1212 }
1213
1214 /**
1215 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1216
1217 @param Xhc The XHCI Instance.
1218 @param ParentRouteChart The route string pointed to the parent device if it exists.
1219 @param Port The port to be polled.
1220 @param PortState The port state.
1221
1222 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1223 @retval Others Should not appear.
1224
1225 **/
1226 EFI_STATUS
1227 EFIAPI
1228 XhcPollPortStatusChange (
1229 IN USB_XHCI_INSTANCE *Xhc,
1230 IN USB_DEV_ROUTE ParentRouteChart,
1231 IN UINT8 Port,
1232 IN EFI_USB_PORT_STATUS *PortState
1233 )
1234 {
1235 EFI_STATUS Status;
1236 UINT8 Speed;
1237 UINT8 SlotId;
1238 USB_DEV_ROUTE RouteChart;
1239
1240 Status = EFI_SUCCESS;
1241
1242 if (ParentRouteChart.Dword == 0) {
1243 RouteChart.Route.RouteString = 0;
1244 RouteChart.Route.RootPortNum = Port + 1;
1245 RouteChart.Route.TierNum = 1;
1246 } else {
1247 if(Port < 14) {
1248 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
1249 } else {
1250 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
1251 }
1252 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
1253 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
1254 }
1255
1256 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
1257 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
1258 //
1259 // Has a device attached, Identify device speed after port is enabled.
1260 //
1261 Speed = EFI_USB_SPEED_FULL;
1262 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
1263 Speed = EFI_USB_SPEED_LOW;
1264 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
1265 Speed = EFI_USB_SPEED_HIGH;
1266 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
1267 Speed = EFI_USB_SPEED_SUPER;
1268 }
1269 //
1270 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1271 //
1272 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1273 if (SlotId == 0) {
1274 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1275 ASSERT_EFI_ERROR (Status);
1276 }
1277 } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {
1278 //
1279 // Device is detached. Disable the allocated device slot and release resource.
1280 //
1281 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1282 if (SlotId != 0) {
1283 Status = XhcDisableSlotCmd (Xhc, SlotId);
1284 ASSERT_EFI_ERROR (Status);
1285 }
1286 }
1287 return Status;
1288 }
1289
1290
1291 /**
1292 Calculate the device context index by endpoint address and direction.
1293
1294 @param EpAddr The target endpoint number.
1295 @param Direction The direction of the target endpoint.
1296
1297 @return The device context index of endpoint.
1298
1299 **/
1300 UINT8
1301 XhcEndpointToDci (
1302 IN UINT8 EpAddr,
1303 IN UINT8 Direction
1304 )
1305 {
1306 UINT8 Index;
1307
1308 if (EpAddr == 0) {
1309 return 1;
1310 } else {
1311 Index = (UINT8) (2 * EpAddr);
1312 if (Direction == EfiUsbDataIn) {
1313 Index += 1;
1314 }
1315 return Index;
1316 }
1317 }
1318
1319 /**
1320 Find out the slot id according to device address assigned by XHCI's Address_Device cmd.
1321
1322 @param Xhc The XHCI Instance.
1323 @param DevAddr The device address of the target device.
1324
1325 @return The slot id used by the device.
1326
1327 **/
1328 UINT8
1329 XhcDevAddrToSlotId (
1330 IN USB_XHCI_INSTANCE *Xhc,
1331 IN UINT8 DevAddr
1332 )
1333 {
1334 UINT8 Index;
1335
1336 for (Index = 0; Index < 255; Index++) {
1337 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1338 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1339 (Xhc->UsbDevContext[Index + 1].XhciDevAddr == DevAddr)) {
1340 break;
1341 }
1342 }
1343
1344 if (Index == 255) {
1345 return 0;
1346 }
1347
1348 return Xhc->UsbDevContext[Index + 1].SlotId;
1349 }
1350
1351 /**
1352 Find out the actual device address according to the requested device address from UsbBus.
1353
1354 @param Xhc The XHCI Instance.
1355 @param BusDevAddr The requested device address by UsbBus upper driver.
1356
1357 @return The actual device address assigned to the device.
1358
1359 **/
1360 UINT8
1361 EFIAPI
1362 XhcBusDevAddrToSlotId (
1363 IN USB_XHCI_INSTANCE *Xhc,
1364 IN UINT8 BusDevAddr
1365 )
1366 {
1367 UINT8 Index;
1368
1369 for (Index = 0; Index < 255; Index++) {
1370 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1371 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1372 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
1373 break;
1374 }
1375 }
1376
1377 if (Index == 255) {
1378 return 0;
1379 }
1380
1381 return Xhc->UsbDevContext[Index + 1].SlotId;
1382 }
1383
1384 /**
1385 Find out the slot id according to the device's route string.
1386
1387 @param Xhc The XHCI Instance.
1388 @param RouteString The route string described the device location.
1389
1390 @return The slot id used by the device.
1391
1392 **/
1393 UINT8
1394 EFIAPI
1395 XhcRouteStringToSlotId (
1396 IN USB_XHCI_INSTANCE *Xhc,
1397 IN USB_DEV_ROUTE RouteString
1398 )
1399 {
1400 UINT8 Index;
1401
1402 for (Index = 0; Index < 255; Index++) {
1403 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1404 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1405 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
1406 break;
1407 }
1408 }
1409
1410 if (Index == 255) {
1411 return 0;
1412 }
1413
1414 return Xhc->UsbDevContext[Index + 1].SlotId;
1415 }
1416
1417 /**
1418 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1419
1420 @param Xhc The XHCI Instance.
1421 @param EvtRing The event ring to sync.
1422
1423 @retval EFI_SUCCESS The event ring is synchronized successfully.
1424
1425 **/
1426 EFI_STATUS
1427 EFIAPI
1428 XhcSyncEventRing (
1429 IN USB_XHCI_INSTANCE *Xhc,
1430 IN EVENT_RING *EvtRing
1431 )
1432 {
1433 UINTN Index;
1434 TRB_TEMPLATE *EvtTrb1;
1435 TRB_TEMPLATE *EvtTrb2;
1436 TRB_TEMPLATE *XhcDequeue;
1437
1438 ASSERT (EvtRing != NULL);
1439
1440 //
1441 // Calculate the EventRingEnqueue and EventRingCCS.
1442 // Note: only support single Segment
1443 //
1444 EvtTrb1 = EvtRing->EventRingSeg0;
1445 EvtTrb2 = EvtRing->EventRingSeg0;
1446
1447 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
1448 if (EvtTrb1->CycleBit != EvtTrb2->CycleBit) {
1449 break;
1450 }
1451 EvtTrb1++;
1452 }
1453
1454 if (Index < EvtRing->TrbNumber) {
1455 EvtRing->EventRingEnqueue = EvtTrb1;
1456 EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 1 : 0;
1457 } else {
1458 EvtRing->EventRingEnqueue = EvtTrb2;
1459 EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 0 : 1;
1460 }
1461
1462 //
1463 // Apply the EventRingDequeue to Xhc
1464 //
1465 XhcDequeue = (TRB_TEMPLATE *)(UINTN) XhcReadRuntimeReg64 (
1466 Xhc,
1467 XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter)
1468 );
1469
1470 if (((UINT64)(UINTN)XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)EvtRing->EventRingDequeue & (~0x0F))) {
1471 XhcWriteRuntimeReg64 (
1472 Xhc,
1473 XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter),
1474 (UINT64)(UINTN)EvtRing->EventRingDequeue | BIT3
1475 );
1476 }
1477
1478 return EFI_SUCCESS;
1479 }
1480
1481 /**
1482 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1483
1484 @param Xhc The XHCI Instance.
1485 @param TrsRing The transfer ring to sync.
1486
1487 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1488
1489 **/
1490 EFI_STATUS
1491 EFIAPI
1492 XhcSyncTrsRing (
1493 IN USB_XHCI_INSTANCE *Xhc,
1494 IN TRANSFER_RING *TrsRing
1495 )
1496 {
1497 UINTN Index;
1498 TRB_TEMPLATE *TrsTrb;
1499
1500 ASSERT (TrsRing != NULL);
1501 //
1502 // Calculate the latest RingEnqueue and RingPCS
1503 //
1504 TrsTrb = TrsRing->RingEnqueue;
1505 ASSERT (TrsTrb != NULL);
1506
1507 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
1508 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
1509 break;
1510 }
1511 TrsTrb++;
1512 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
1513 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
1514 //
1515 // set cycle bit in Link TRB as normal
1516 //
1517 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
1518 //
1519 // Toggle PCS maintained by software
1520 //
1521 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
1522 TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | ((UINT64)TrsTrb->Parameter2 << 32)) & ~0x0F);
1523 }
1524 }
1525
1526 ASSERT (Index != TrsRing->TrbNumber);
1527
1528 if (TrsTrb != TrsRing->RingEnqueue) {
1529 TrsRing->RingEnqueue = TrsTrb;
1530 }
1531
1532 //
1533 // Clear the Trb context for enqueue, but reserve the PCS bit
1534 //
1535 TrsTrb->Parameter1 = 0;
1536 TrsTrb->Parameter2 = 0;
1537 TrsTrb->Status = 0;
1538 TrsTrb->RsvdZ1 = 0;
1539 TrsTrb->Type = 0;
1540 TrsTrb->Control = 0;
1541
1542 return EFI_SUCCESS;
1543 }
1544
1545 /**
1546 Check if there is a new generated event.
1547
1548 @param Xhc The XHCI Instance.
1549 @param EvtRing The event ring to check.
1550 @param NewEvtTrb The new event TRB found.
1551
1552 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1553 @retval EFI_NOT_READY The event ring has no new event.
1554
1555 **/
1556 EFI_STATUS
1557 EFIAPI
1558 XhcCheckNewEvent (
1559 IN USB_XHCI_INSTANCE *Xhc,
1560 IN EVENT_RING *EvtRing,
1561 OUT TRB_TEMPLATE **NewEvtTrb
1562 )
1563 {
1564 EFI_STATUS Status;
1565 TRB_TEMPLATE*EvtTrb;
1566
1567 ASSERT (EvtRing != NULL);
1568
1569 EvtTrb = EvtRing->EventRingDequeue;
1570 *NewEvtTrb = EvtRing->EventRingDequeue;
1571
1572 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
1573 return EFI_NOT_READY;
1574 }
1575
1576 Status = EFI_SUCCESS;
1577
1578 if (((EvtTrb->Status >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) {
1579 Status = EFI_DEVICE_ERROR;
1580 }
1581
1582 EvtRing->EventRingDequeue++;
1583 //
1584 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1585 //
1586 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1587 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
1588 }
1589
1590 return Status;
1591 }
1592
1593 /**
1594 Ring the door bell to notify XHCI there is a transaction to be executed.
1595
1596 @param Xhc The XHCI Instance.
1597 @param SlotId The slot id of the target device.
1598 @param Dci The device context index of the target slot or endpoint.
1599
1600 @retval EFI_SUCCESS Successfully ring the door bell.
1601
1602 **/
1603 EFI_STATUS
1604 EFIAPI
1605 XhcRingDoorBell (
1606 IN USB_XHCI_INSTANCE *Xhc,
1607 IN UINT8 SlotId,
1608 IN UINT8 Dci
1609 )
1610 {
1611 if (SlotId == 0) {
1612 XhcWriteDoorBellReg (Xhc, 0, 0);
1613 } else {
1614 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1615 }
1616
1617 return EFI_SUCCESS;
1618 }
1619
1620 /**
1621 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1622
1623 @param Xhc The XHCI Instance.
1624 @param Urb The URB to be rung.
1625
1626 @retval EFI_SUCCESS Successfully ring the door bell.
1627
1628 **/
1629 EFI_STATUS
1630 RingIntTransferDoorBell (
1631 IN USB_XHCI_INSTANCE *Xhc,
1632 IN URB *Urb
1633 )
1634 {
1635 UINT8 SlotId;
1636 UINT8 Dci;
1637
1638 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);
1639 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1640 XhcRingDoorBell (Xhc, SlotId, Dci);
1641 return EFI_SUCCESS;
1642 }
1643
1644 /**
1645 Assign and initialize the device slot for a new device.
1646
1647 @param Xhc The XHCI Instance.
1648 @param ParentRouteChart The route string pointed to the parent device.
1649 @param ParentPort The port at which the device is located.
1650 @param RouteChart The route string pointed to the device.
1651 @param DeviceSpeed The device speed.
1652
1653 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1654
1655 **/
1656 EFI_STATUS
1657 EFIAPI
1658 XhcInitializeDeviceSlot (
1659 IN USB_XHCI_INSTANCE *Xhc,
1660 IN USB_DEV_ROUTE ParentRouteChart,
1661 IN UINT16 ParentPort,
1662 IN USB_DEV_ROUTE RouteChart,
1663 IN UINT8 DeviceSpeed
1664 )
1665 {
1666 EFI_STATUS Status;
1667 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1668 INPUT_CONTEXT *InputContext;
1669 DEVICE_CONTEXT *OutputContext;
1670 TRANSFER_RING *EndpointTransferRing;
1671 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1672 UINT8 DeviceAddress;
1673 CMD_TRB_ENABLE_SLOT CmdTrb;
1674 UINT8 SlotId;
1675 UINT8 ParentSlotId;
1676 DEVICE_CONTEXT *ParentDeviceContext;
1677
1678 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1679 CmdTrb.CycleBit = 1;
1680 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1681
1682 Status = XhcCmdTransfer (
1683 Xhc,
1684 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1685 XHC_GENERIC_TIMEOUT,
1686 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1687 );
1688 ASSERT_EFI_ERROR (Status);
1689 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1690 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1691 SlotId = (UINT8)EvtTrb->SlotId;
1692 ASSERT (SlotId != 0);
1693
1694 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1695 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1696 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1697 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1698 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1699
1700 //
1701 // 4.3.3 Device Slot Initialization
1702 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1703 //
1704 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));
1705 ASSERT (InputContext != NULL);
1706 ASSERT (((UINTN) InputContext & 0x3F) == 0);
1707 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1708
1709 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1710
1711 //
1712 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1713 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1714 // Context are affected by the command.
1715 //
1716 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1717
1718 //
1719 // 3) Initialize the Input Slot Context data structure
1720 //
1721 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1722 InputContext->Slot.Speed = DeviceSpeed + 1;
1723 InputContext->Slot.ContextEntries = 1;
1724 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1725
1726 if (RouteChart.Route.RouteString) {
1727 //
1728 // The device is behind of hub device.
1729 //
1730 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
1731 ASSERT (ParentSlotId != 0);
1732 //
1733 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1734 //
1735 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1736 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1737 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1738 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1739 //
1740 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1741 // environment from Full/Low speed signaling environment for a device
1742 //
1743 InputContext->Slot.TTPortNum = ParentPort;
1744 InputContext->Slot.TTHubSlotId = ParentSlotId;
1745 }
1746 } else {
1747 //
1748 // Inherit the TT parameters from parent device.
1749 //
1750 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
1751 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1752 //
1753 // If the device is a High speed device then down the speed to be the same as its parent Hub
1754 //
1755 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1756 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1757 }
1758 }
1759 }
1760
1761 //
1762 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1763 //
1764 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1765 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1766 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1767 //
1768 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1769 //
1770 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1771
1772 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1773 InputContext->EP[0].MaxPacketSize = 512;
1774 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1775 InputContext->EP[0].MaxPacketSize = 64;
1776 } else {
1777 InputContext->EP[0].MaxPacketSize = 8;
1778 }
1779 //
1780 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1781 // 1KB, and Bulk and Isoch endpoints 3KB.
1782 //
1783 InputContext->EP[0].AverageTRBLength = 8;
1784 InputContext->EP[0].MaxBurstSize = 0;
1785 InputContext->EP[0].Interval = 0;
1786 InputContext->EP[0].MaxPStreams = 0;
1787 InputContext->EP[0].Mult = 0;
1788 InputContext->EP[0].CErr = 3;
1789
1790 //
1791 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1792 //
1793 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;
1794 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);
1795
1796 //
1797 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1798 //
1799 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));
1800 ASSERT (OutputContext != NULL);
1801 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
1802 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
1803
1804 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1805 //
1806 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1807 // a pointer to the Output Device Context data structure (6.2.1).
1808 //
1809 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;
1810
1811 //
1812 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1813 // Context data structure described above.
1814 //
1815 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1816 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
1817 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
1818 CmdTrbAddr.CycleBit = 1;
1819 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
1820 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
1821 Status = XhcCmdTransfer (
1822 Xhc,
1823 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1824 XHC_GENERIC_TIMEOUT,
1825 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1826 );
1827 ASSERT (!EFI_ERROR(Status));
1828
1829 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
1830 DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress));
1831
1832 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1833
1834 return Status;
1835 }
1836
1837 /**
1838 Disable the specified device slot.
1839
1840 @param Xhc The XHCI Instance.
1841 @param SlotId The slot id to be disabled.
1842
1843 @retval EFI_SUCCESS Successfully disable the device slot.
1844
1845 **/
1846 EFI_STATUS
1847 EFIAPI
1848 XhcDisableSlotCmd (
1849 IN USB_XHCI_INSTANCE *Xhc,
1850 IN UINT8 SlotId
1851 )
1852 {
1853 EFI_STATUS Status;
1854 TRB_TEMPLATE *EvtTrb;
1855 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
1856 UINT8 Index;
1857 VOID *RingSeg;
1858
1859 //
1860 // Disable the device slots occupied by these devices on its downstream ports.
1861 // Entry 0 is reserved.
1862 //
1863 for (Index = 0; Index < 255; Index++) {
1864 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
1865 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
1866 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
1867 continue;
1868 }
1869
1870 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
1871
1872 if (EFI_ERROR (Status)) {
1873 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
1874 Xhc->UsbDevContext[Index + 1].SlotId = 0;
1875 }
1876 }
1877
1878 //
1879 // Construct the disable slot command
1880 //
1881 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
1882
1883 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
1884 CmdTrbDisSlot.CycleBit = 1;
1885 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
1886 CmdTrbDisSlot.SlotId = SlotId;
1887 Status = XhcCmdTransfer (
1888 Xhc,
1889 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
1890 XHC_GENERIC_TIMEOUT,
1891 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1892 );
1893 ASSERT_EFI_ERROR(Status);
1894 //
1895 // Free the slot's device context entry
1896 //
1897 Xhc->DCBAA[SlotId] = 0;
1898
1899 //
1900 // Free the slot related data structure
1901 //
1902 for (Index = 0; Index < 31; Index++) {
1903 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
1904 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
1905 if (RingSeg != NULL) {
1906 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));
1907 }
1908 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
1909 }
1910 }
1911
1912 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1913 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
1914 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1915 }
1916 }
1917
1918 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
1919 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));
1920 }
1921
1922 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
1923 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));
1924 }
1925 //
1926 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1927 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1928 // remove urb from XHCI's asynchronous transfer list.
1929 //
1930 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
1931
1932 return Status;
1933 }
1934
1935 /**
1936 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1937
1938 @param Xhc The XHCI Instance.
1939 @param SlotId The slot id to be configured.
1940 @param DeviceSpeed The device's speed.
1941 @param ConfigDesc The pointer to the usb device configuration descriptor.
1942
1943 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1944
1945 **/
1946 EFI_STATUS
1947 EFIAPI
1948 XhcSetConfigCmd (
1949 IN USB_XHCI_INSTANCE *Xhc,
1950 IN UINT8 SlotId,
1951 IN UINT8 DeviceSpeed,
1952 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
1953 )
1954 {
1955 EFI_STATUS Status;
1956
1957 USB_INTERFACE_DESCRIPTOR *IfDesc;
1958 USB_ENDPOINT_DESCRIPTOR *EpDesc;
1959 UINT8 Index;
1960 UINTN NumEp;
1961 UINTN EpIndex;
1962 UINT8 EpAddr;
1963 UINT8 Direction;
1964 UINT8 Dci;
1965 UINT8 MaxDci;
1966 UINT32 PhyAddr;
1967 UINT8 Interval;
1968
1969 TRANSFER_RING *EndpointTransferRing;
1970 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
1971 INPUT_CONTEXT *InputContext;
1972 DEVICE_CONTEXT *OutputContext;
1973 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1974 //
1975 // 4.6.6 Configure Endpoint
1976 //
1977 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
1978 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
1979 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1980 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
1981
1982 ASSERT (ConfigDesc != NULL);
1983
1984 MaxDci = 0;
1985
1986 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
1987 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
1988 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
1989 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
1990 }
1991
1992 NumEp = IfDesc->NumEndpoints;
1993
1994 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
1995 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
1996 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
1997 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
1998 }
1999
2000 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2001 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2002
2003 Dci = XhcEndpointToDci (EpAddr, Direction);
2004 ASSERT (Dci < 32);
2005 if (Dci > MaxDci) {
2006 MaxDci = Dci;
2007 }
2008
2009 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2010 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2011
2012 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2013 //
2014 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2015 //
2016 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2017 } else {
2018 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2019 }
2020
2021 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2022 case USB_ENDPOINT_BULK:
2023 if (Direction == EfiUsbDataIn) {
2024 InputContext->EP[Dci-1].CErr = 3;
2025 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2026 } else {
2027 InputContext->EP[Dci-1].CErr = 3;
2028 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2029 }
2030
2031 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2032 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2033 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2034 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2035 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2036 }
2037
2038 break;
2039 case USB_ENDPOINT_ISO:
2040 if (Direction == EfiUsbDataIn) {
2041 InputContext->EP[Dci-1].CErr = 0;
2042 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2043 } else {
2044 InputContext->EP[Dci-1].CErr = 0;
2045 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2046 }
2047 break;
2048 case USB_ENDPOINT_INTERRUPT:
2049 if (Direction == EfiUsbDataIn) {
2050 InputContext->EP[Dci-1].CErr = 3;
2051 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2052 } else {
2053 InputContext->EP[Dci-1].CErr = 3;
2054 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2055 }
2056 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2057 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2058 //
2059 // Get the bInterval from descriptor and init the the interval field of endpoint context
2060 //
2061 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2062 Interval = EpDesc->Interval;
2063 //
2064 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2065 //
2066 InputContext->EP[Dci-1].Interval = 6;
2067 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2068 Interval = EpDesc->Interval;
2069 ASSERT (Interval >= 1 && Interval <= 16);
2070 //
2071 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2072 //
2073 InputContext->EP[Dci-1].Interval = Interval - 1;
2074 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2075 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2076 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2077 InputContext->EP[Dci-1].CErr = 3;
2078 }
2079
2080 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2081 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2082 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2083 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2084 }
2085 break;
2086
2087 case USB_ENDPOINT_CONTROL:
2088 default:
2089 ASSERT (0);
2090 break;
2091 }
2092
2093 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2094 PhyAddr &= ~(0x0F);
2095 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2096 InputContext->EP[Dci-1].PtrLo = PhyAddr;
2097 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2098
2099 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2100 }
2101 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2102 }
2103
2104 InputContext->InputControlContext.Dword2 |= BIT0;
2105 InputContext->Slot.ContextEntries = MaxDci;
2106 //
2107 // configure endpoint
2108 //
2109 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2110 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2111 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2112 CmdTrbCfgEP.CycleBit = 1;
2113 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2114 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2115 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2116 Status = XhcCmdTransfer (
2117 Xhc,
2118 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2119 XHC_GENERIC_TIMEOUT,
2120 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2121 );
2122 ASSERT_EFI_ERROR(Status);
2123
2124 return Status;
2125 }
2126
2127 /**
2128 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2129
2130 @param Xhc The XHCI Instance.
2131 @param SlotId The slot id to be evaluated.
2132 @param MaxPacketSize The max packet size supported by the device control transfer.
2133
2134 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2135
2136 **/
2137 EFI_STATUS
2138 EFIAPI
2139 XhcEvaluateContext (
2140 IN USB_XHCI_INSTANCE *Xhc,
2141 IN UINT8 SlotId,
2142 IN UINT32 MaxPacketSize
2143 )
2144 {
2145 EFI_STATUS Status;
2146 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2147 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2148 INPUT_CONTEXT *InputContext;
2149
2150 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2151
2152 //
2153 // 4.6.7 Evaluate Context
2154 //
2155 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2156 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2157
2158 InputContext->InputControlContext.Dword2 |= BIT1;
2159 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2160
2161 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2162 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);
2163 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);
2164 CmdTrbEvalu.CycleBit = 1;
2165 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2166 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2167 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
2168 Status = XhcCmdTransfer (
2169 Xhc,
2170 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2171 XHC_GENERIC_TIMEOUT,
2172 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2173 );
2174 ASSERT (!EFI_ERROR(Status));
2175
2176 return Status;
2177 }
2178
2179 /**
2180 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2181
2182 @param Xhc The XHCI Instance.
2183 @param SlotId The slot id to be configured.
2184 @param PortNum The total number of downstream port supported by the hub.
2185 @param TTT The TT think time of the hub device.
2186 @param MTT The multi-TT of the hub device.
2187
2188 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2189
2190 **/
2191 EFI_STATUS
2192 XhcConfigHubContext (
2193 IN USB_XHCI_INSTANCE *Xhc,
2194 IN UINT8 SlotId,
2195 IN UINT8 PortNum,
2196 IN UINT8 TTT,
2197 IN UINT8 MTT
2198 )
2199 {
2200 EFI_STATUS Status;
2201
2202 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2203 INPUT_CONTEXT *InputContext;
2204 DEVICE_CONTEXT *OutputContext;
2205 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2206
2207 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2208 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2209 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2210
2211 //
2212 // 4.6.7 Evaluate Context
2213 //
2214 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2215
2216 InputContext->InputControlContext.Dword2 |= BIT0;
2217
2218 //
2219 // Copy the slot context from OutputContext to Input context
2220 //
2221 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
2222 InputContext->Slot.Hub = 1;
2223 InputContext->Slot.PortNum = PortNum;
2224 InputContext->Slot.TTT = TTT;
2225 InputContext->Slot.MTT = MTT;
2226
2227 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2228 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2229 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2230 CmdTrbCfgEP.CycleBit = 1;
2231 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2232 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2233 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2234 Status = XhcCmdTransfer (
2235 Xhc,
2236 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2237 XHC_GENERIC_TIMEOUT,
2238 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2239 );
2240 ASSERT (!EFI_ERROR(Status));
2241
2242 return Status;
2243 }
2244