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