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