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) 2010, 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 "EhcPeim.h" 19 20 /** 21 Delete a single asynchronous interrupt transfer for 22 the device and endpoint. 23 24 @param Ehc The EHCI device. 25 @param Data Current data not associated with a QTD. 26 @param DataLen The length of the data. 27 @param PktId Packet ID to use in the QTD. 28 @param Toggle Data toggle to use in the QTD. 29 @param MaxPacket Maximu packet length of the endpoint. 30 31 @retval the pointer to the created QTD or NULL if failed to create one. 32 33 **/ 34 PEI_EHC_QTD * 35 EhcCreateQtd ( 36 IN PEI_USB2_HC_DEV *Ehc, 37 IN UINT8 *Data, 38 IN UINTN DataLen, 39 IN UINT8 PktId, 40 IN UINT8 Toggle, 41 IN UINTN MaxPacket 42 ) 43 { 44 PEI_EHC_QTD *Qtd; 45 QTD_HW *QtdHw; 46 UINTN Index; 47 UINTN Len; 48 UINTN ThisBufLen; 49 50 ASSERT (Ehc != NULL); 51 52 Qtd = UsbHcAllocateMem (Ehc, Ehc->MemPool, sizeof (PEI_EHC_QTD)); 53 54 if (Qtd == NULL) { 55 return NULL; 56 } 57 58 Qtd->Signature = EHC_QTD_SIG; 59 Qtd->Data = Data; 60 Qtd->DataLen = 0; 61 62 InitializeListHead (&Qtd->QtdList); 63 64 QtdHw = &Qtd->QtdHw; 65 QtdHw->NextQtd = QTD_LINK (NULL, TRUE); 66 QtdHw->AltNext = QTD_LINK (NULL, TRUE); 67 QtdHw->Status = QTD_STAT_ACTIVE; 68 QtdHw->Pid = PktId; 69 QtdHw->ErrCnt = QTD_MAX_ERR; 70 QtdHw->Ioc = 0; 71 QtdHw->TotalBytes = 0; 72 QtdHw->DataToggle = Toggle; 73 74 // 75 // Fill in the buffer points 76 // 77 if (Data != NULL) { 78 Len = 0; 79 80 for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) { 81 // 82 // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to 83 // compute the offset and clear Reserved fields. This is already 84 // done in the data point. 85 // 86 QtdHw->Page[Index] = EHC_LOW_32BIT (Data); 87 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data); 88 89 ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK); 90 91 if (Len + ThisBufLen >= DataLen) { 92 Len = DataLen; 93 break; 94 } 95 96 Len += ThisBufLen; 97 Data += ThisBufLen; 98 } 99 100 // 101 // Need to fix the last pointer if the Qtd can't hold all the 102 // user's data to make sure that the length is in the unit of 103 // max packets. If it can hold all the data, there is no such 104 // need. 105 // 106 if (Len < DataLen) { 107 Len = Len - Len % MaxPacket; 108 } 109 110 QtdHw->TotalBytes = (UINT32) Len; 111 Qtd->DataLen = Len; 112 } 113 114 return Qtd; 115 } 116 117 /** 118 Initialize the queue head for interrupt transfer, 119 that is, initialize the following three fields: 120 1. SplitXState in the Status field. 121 2. Microframe S-mask. 122 3. Microframe C-mask. 123 124 @param Ep The queue head's related endpoint. 125 @param QhHw The queue head to initialize. 126 127 **/ 128 VOID 129 EhcInitIntQh ( 130 IN USB_ENDPOINT *Ep, 131 IN QH_HW *QhHw 132 ) 133 { 134 // 135 // Because UEFI interface can't utilitize an endpoint with 136 // poll rate faster than 1ms, only need to set one bit in 137 // the queue head. simple. But it may be changed later. If 138 // sub-1ms interrupt is supported, need to update the S-Mask 139 // here 140 // 141 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) { 142 QhHw->SMask = QH_MICROFRAME_0; 143 return ; 144 } 145 146 // 147 // For low/full speed device, the transfer must go through 148 // the split transaction. Need to update three fields 149 // 1. SplitXState in the status 150 // 2. Microframe S-Mask 151 // 3. Microframe C-Mask 152 // UEFI USB doesn't exercise admission control. It simplely 153 // schedule the high speed transactions in microframe 0, and 154 // full/low speed transactions at microframe 1. This also 155 // avoid the use of FSTN. 156 // 157 QhHw->SMask = QH_MICROFRAME_1; 158 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5; 159 } 160 161 /** 162 Allocate and initialize a EHCI queue head. 163 164 @param Ehci The EHCI device. 165 @param Ep The endpoint to create queue head for. 166 167 @retval the pointer to the created queue head or NULL if failed to create one. 168 169 **/ 170 PEI_EHC_QH * 171 EhcCreateQh ( 172 IN PEI_USB2_HC_DEV *Ehci, 173 IN USB_ENDPOINT *Ep 174 ) 175 { 176 PEI_EHC_QH *Qh; 177 QH_HW *QhHw; 178 179 Qh = UsbHcAllocateMem (Ehci, Ehci->MemPool, sizeof (PEI_EHC_QH)); 180 181 if (Qh == NULL) { 182 return NULL; 183 } 184 185 Qh->Signature = EHC_QH_SIG; 186 Qh->NextQh = NULL; 187 Qh->Interval = Ep->PollRate; 188 189 InitializeListHead (&Qh->Qtds); 190 191 QhHw = &Qh->QhHw; 192 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE); 193 QhHw->DeviceAddr = Ep->DevAddr; 194 QhHw->Inactive = 0; 195 QhHw->EpNum = Ep->EpAddr; 196 QhHw->EpSpeed = Ep->DevSpeed; 197 QhHw->DtCtrl = 0; 198 QhHw->ReclaimHead = 0; 199 QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket; 200 QhHw->CtrlEp = 0; 201 QhHw->NakReload = QH_NAK_RELOAD; 202 QhHw->HubAddr = Ep->HubAddr; 203 QhHw->PortNum = Ep->HubPort; 204 QhHw->Multiplier = 1; 205 QhHw->DataToggle = Ep->Toggle; 206 207 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) { 208 QhHw->Status |= QTD_STAT_DO_SS; 209 } 210 211 switch (Ep->Type) { 212 case EHC_CTRL_TRANSFER: 213 // 214 // Special initialization for the control transfer: 215 // 1. Control transfer initialize data toggle from each QTD 216 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint. 217 // 218 QhHw->DtCtrl = 1; 219 220 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) { 221 QhHw->CtrlEp = 1; 222 } 223 break; 224 225 case EHC_INT_TRANSFER_ASYNC: 226 case EHC_INT_TRANSFER_SYNC: 227 // 228 // Special initialization for the interrupt transfer 229 // to set the S-Mask and C-Mask 230 // 231 QhHw->NakReload = 0; 232 EhcInitIntQh (Ep, QhHw); 233 break; 234 235 case EHC_BULK_TRANSFER: 236 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) { 237 QhHw->Status |= QTD_STAT_DO_PING; 238 } 239 240 break; 241 } 242 243 return Qh; 244 } 245 246 /** 247 Convert the poll interval from application to that 248 be used by EHCI interface data structure. Only need 249 to get the max 2^n that is less than interval. UEFI 250 can't support high speed endpoint with a interval less 251 than 8 microframe because interval is specified in 252 the unit of ms (millisecond). 253 254 @param Interval The interval to convert. 255 256 @retval The converted interval. 257 258 **/ 259 UINTN 260 EhcConvertPollRate ( 261 IN UINTN Interval 262 ) 263 { 264 UINTN BitCount; 265 266 if (Interval == 0) { 267 return 1; 268 } 269 270 // 271 // Find the index (1 based) of the highest non-zero bit 272 // 273 BitCount = 0; 274 275 while (Interval != 0) { 276 Interval >>= 1; 277 BitCount++; 278 } 279 280 return (UINTN)1 << (BitCount - 1); 281 } 282 283 /** 284 Free a list of QTDs. 285 286 @param Ehc The EHCI device. 287 @param Qtds The list head of the QTD. 288 289 **/ 290 VOID 291 EhcFreeQtds ( 292 IN PEI_USB2_HC_DEV *Ehc, 293 IN EFI_LIST_ENTRY *Qtds 294 ) 295 { 296 EFI_LIST_ENTRY *Entry; 297 EFI_LIST_ENTRY *Next; 298 PEI_EHC_QTD *Qtd; 299 300 EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) { 301 Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList); 302 303 RemoveEntryList (&Qtd->QtdList); 304 UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (PEI_EHC_QTD)); 305 } 306 } 307 308 /** 309 Free an allocated URB. It is possible for it to be partially inited. 310 311 @param Ehc The EHCI device. 312 @param Urb The URB to free. 313 314 **/ 315 VOID 316 EhcFreeUrb ( 317 IN PEI_USB2_HC_DEV *Ehc, 318 IN PEI_URB *Urb 319 ) 320 { 321 if (Urb->Qh != NULL) { 322 // 323 // Ensure that this queue head has been unlinked from the 324 // schedule data structures. Free all the associated QTDs 325 // 326 EhcFreeQtds (Ehc, &Urb->Qh->Qtds); 327 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (PEI_EHC_QH)); 328 } 329 } 330 331 /** 332 Create a list of QTDs for the URB. 333 334 @param Ehc The EHCI device. 335 @param Urb The URB to create QTDs for. 336 337 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD. 338 @retval EFI_SUCCESS The QTDs are allocated for the URB. 339 340 **/ 341 EFI_STATUS 342 EhcCreateQtds ( 343 IN PEI_USB2_HC_DEV *Ehc, 344 IN PEI_URB *Urb 345 ) 346 { 347 USB_ENDPOINT *Ep; 348 PEI_EHC_QH *Qh; 349 PEI_EHC_QTD *Qtd; 350 PEI_EHC_QTD *StatusQtd; 351 PEI_EHC_QTD *NextQtd; 352 EFI_LIST_ENTRY *Entry; 353 UINT32 AlterNext; 354 UINT8 Toggle; 355 UINTN Len; 356 UINT8 Pid; 357 358 ASSERT ((Urb != NULL) && (Urb->Qh != NULL)); 359 360 // 361 // EHCI follows the alternet next QTD pointer if it meets 362 // a short read and the AlterNext pointer is valid. UEFI 363 // EHCI driver should terminate the transfer except the 364 // control transfer. 365 // 366 Toggle = 0; 367 Qh = Urb->Qh; 368 Ep = &Urb->Ep; 369 StatusQtd = NULL; 370 AlterNext = QTD_LINK (NULL, TRUE); 371 372 if (Ep->Direction == EfiUsbDataIn) { 373 AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE); 374 } 375 376 // 377 // Build the Setup and status packets for control transfer 378 // 379 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) { 380 Len = sizeof (EFI_USB_DEVICE_REQUEST); 381 Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket); 382 383 if (Qtd == NULL) { 384 return EFI_OUT_OF_RESOURCES; 385 } 386 387 InsertTailList (&Qh->Qtds, &Qtd->QtdList); 388 389 // 390 // Create the status packet now. Set the AlterNext to it. So, when 391 // EHCI meets a short control read, it can resume at the status stage. 392 // Use the opposite direction of the data stage, or IN if there is 393 // no data stage. 394 // 395 if (Ep->Direction == EfiUsbDataIn) { 396 Pid = QTD_PID_OUTPUT; 397 } else { 398 Pid = QTD_PID_INPUT; 399 } 400 401 StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket); 402 403 if (StatusQtd == NULL) { 404 goto ON_ERROR; 405 } 406 407 if (Ep->Direction == EfiUsbDataIn) { 408 AlterNext = QTD_LINK (StatusQtd, FALSE); 409 } 410 411 Toggle = 1; 412 } 413 414 // 415 // Build the data packets for all the transfers 416 // 417 if (Ep->Direction == EfiUsbDataIn) { 418 Pid = QTD_PID_INPUT; 419 } else { 420 Pid = QTD_PID_OUTPUT; 421 } 422 423 Qtd = NULL; 424 Len = 0; 425 426 while (Len < Urb->DataLen) { 427 Qtd = EhcCreateQtd ( 428 Ehc, 429 (UINT8 *) Urb->DataPhy + Len, 430 Urb->DataLen - Len, 431 Pid, 432 Toggle, 433 Ep->MaxPacket 434 ); 435 436 if (Qtd == NULL) { 437 goto ON_ERROR; 438 } 439 440 Qtd->QtdHw.AltNext = AlterNext; 441 InsertTailList (&Qh->Qtds, &Qtd->QtdList); 442 443 // 444 // Switch the Toggle bit if odd number of packets are included in the QTD. 445 // 446 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) { 447 Toggle = (UINT8) (1 - Toggle); 448 } 449 450 Len += Qtd->DataLen; 451 } 452 453 // 454 // Insert the status packet for control transfer 455 // 456 if (Ep->Type == EHC_CTRL_TRANSFER) { 457 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList); 458 } 459 460 // 461 // OK, all the QTDs needed are created. Now, fix the NextQtd point 462 // 463 EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) { 464 Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList); 465 466 // 467 // break if it is the last entry on the list 468 // 469 if (Entry->ForwardLink == &Qh->Qtds) { 470 break; 471 } 472 473 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, PEI_EHC_QTD, QtdList); 474 Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE); 475 } 476 477 // 478 // Link the QTDs to the queue head 479 // 480 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, PEI_EHC_QTD, QtdList); 481 Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE); 482 return EFI_SUCCESS; 483 484 ON_ERROR: 485 EhcFreeQtds (Ehc, &Qh->Qtds); 486 return EFI_OUT_OF_RESOURCES; 487 } 488 489 /** 490 Create a new URB and its associated QTD. 491 492 @param Ehc The EHCI device. 493 @param DevAddr The device address. 494 @param EpAddr Endpoint addrress & its direction. 495 @param DevSpeed The device speed. 496 @param Toggle Initial data toggle to use. 497 @param MaxPacket The max packet length of the endpoint. 498 @param Hub The transaction translator to use. 499 @param Type The transaction type. 500 @param Request The standard USB request for control transfer. 501 @param Data The user data to transfer. 502 @param DataLen The length of data buffer. 503 @param Callback The function to call when data is transferred. 504 @param Context The context to the callback. 505 @param Interval The interval for interrupt transfer. 506 507 @retval the pointer to the created URB or NULL. 508 509 **/ 510 PEI_URB * 511 EhcCreateUrb ( 512 IN PEI_USB2_HC_DEV *Ehc, 513 IN UINT8 DevAddr, 514 IN UINT8 EpAddr, 515 IN UINT8 DevSpeed, 516 IN UINT8 Toggle, 517 IN UINTN MaxPacket, 518 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub, 519 IN UINTN Type, 520 IN EFI_USB_DEVICE_REQUEST *Request, 521 IN VOID *Data, 522 IN UINTN DataLen, 523 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, 524 IN VOID *Context, 525 IN UINTN Interval 526 ) 527 { 528 USB_ENDPOINT *Ep; 529 EFI_PHYSICAL_ADDRESS PhyAddr; 530 EFI_STATUS Status; 531 UINTN Len; 532 PEI_URB *Urb; 533 VOID *Map; 534 535 536 Map = NULL; 537 538 Urb = Ehc->Urb; 539 Urb->Signature = EHC_URB_SIG; 540 InitializeListHead (&Urb->UrbList); 541 542 Ep = &Urb->Ep; 543 Ep->DevAddr = DevAddr; 544 Ep->EpAddr = (UINT8) (EpAddr & 0x0F); 545 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut); 546 Ep->DevSpeed = DevSpeed; 547 Ep->MaxPacket = MaxPacket; 548 549 Ep->HubAddr = 0; 550 Ep->HubPort = 0; 551 552 if (DevSpeed != EFI_USB_SPEED_HIGH) { 553 ASSERT (Hub != NULL); 554 555 Ep->HubAddr = Hub->TranslatorHubAddress; 556 Ep->HubPort = Hub->TranslatorPortNumber; 557 } 558 559 Ep->Toggle = Toggle; 560 Ep->Type = Type; 561 Ep->PollRate = EhcConvertPollRate (Interval); 562 563 Urb->Request = Request; 564 Urb->Data = Data; 565 Urb->DataLen = DataLen; 566 Urb->Callback = Callback; 567 Urb->Context = Context; 568 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep); 569 570 if (Urb->Qh == NULL) { 571 goto ON_ERROR; 572 } 573 574 // 575 // Map the request and user data 576 // 577 if (Request != NULL) { 578 Len = sizeof (EFI_USB_DEVICE_REQUEST); 579 PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) Request ; 580 if ( (Len != sizeof (EFI_USB_DEVICE_REQUEST))) { 581 goto ON_ERROR; 582 } 583 584 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr); 585 Urb->RequestMap = Map; 586 } 587 588 if (Data != NULL) { 589 Len = DataLen; 590 PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) Data ; 591 if ( (Len != DataLen)) { 592 goto ON_ERROR; 593 } 594 595 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr); 596 Urb->DataMap = Map; 597 } 598 599 Status = EhcCreateQtds (Ehc, Urb); 600 601 if (EFI_ERROR (Status)) { 602 goto ON_ERROR; 603 } 604 605 return Urb; 606 607 ON_ERROR: 608 EhcFreeUrb (Ehc, Urb); 609 return NULL; 610 } 611