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