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