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