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