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