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