1 /** @file 2 3 EHCI transfer scheduling routines. 4 5 Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "Ehci.h" 17 18 19 /** 20 Create helper QTD/QH for the EHCI device. 21 22 @param Ehc The EHCI device. 23 24 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for helper QTD/QH. 25 @retval EFI_SUCCESS Helper QH/QTD are created. 26 27 **/ 28 EFI_STATUS 29 EhcCreateHelpQ ( 30 IN USB2_HC_DEV *Ehc 31 ) 32 { 33 USB_ENDPOINT Ep; 34 EHC_QH *Qh; 35 QH_HW *QhHw; 36 EHC_QTD *Qtd; 37 EFI_PHYSICAL_ADDRESS PciAddr; 38 39 // 40 // Create an inactive Qtd to terminate the short packet read. 41 // 42 Qtd = EhcCreateQtd (Ehc, NULL, NULL, 0, QTD_PID_INPUT, 0, 64); 43 44 if (Qtd == NULL) { 45 return EFI_OUT_OF_RESOURCES; 46 } 47 48 Qtd->QtdHw.Status = QTD_STAT_HALTED; 49 Ehc->ShortReadStop = Qtd; 50 51 // 52 // Create a QH to act as the EHC reclamation header. 53 // Set the header to loopback to itself. 54 // 55 Ep.DevAddr = 0; 56 Ep.EpAddr = 1; 57 Ep.Direction = EfiUsbDataIn; 58 Ep.DevSpeed = EFI_USB_SPEED_HIGH; 59 Ep.MaxPacket = 64; 60 Ep.HubAddr = 0; 61 Ep.HubPort = 0; 62 Ep.Toggle = 0; 63 Ep.Type = EHC_BULK_TRANSFER; 64 Ep.PollRate = 1; 65 66 Qh = EhcCreateQh (Ehc, &Ep); 67 68 if (Qh == NULL) { 69 return EFI_OUT_OF_RESOURCES; 70 } 71 72 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH)); 73 QhHw = &Qh->QhHw; 74 QhHw->HorizonLink = QH_LINK (PciAddr + OFFSET_OF(EHC_QH, QhHw), EHC_TYPE_QH, FALSE); 75 QhHw->Status = QTD_STAT_HALTED; 76 QhHw->ReclaimHead = 1; 77 Qh->NextQh = Qh; 78 Ehc->ReclaimHead = Qh; 79 80 // 81 // Create a dummy QH to act as the terminator for periodical schedule 82 // 83 Ep.EpAddr = 2; 84 Ep.Type = EHC_INT_TRANSFER_SYNC; 85 86 Qh = EhcCreateQh (Ehc, &Ep); 87 88 if (Qh == NULL) { 89 return EFI_OUT_OF_RESOURCES; 90 } 91 92 Qh->QhHw.Status = QTD_STAT_HALTED; 93 Ehc->PeriodOne = Qh; 94 95 return EFI_SUCCESS; 96 } 97 98 99 /** 100 Initialize the schedule data structure such as frame list. 101 102 @param Ehc The EHCI device to init schedule data. 103 104 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data. 105 @retval EFI_SUCCESS The schedule data is initialized. 106 107 **/ 108 EFI_STATUS 109 EhcInitSched ( 110 IN USB2_HC_DEV *Ehc 111 ) 112 { 113 EFI_PCI_IO_PROTOCOL *PciIo; 114 VOID *Buf; 115 EFI_PHYSICAL_ADDRESS PhyAddr; 116 VOID *Map; 117 UINTN Pages; 118 UINTN Bytes; 119 UINTN Index; 120 EFI_STATUS Status; 121 EFI_PHYSICAL_ADDRESS PciAddr; 122 123 // 124 // First initialize the periodical schedule data: 125 // 1. Allocate and map the memory for the frame list 126 // 2. Create the help QTD/QH 127 // 3. Initialize the frame entries 128 // 4. Set the frame list register 129 // 130 PciIo = Ehc->PciIo; 131 132 Bytes = 4096; 133 Pages = EFI_SIZE_TO_PAGES (Bytes); 134 135 Status = PciIo->AllocateBuffer ( 136 PciIo, 137 AllocateAnyPages, 138 EfiBootServicesData, 139 Pages, 140 &Buf, 141 0 142 ); 143 144 if (EFI_ERROR (Status)) { 145 return EFI_OUT_OF_RESOURCES; 146 } 147 148 Status = PciIo->Map ( 149 PciIo, 150 EfiPciIoOperationBusMasterCommonBuffer, 151 Buf, 152 &Bytes, 153 &PhyAddr, 154 &Map 155 ); 156 157 if (EFI_ERROR (Status) || (Bytes != 4096)) { 158 PciIo->FreeBuffer (PciIo, Pages, Buf); 159 return EFI_OUT_OF_RESOURCES; 160 } 161 162 Ehc->PeriodFrame = Buf; 163 Ehc->PeriodFrameMap = Map; 164 165 // 166 // Program the FRAMELISTBASE register with the low 32 bit addr 167 // 168 EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (PhyAddr)); 169 // 170 // Program the CTRLDSSEGMENT register with the high 32 bit addr 171 // 172 EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, EHC_HIGH_32BIT (PhyAddr)); 173 174 // 175 // Init memory pool management then create the helper 176 // QTD/QH. If failed, previously allocated resources 177 // will be freed by EhcFreeSched 178 // 179 Ehc->MemPool = UsbHcInitMemPool ( 180 PciIo, 181 Ehc->Support64BitDma, 182 EHC_HIGH_32BIT (PhyAddr) 183 ); 184 185 if (Ehc->MemPool == NULL) { 186 Status = EFI_OUT_OF_RESOURCES; 187 goto ErrorExit1; 188 } 189 190 Status = EhcCreateHelpQ (Ehc); 191 192 if (EFI_ERROR (Status)) { 193 goto ErrorExit; 194 } 195 196 // 197 // Initialize the frame list entries then set the registers 198 // 199 Ehc->PeriodFrameHost = AllocateZeroPool (EHC_FRAME_LEN * sizeof (UINTN)); 200 if (Ehc->PeriodFrameHost == NULL) { 201 Status = EFI_OUT_OF_RESOURCES; 202 goto ErrorExit; 203 } 204 205 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH)); 206 207 for (Index = 0; Index < EHC_FRAME_LEN; Index++) { 208 // 209 // Store the pci bus address of the QH in period frame list which will be accessed by pci bus master. 210 // 211 ((UINT32 *)(Ehc->PeriodFrame))[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 212 // 213 // Store the host address of the QH in period frame list which will be accessed by host. 214 // 215 ((UINTN *)(Ehc->PeriodFrameHost))[Index] = (UINTN)Ehc->PeriodOne; 216 } 217 218 // 219 // Second initialize the asynchronous schedule: 220 // Only need to set the AsynListAddr register to 221 // the reclamation header 222 // 223 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH)); 224 EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (PciAddr)); 225 return EFI_SUCCESS; 226 227 ErrorExit: 228 if (Ehc->PeriodOne != NULL) { 229 UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH)); 230 Ehc->PeriodOne = NULL; 231 } 232 233 if (Ehc->ReclaimHead != NULL) { 234 UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH)); 235 Ehc->ReclaimHead = NULL; 236 } 237 238 if (Ehc->ShortReadStop != NULL) { 239 UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD)); 240 Ehc->ShortReadStop = NULL; 241 } 242 243 ErrorExit1: 244 PciIo->FreeBuffer (PciIo, Pages, Buf); 245 PciIo->Unmap (PciIo, Map); 246 247 return Status; 248 } 249 250 251 /** 252 Free the schedule data. It may be partially initialized. 253 254 @param Ehc The EHCI device. 255 256 **/ 257 VOID 258 EhcFreeSched ( 259 IN USB2_HC_DEV *Ehc 260 ) 261 { 262 EFI_PCI_IO_PROTOCOL *PciIo; 263 264 EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0); 265 EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0); 266 267 if (Ehc->PeriodOne != NULL) { 268 UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH)); 269 Ehc->PeriodOne = NULL; 270 } 271 272 if (Ehc->ReclaimHead != NULL) { 273 UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH)); 274 Ehc->ReclaimHead = NULL; 275 } 276 277 if (Ehc->ShortReadStop != NULL) { 278 UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD)); 279 Ehc->ShortReadStop = NULL; 280 } 281 282 if (Ehc->MemPool != NULL) { 283 UsbHcFreeMemPool (Ehc->MemPool); 284 Ehc->MemPool = NULL; 285 } 286 287 if (Ehc->PeriodFrame != NULL) { 288 PciIo = Ehc->PciIo; 289 ASSERT (PciIo != NULL); 290 291 PciIo->Unmap (PciIo, Ehc->PeriodFrameMap); 292 293 PciIo->FreeBuffer ( 294 PciIo, 295 EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), 296 Ehc->PeriodFrame 297 ); 298 299 Ehc->PeriodFrame = NULL; 300 } 301 302 if (Ehc->PeriodFrameHost != NULL) { 303 FreePool (Ehc->PeriodFrameHost); 304 Ehc->PeriodFrameHost = NULL; 305 } 306 } 307 308 309 /** 310 Link the queue head to the asynchronous schedule list. 311 UEFI only supports one CTRL/BULK transfer at a time 312 due to its interfaces. This simplifies the AsynList 313 management: A reclamation header is always linked to 314 the AsyncListAddr, the only active QH is appended to it. 315 316 @param Ehc The EHCI device. 317 @param Qh The queue head to link. 318 319 **/ 320 VOID 321 EhcLinkQhToAsync ( 322 IN USB2_HC_DEV *Ehc, 323 IN EHC_QH *Qh 324 ) 325 { 326 EHC_QH *Head; 327 EFI_PHYSICAL_ADDRESS PciAddr; 328 329 // 330 // Append the queue head after the reclaim header, then 331 // fix the hardware visiable parts (EHCI R1.0 page 72). 332 // ReclaimHead is always linked to the EHCI's AsynListAddr. 333 // 334 Head = Ehc->ReclaimHead; 335 336 Qh->NextQh = Head->NextQh; 337 Head->NextQh = Qh; 338 339 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh->NextQh, sizeof (EHC_QH)); 340 Qh->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 341 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH)); 342 Head->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 343 } 344 345 346 /** 347 Unlink a queue head from the asynchronous schedule list. 348 Need to synchronize with hardware. 349 350 @param Ehc The EHCI device. 351 @param Qh The queue head to unlink. 352 353 **/ 354 VOID 355 EhcUnlinkQhFromAsync ( 356 IN USB2_HC_DEV *Ehc, 357 IN EHC_QH *Qh 358 ) 359 { 360 EHC_QH *Head; 361 EFI_STATUS Status; 362 EFI_PHYSICAL_ADDRESS PciAddr; 363 364 ASSERT (Ehc->ReclaimHead->NextQh == Qh); 365 366 // 367 // Remove the QH from reclamation head, then update the hardware 368 // visiable part: Only need to loopback the ReclaimHead. The Qh 369 // is pointing to ReclaimHead (which is staill in the list). 370 // 371 Head = Ehc->ReclaimHead; 372 373 Head->NextQh = Qh->NextQh; 374 Qh->NextQh = NULL; 375 376 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH)); 377 Head->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 378 379 // 380 // Set and wait the door bell to synchronize with the hardware 381 // 382 Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT); 383 384 if (EFI_ERROR (Status)) { 385 DEBUG ((EFI_D_ERROR, "EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n")); 386 } 387 } 388 389 390 /** 391 Link a queue head for interrupt transfer to the periodic 392 schedule frame list. This code is very much the same as 393 that in UHCI. 394 395 @param Ehc The EHCI device. 396 @param Qh The queue head to link. 397 398 **/ 399 VOID 400 EhcLinkQhToPeriod ( 401 IN USB2_HC_DEV *Ehc, 402 IN EHC_QH *Qh 403 ) 404 { 405 UINTN Index; 406 EHC_QH *Prev; 407 EHC_QH *Next; 408 EFI_PHYSICAL_ADDRESS PciAddr; 409 410 for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) { 411 // 412 // First QH can't be NULL because we always keep PeriodOne 413 // heads on the frame list 414 // 415 ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index])); 416 Next = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index]; 417 Prev = NULL; 418 419 // 420 // Now, insert the queue head (Qh) into this frame: 421 // 1. Find a queue head with the same poll interval, just insert 422 // Qh after this queue head, then we are done. 423 // 424 // 2. Find the position to insert the queue head into: 425 // Previous head's interval is bigger than Qh's 426 // Next head's interval is less than Qh's 427 // Then, insert the Qh between then 428 // 429 while (Next->Interval > Qh->Interval) { 430 Prev = Next; 431 Next = Next->NextQh; 432 } 433 434 ASSERT (Next != NULL); 435 436 // 437 // The entry may have been linked into the frame by early insertation. 438 // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh 439 // with Qh.Interval == 8 on the frame. If so, we are done with this frame. 440 // It isn't necessary to compare all the QH with the same interval to 441 // Qh. This is because if there is other QH with the same interval, Qh 442 // should has been inserted after that at Frames[0] and at Frames[0] it is 443 // impossible for (Next == Qh) 444 // 445 if (Next == Qh) { 446 continue; 447 } 448 449 if (Next->Interval == Qh->Interval) { 450 // 451 // If there is a QH with the same interval, it locates at 452 // Frames[0], and we can simply insert it after this QH. We 453 // are all done. 454 // 455 ASSERT ((Index == 0) && (Qh->NextQh == NULL)); 456 457 Prev = Next; 458 Next = Next->NextQh; 459 460 Qh->NextQh = Next; 461 Prev->NextQh = Qh; 462 463 Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink; 464 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH)); 465 Prev->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 466 break; 467 } 468 469 // 470 // OK, find the right position, insert it in. If Qh's next 471 // link has already been set, it is in position. This is 472 // guarranted by 2^n polling interval. 473 // 474 if (Qh->NextQh == NULL) { 475 Qh->NextQh = Next; 476 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Next, sizeof (EHC_QH)); 477 Qh->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 478 } 479 480 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH)); 481 482 if (Prev == NULL) { 483 ((UINT32*)Ehc->PeriodFrame)[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 484 ((UINTN*)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh; 485 } else { 486 Prev->NextQh = Qh; 487 Prev->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE); 488 } 489 } 490 } 491 492 493 /** 494 Unlink an interrupt queue head from the periodic 495 schedule frame list. 496 497 @param Ehc The EHCI device. 498 @param Qh The queue head to unlink. 499 500 **/ 501 VOID 502 EhcUnlinkQhFromPeriod ( 503 IN USB2_HC_DEV *Ehc, 504 IN EHC_QH *Qh 505 ) 506 { 507 UINTN Index; 508 EHC_QH *Prev; 509 EHC_QH *This; 510 511 for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) { 512 // 513 // Frame link can't be NULL because we always keep PeroidOne 514 // on the frame list 515 // 516 ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index])); 517 This = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index]; 518 Prev = NULL; 519 520 // 521 // Walk through the frame's QH list to find the 522 // queue head to remove 523 // 524 while ((This != NULL) && (This != Qh)) { 525 Prev = This; 526 This = This->NextQh; 527 } 528 529 // 530 // Qh may have already been unlinked from this frame 531 // by early action. See the comments in EhcLinkQhToPeriod. 532 // 533 if (This == NULL) { 534 continue; 535 } 536 537 if (Prev == NULL) { 538 // 539 // Qh is the first entry in the frame 540 // 541 ((UINT32*)Ehc->PeriodFrame)[Index] = Qh->QhHw.HorizonLink; 542 ((UINTN*)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh->NextQh; 543 } else { 544 Prev->NextQh = Qh->NextQh; 545 Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink; 546 } 547 } 548 } 549 550 551 /** 552 Check the URB's execution result and update the URB's 553 result accordingly. 554 555 @param Ehc The EHCI device. 556 @param Urb The URB to check result. 557 558 @return Whether the result of URB transfer is finialized. 559 560 **/ 561 BOOLEAN 562 EhcCheckUrbResult ( 563 IN USB2_HC_DEV *Ehc, 564 IN URB *Urb 565 ) 566 { 567 LIST_ENTRY *Entry; 568 EHC_QTD *Qtd; 569 QTD_HW *QtdHw; 570 UINT8 State; 571 BOOLEAN Finished; 572 EFI_PHYSICAL_ADDRESS PciAddr; 573 574 ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL)); 575 576 Finished = TRUE; 577 Urb->Completed = 0; 578 579 Urb->Result = EFI_USB_NOERROR; 580 581 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { 582 Urb->Result |= EFI_USB_ERR_SYSTEM; 583 goto ON_EXIT; 584 } 585 586 EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) { 587 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList); 588 QtdHw = &Qtd->QtdHw; 589 State = (UINT8) QtdHw->Status; 590 591 if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) { 592 // 593 // EHCI will halt the queue head when met some error. 594 // If it is halted, the result of URB is finialized. 595 // 596 if ((State & QTD_STAT_ERR_MASK) == 0) { 597 Urb->Result |= EFI_USB_ERR_STALL; 598 } 599 600 if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) { 601 Urb->Result |= EFI_USB_ERR_BABBLE; 602 } 603 604 if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) { 605 Urb->Result |= EFI_USB_ERR_BUFFER; 606 } 607 608 if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) { 609 Urb->Result |= EFI_USB_ERR_TIMEOUT; 610 } 611 612 Finished = TRUE; 613 goto ON_EXIT; 614 615 } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) { 616 // 617 // The QTD is still active, no need to check furthur. 618 // 619 Urb->Result |= EFI_USB_ERR_NOTEXECUTE; 620 621 Finished = FALSE; 622 goto ON_EXIT; 623 624 } else { 625 // 626 // This QTD is finished OK or met short packet read. Update the 627 // transfer length if it isn't a setup. 628 // 629 if (QtdHw->Pid != QTD_PID_SETUP) { 630 Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes; 631 } 632 633 if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) { 634 EhcDumpQh (Urb->Qh, "Short packet read", FALSE); 635 636 // 637 // Short packet read condition. If it isn't a setup transfer, 638 // no need to check furthur: the queue head will halt at the 639 // ShortReadStop. If it is a setup transfer, need to check the 640 // Status Stage of the setup transfer to get the finial result 641 // 642 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD)); 643 if (QtdHw->AltNext == QTD_LINK (PciAddr, FALSE)) { 644 DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, break\n")); 645 646 Finished = TRUE; 647 goto ON_EXIT; 648 } 649 650 DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, continue\n")); 651 } 652 } 653 } 654 655 ON_EXIT: 656 // 657 // Return the data toggle set by EHCI hardware, bulk and interrupt 658 // transfer will use this to initialize the next transaction. For 659 // Control transfer, it always start a new data toggle sequence for 660 // new transfer. 661 // 662 // NOTICE: don't move DT update before the loop, otherwise there is 663 // a race condition that DT is wrong. 664 // 665 Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle; 666 667 return Finished; 668 } 669 670 671 /** 672 Execute the transfer by polling the URB. This is a synchronous operation. 673 674 @param Ehc The EHCI device. 675 @param Urb The URB to execute. 676 @param TimeOut The time to wait before abort, in millisecond. 677 678 @return EFI_DEVICE_ERROR The transfer failed due to transfer error. 679 @return EFI_TIMEOUT The transfer failed due to time out. 680 @return EFI_SUCCESS The transfer finished OK. 681 682 **/ 683 EFI_STATUS 684 EhcExecTransfer ( 685 IN USB2_HC_DEV *Ehc, 686 IN URB *Urb, 687 IN UINTN TimeOut 688 ) 689 { 690 EFI_STATUS Status; 691 UINTN Index; 692 UINTN Loop; 693 BOOLEAN Finished; 694 BOOLEAN InfiniteLoop; 695 696 Status = EFI_SUCCESS; 697 Loop = TimeOut * EHC_1_MILLISECOND; 698 Finished = FALSE; 699 InfiniteLoop = FALSE; 700 701 // 702 // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller 703 // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR 704 // is returned. 705 // 706 if (TimeOut == 0) { 707 InfiniteLoop = TRUE; 708 } 709 710 for (Index = 0; InfiniteLoop || (Index < Loop); Index++) { 711 Finished = EhcCheckUrbResult (Ehc, Urb); 712 713 if (Finished) { 714 break; 715 } 716 717 gBS->Stall (EHC_1_MICROSECOND); 718 } 719 720 if (!Finished) { 721 DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer not finished in %dms\n", (UINT32)TimeOut)); 722 EhcDumpQh (Urb->Qh, NULL, FALSE); 723 724 Status = EFI_TIMEOUT; 725 726 } else if (Urb->Result != EFI_USB_NOERROR) { 727 DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer failed with %x\n", Urb->Result)); 728 EhcDumpQh (Urb->Qh, NULL, FALSE); 729 730 Status = EFI_DEVICE_ERROR; 731 } 732 733 return Status; 734 } 735 736 737 /** 738 Delete a single asynchronous interrupt transfer for 739 the device and endpoint. 740 741 @param Ehc The EHCI device. 742 @param DevAddr The address of the target device. 743 @param EpNum The endpoint of the target. 744 @param DataToggle Return the next data toggle to use. 745 746 @retval EFI_SUCCESS An asynchronous transfer is removed. 747 @retval EFI_NOT_FOUND No transfer for the device is found. 748 749 **/ 750 EFI_STATUS 751 EhciDelAsyncIntTransfer ( 752 IN USB2_HC_DEV *Ehc, 753 IN UINT8 DevAddr, 754 IN UINT8 EpNum, 755 OUT UINT8 *DataToggle 756 ) 757 { 758 LIST_ENTRY *Entry; 759 LIST_ENTRY *Next; 760 URB *Urb; 761 EFI_USB_DATA_DIRECTION Direction; 762 763 Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut); 764 EpNum &= 0x0F; 765 766 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) { 767 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList); 768 769 if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) && 770 (Urb->Ep.Direction == Direction)) { 771 // 772 // Check the URB status to retrieve the next data toggle 773 // from the associated queue head. 774 // 775 EhcCheckUrbResult (Ehc, Urb); 776 *DataToggle = Urb->DataToggle; 777 778 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh); 779 RemoveEntryList (&Urb->UrbList); 780 781 gBS->FreePool (Urb->Data); 782 EhcFreeUrb (Ehc, Urb); 783 return EFI_SUCCESS; 784 } 785 } 786 787 return EFI_NOT_FOUND; 788 } 789 790 791 /** 792 Remove all the asynchronous interrutp transfers. 793 794 @param Ehc The EHCI device. 795 796 **/ 797 VOID 798 EhciDelAllAsyncIntTransfers ( 799 IN USB2_HC_DEV *Ehc 800 ) 801 { 802 LIST_ENTRY *Entry; 803 LIST_ENTRY *Next; 804 URB *Urb; 805 806 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) { 807 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList); 808 809 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh); 810 RemoveEntryList (&Urb->UrbList); 811 812 gBS->FreePool (Urb->Data); 813 EhcFreeUrb (Ehc, Urb); 814 } 815 } 816 817 818 /** 819 Flush data from PCI controller specific address to mapped system 820 memory address. 821 822 @param Ehc The EHCI device. 823 @param Urb The URB to unmap. 824 825 @retval EFI_SUCCESS Success to flush data to mapped system memory. 826 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory. 827 828 **/ 829 EFI_STATUS 830 EhcFlushAsyncIntMap ( 831 IN USB2_HC_DEV *Ehc, 832 IN URB *Urb 833 ) 834 { 835 EFI_STATUS Status; 836 EFI_PHYSICAL_ADDRESS PhyAddr; 837 EFI_PCI_IO_PROTOCOL_OPERATION MapOp; 838 EFI_PCI_IO_PROTOCOL *PciIo; 839 UINTN Len; 840 VOID *Map; 841 842 PciIo = Ehc->PciIo; 843 Len = Urb->DataLen; 844 845 if (Urb->Ep.Direction == EfiUsbDataIn) { 846 MapOp = EfiPciIoOperationBusMasterWrite; 847 } else { 848 MapOp = EfiPciIoOperationBusMasterRead; 849 } 850 851 Status = PciIo->Unmap (PciIo, Urb->DataMap); 852 if (EFI_ERROR (Status)) { 853 goto ON_ERROR; 854 } 855 856 Urb->DataMap = NULL; 857 858 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map); 859 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) { 860 goto ON_ERROR; 861 } 862 863 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr); 864 Urb->DataMap = Map; 865 return EFI_SUCCESS; 866 867 ON_ERROR: 868 return EFI_DEVICE_ERROR; 869 } 870 871 872 /** 873 Update the queue head for next round of asynchronous transfer. 874 875 @param Ehc The EHCI device. 876 @param Urb The URB to update. 877 878 **/ 879 VOID 880 EhcUpdateAsyncRequest ( 881 IN USB2_HC_DEV *Ehc, 882 IN URB *Urb 883 ) 884 { 885 LIST_ENTRY *Entry; 886 EHC_QTD *FirstQtd; 887 QH_HW *QhHw; 888 EHC_QTD *Qtd; 889 QTD_HW *QtdHw; 890 UINTN Index; 891 EFI_PHYSICAL_ADDRESS PciAddr; 892 893 Qtd = NULL; 894 895 if (Urb->Result == EFI_USB_NOERROR) { 896 FirstQtd = NULL; 897 898 EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) { 899 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList); 900 901 if (FirstQtd == NULL) { 902 FirstQtd = Qtd; 903 } 904 905 // 906 // Update the QTD for next round of transfer. Host control 907 // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/ 908 // Current Offset. These fields need to be updated. DT isn't 909 // used by interrupt transfer. It uses DT in queue head. 910 // Current Offset is in Page[0], only need to reset Page[0] 911 // to initial data buffer. 912 // 913 QtdHw = &Qtd->QtdHw; 914 QtdHw->Status = QTD_STAT_ACTIVE; 915 QtdHw->ErrCnt = QTD_MAX_ERR; 916 QtdHw->CurPage = 0; 917 QtdHw->TotalBytes = (UINT32) Qtd->DataLen; 918 // 919 // calculate physical address by offset. 920 // 921 PciAddr = (UINTN)Urb->DataPhy + ((UINTN)Qtd->Data - (UINTN)Urb->Data); 922 QtdHw->Page[0] = EHC_LOW_32BIT (PciAddr); 923 QtdHw->PageHigh[0]= EHC_HIGH_32BIT (PciAddr); 924 } 925 926 // 927 // Update QH for next round of transfer. Host control only 928 // touch the fields in transfer overlay area. Only need to 929 // zero out the overlay area and set NextQtd to the first 930 // QTD. DateToggle bit is left untouched. 931 // 932 QhHw = &Urb->Qh->QhHw; 933 QhHw->CurQtd = QTD_LINK (0, TRUE); 934 QhHw->AltQtd = 0; 935 936 QhHw->Status = 0; 937 QhHw->Pid = 0; 938 QhHw->ErrCnt = 0; 939 QhHw->CurPage = 0; 940 QhHw->Ioc = 0; 941 QhHw->TotalBytes = 0; 942 943 for (Index = 0; Index < 5; Index++) { 944 QhHw->Page[Index] = 0; 945 QhHw->PageHigh[Index] = 0; 946 } 947 948 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, FirstQtd, sizeof (EHC_QTD)); 949 QhHw->NextQtd = QTD_LINK (PciAddr, FALSE); 950 } 951 952 return ; 953 } 954 955 956 /** 957 Interrupt transfer periodic check handler. 958 959 @param Event Interrupt event. 960 @param Context Pointer to USB2_HC_DEV. 961 962 **/ 963 VOID 964 EFIAPI 965 EhcMonitorAsyncRequests ( 966 IN EFI_EVENT Event, 967 IN VOID *Context 968 ) 969 { 970 USB2_HC_DEV *Ehc; 971 EFI_TPL OldTpl; 972 LIST_ENTRY *Entry; 973 LIST_ENTRY *Next; 974 BOOLEAN Finished; 975 UINT8 *ProcBuf; 976 URB *Urb; 977 EFI_STATUS Status; 978 979 OldTpl = gBS->RaiseTPL (EHC_TPL); 980 Ehc = (USB2_HC_DEV *) Context; 981 982 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) { 983 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList); 984 985 // 986 // Check the result of URB execution. If it is still 987 // active, check the next one. 988 // 989 Finished = EhcCheckUrbResult (Ehc, Urb); 990 991 if (!Finished) { 992 continue; 993 } 994 995 // 996 // Flush any PCI posted write transactions from a PCI host 997 // bridge to system memory. 998 // 999 Status = EhcFlushAsyncIntMap (Ehc, Urb); 1000 if (EFI_ERROR (Status)) { 1001 DEBUG ((EFI_D_ERROR, "EhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n")); 1002 } 1003 1004 // 1005 // Allocate a buffer then copy the transferred data for user. 1006 // If failed to allocate the buffer, update the URB for next 1007 // round of transfer. Ignore the data of this round. 1008 // 1009 ProcBuf = NULL; 1010 1011 if (Urb->Result == EFI_USB_NOERROR) { 1012 ASSERT (Urb->Completed <= Urb->DataLen); 1013 1014 ProcBuf = AllocatePool (Urb->Completed); 1015 1016 if (ProcBuf == NULL) { 1017 EhcUpdateAsyncRequest (Ehc, Urb); 1018 continue; 1019 } 1020 1021 CopyMem (ProcBuf, Urb->Data, Urb->Completed); 1022 } 1023 1024 EhcUpdateAsyncRequest (Ehc, Urb); 1025 1026 // 1027 // Leave error recovery to its related device driver. A 1028 // common case of the error recovery is to re-submit the 1029 // interrupt transfer which is linked to the head of the 1030 // list. This function scans from head to tail. So the 1031 // re-submitted interrupt transfer's callback function 1032 // will not be called again in this round. Don't touch this 1033 // URB after the callback, it may have been removed by the 1034 // callback. 1035 // 1036 if (Urb->Callback != NULL) { 1037 // 1038 // Restore the old TPL, USB bus maybe connect device in 1039 // his callback. Some drivers may has a lower TPL restriction. 1040 // 1041 gBS->RestoreTPL (OldTpl); 1042 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result); 1043 OldTpl = gBS->RaiseTPL (EHC_TPL); 1044 } 1045 1046 if (ProcBuf != NULL) { 1047 FreePool (ProcBuf); 1048 } 1049 } 1050 1051 gBS->RestoreTPL (OldTpl); 1052 } 1053