TianoCore EDK2 master
Loading...
Searching...
No Matches
EhciSched.c
Go to the documentation of this file.
1
11#include "Ehci.h"
12
24 IN USB2_HC_DEV *Ehc
25 )
26{
27 USB_ENDPOINT Ep;
28 EHC_QH *Qh;
29 QH_HW *QhHw;
30 EHC_QTD *Qtd;
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
103 IN USB2_HC_DEV *Ehc
104 )
105{
106 EFI_PCI_IO_PROTOCOL *PciIo;
107 VOID *Buf;
108 EFI_PHYSICAL_ADDRESS PhyAddr;
109 VOID *Map;
110 UINTN Pages;
111 UINTN Bytes;
112 UINTN Index;
113 EFI_STATUS Status;
114 EFI_PHYSICAL_ADDRESS PciAddr;
115
116 //
117 // First initialize the periodical schedule data:
118 // 1. Allocate and map the memory for the frame list
119 // 2. Create the help QTD/QH
120 // 3. Initialize the frame entries
121 // 4. Set the frame list register
122 //
123 PciIo = Ehc->PciIo;
124
125 Bytes = 4096;
126 Pages = EFI_SIZE_TO_PAGES (Bytes);
127
128 Status = PciIo->AllocateBuffer (
129 PciIo,
132 Pages,
133 &Buf,
134 0
135 );
136
137 if (EFI_ERROR (Status)) {
138 return EFI_OUT_OF_RESOURCES;
139 }
140
141 Status = PciIo->Map (
142 PciIo,
144 Buf,
145 &Bytes,
146 &PhyAddr,
147 &Map
148 );
149
150 if (EFI_ERROR (Status) || (Bytes != 4096)) {
151 PciIo->FreeBuffer (PciIo, Pages, Buf);
152 return EFI_OUT_OF_RESOURCES;
153 }
154
155 Ehc->PeriodFrame = Buf;
156 Ehc->PeriodFrameMap = Map;
157
158 //
159 // Program the FRAMELISTBASE register with the low 32 bit addr
160 //
161 EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (PhyAddr));
162 //
163 // Program the CTRLDSSEGMENT register with the high 32 bit addr
164 //
165 EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, EHC_HIGH_32BIT (PhyAddr));
166
167 //
168 // Init memory pool management then create the helper
169 // QTD/QH. If failed, previously allocated resources
170 // will be freed by EhcFreeSched
171 //
172 Ehc->MemPool = UsbHcInitMemPool (
173 PciIo,
174 Ehc->Support64BitDma,
175 EHC_HIGH_32BIT (PhyAddr)
176 );
177
178 if (Ehc->MemPool == NULL) {
179 Status = EFI_OUT_OF_RESOURCES;
180 goto ErrorExit1;
181 }
182
183 Status = EhcCreateHelpQ (Ehc);
184
185 if (EFI_ERROR (Status)) {
186 goto ErrorExit;
187 }
188
189 //
190 // Initialize the frame list entries then set the registers
191 //
192 Ehc->PeriodFrameHost = AllocateZeroPool (EHC_FRAME_LEN * sizeof (UINTN));
193 if (Ehc->PeriodFrameHost == NULL) {
194 Status = EFI_OUT_OF_RESOURCES;
195 goto ErrorExit;
196 }
197
198 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
199
200 for (Index = 0; Index < EHC_FRAME_LEN; Index++) {
201 //
202 // Store the pci bus address of the QH in period frame list which will be accessed by pci bus master.
203 //
204 ((UINT32 *)(Ehc->PeriodFrame))[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
205 //
206 // Store the host address of the QH in period frame list which will be accessed by host.
207 //
208 ((UINTN *)(Ehc->PeriodFrameHost))[Index] = (UINTN)Ehc->PeriodOne;
209 }
210
211 //
212 // Second initialize the asynchronous schedule:
213 // Only need to set the AsynListAddr register to
214 // the reclamation header
215 //
216 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
217 EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (PciAddr));
218 return EFI_SUCCESS;
219
220ErrorExit:
221 if (Ehc->PeriodOne != NULL) {
222 UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
223 Ehc->PeriodOne = NULL;
224 }
225
226 if (Ehc->ReclaimHead != NULL) {
227 UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
228 Ehc->ReclaimHead = NULL;
229 }
230
231 if (Ehc->ShortReadStop != NULL) {
232 UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
233 Ehc->ShortReadStop = NULL;
234 }
235
236ErrorExit1:
237 PciIo->FreeBuffer (PciIo, Pages, Buf);
238 PciIo->Unmap (PciIo, Map);
239
240 return Status;
241}
242
249VOID
251 IN USB2_HC_DEV *Ehc
252 )
253{
254 EFI_PCI_IO_PROTOCOL *PciIo;
255
256 EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);
257 EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);
258
259 if (Ehc->PeriodOne != NULL) {
260 UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
261 Ehc->PeriodOne = NULL;
262 }
263
264 if (Ehc->ReclaimHead != NULL) {
265 UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
266 Ehc->ReclaimHead = NULL;
267 }
268
269 if (Ehc->ShortReadStop != NULL) {
270 UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
271 Ehc->ShortReadStop = NULL;
272 }
273
274 if (Ehc->MemPool != NULL) {
275 UsbHcFreeMemPool (Ehc->MemPool);
276 Ehc->MemPool = NULL;
277 }
278
279 if (Ehc->PeriodFrame != NULL) {
280 PciIo = Ehc->PciIo;
281 ASSERT (PciIo != NULL);
282
283 PciIo->Unmap (PciIo, Ehc->PeriodFrameMap);
284
285 PciIo->FreeBuffer (
286 PciIo,
287 EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),
288 Ehc->PeriodFrame
289 );
290
291 Ehc->PeriodFrame = NULL;
292 }
293
294 if (Ehc->PeriodFrameHost != NULL) {
295 FreePool (Ehc->PeriodFrameHost);
296 Ehc->PeriodFrameHost = NULL;
297 }
298}
299
311VOID
313 IN USB2_HC_DEV *Ehc,
314 IN EHC_QH *Qh
315 )
316{
317 EHC_QH *Head;
318 EFI_PHYSICAL_ADDRESS PciAddr;
319
320 //
321 // Append the queue head after the reclaim header, then
322 // fix the hardware visiable parts (EHCI R1.0 page 72).
323 // ReclaimHead is always linked to the EHCI's AsynListAddr.
324 //
325 Head = Ehc->ReclaimHead;
326
327 Qh->NextQh = Head->NextQh;
328 Head->NextQh = Qh;
329
330 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh->NextQh, sizeof (EHC_QH));
331 Qh->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
332 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));
333 Head->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
334}
335
344VOID
346 IN USB2_HC_DEV *Ehc,
347 IN EHC_QH *Qh
348 )
349{
350 EHC_QH *Head;
351 EFI_STATUS Status;
352 EFI_PHYSICAL_ADDRESS PciAddr;
353
354 ASSERT (Ehc->ReclaimHead->NextQh == Qh);
355
356 //
357 // Remove the QH from reclamation head, then update the hardware
358 // visiable part: Only need to loopback the ReclaimHead. The Qh
359 // is pointing to ReclaimHead (which is staill in the list).
360 //
361 Head = Ehc->ReclaimHead;
362
363 Head->NextQh = Qh->NextQh;
364 Qh->NextQh = NULL;
365
366 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));
367 Head->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
368
369 //
370 // Set and wait the door bell to synchronize with the hardware
371 //
372 Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);
373
374 if (EFI_ERROR (Status)) {
375 DEBUG ((DEBUG_ERROR, "EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));
376 }
377}
378
388VOID
390 IN USB2_HC_DEV *Ehc,
391 IN EHC_QH *Qh
392 )
393{
394 UINTN Index;
395 EHC_QH *Prev;
396 EHC_QH *Next;
397 EFI_PHYSICAL_ADDRESS PciAddr;
398
399 for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
400 //
401 // First QH can't be NULL because we always keep PeriodOne
402 // heads on the frame list
403 //
404 ASSERT (!EHC_LINK_TERMINATED (((UINT32 *)Ehc->PeriodFrame)[Index]));
405 Next = (EHC_QH *)((UINTN *)Ehc->PeriodFrameHost)[Index];
406 Prev = NULL;
407
408 //
409 // Now, insert the queue head (Qh) into this frame:
410 // 1. Find a queue head with the same poll interval, just insert
411 // Qh after this queue head, then we are done.
412 //
413 // 2. Find the position to insert the queue head into:
414 // Previous head's interval is bigger than Qh's
415 // Next head's interval is less than Qh's
416 // Then, insert the Qh between then
417 //
418 while (Next->Interval > Qh->Interval) {
419 Prev = Next;
420 Next = Next->NextQh;
421 }
422
423 ASSERT (Next != NULL);
424
425 //
426 // The entry may have been linked into the frame by early insertation.
427 // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
428 // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
429 // It isn't necessary to compare all the QH with the same interval to
430 // Qh. This is because if there is other QH with the same interval, Qh
431 // should has been inserted after that at Frames[0] and at Frames[0] it is
432 // impossible for (Next == Qh)
433 //
434 if (Next == Qh) {
435 continue;
436 }
437
438 if (Next->Interval == Qh->Interval) {
439 //
440 // If there is a QH with the same interval, it locates at
441 // Frames[0], and we can simply insert it after this QH. We
442 // are all done.
443 //
444 ASSERT ((Index == 0) && (Qh->NextQh == NULL));
445
446 Prev = Next;
447 Next = Next->NextQh;
448
449 Qh->NextQh = Next;
450 Prev->NextQh = Qh;
451
452 Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink;
453 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
454 Prev->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
455 break;
456 }
457
458 //
459 // OK, find the right position, insert it in. If Qh's next
460 // link has already been set, it is in position. This is
461 // guarranted by 2^n polling interval.
462 //
463 if (Qh->NextQh == NULL) {
464 Qh->NextQh = Next;
465 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Next, sizeof (EHC_QH));
466 Qh->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
467 }
468
469 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
470
471 if (Prev == NULL) {
472 ((UINT32 *)Ehc->PeriodFrame)[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
473 ((UINTN *)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh;
474 } else {
475 Prev->NextQh = Qh;
476 Prev->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
477 }
478 }
479}
480
489VOID
491 IN USB2_HC_DEV *Ehc,
492 IN EHC_QH *Qh
493 )
494{
495 UINTN Index;
496 EHC_QH *Prev;
497 EHC_QH *This;
498
499 for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
500 //
501 // Frame link can't be NULL because we always keep PeroidOne
502 // on the frame list
503 //
504 ASSERT (!EHC_LINK_TERMINATED (((UINT32 *)Ehc->PeriodFrame)[Index]));
505 This = (EHC_QH *)((UINTN *)Ehc->PeriodFrameHost)[Index];
506 Prev = NULL;
507
508 //
509 // Walk through the frame's QH list to find the
510 // queue head to remove
511 //
512 while ((This != NULL) && (This != Qh)) {
513 Prev = This;
514 This = This->NextQh;
515 }
516
517 //
518 // Qh may have already been unlinked from this frame
519 // by early action. See the comments in EhcLinkQhToPeriod.
520 //
521 if (This == NULL) {
522 continue;
523 }
524
525 if (Prev == NULL) {
526 //
527 // Qh is the first entry in the frame
528 //
529 ((UINT32 *)Ehc->PeriodFrame)[Index] = Qh->QhHw.HorizonLink;
530 ((UINTN *)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh->NextQh;
531 } else {
532 Prev->NextQh = Qh->NextQh;
533 Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink;
534 }
535 }
536}
537
548BOOLEAN
550 IN USB2_HC_DEV *Ehc,
551 IN URB *Urb
552 )
553{
554 LIST_ENTRY *Entry;
555 EHC_QTD *Qtd;
556 QTD_HW *QtdHw;
557 UINT8 State;
558 BOOLEAN Finished;
559 EFI_PHYSICAL_ADDRESS PciAddr;
560
561 ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));
562
563 Finished = TRUE;
564 Urb->Completed = 0;
565
566 Urb->Result = EFI_USB_NOERROR;
567
568 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
569 Urb->Result |= EFI_USB_ERR_SYSTEM;
570 goto ON_EXIT;
571 }
572
573 BASE_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
574 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
575 QtdHw = &Qtd->QtdHw;
576 State = (UINT8)QtdHw->Status;
577
578 if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
579 //
580 // EHCI will halt the queue head when met some error.
581 // If it is halted, the result of URB is finialized.
582 //
583 if ((State & QTD_STAT_ERR_MASK) == 0) {
584 Urb->Result |= EFI_USB_ERR_STALL;
585 }
586
587 if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
588 Urb->Result |= EFI_USB_ERR_BABBLE;
589 }
590
591 if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
592 Urb->Result |= EFI_USB_ERR_BUFFER;
593 }
594
595 if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {
596 Urb->Result |= EFI_USB_ERR_TIMEOUT;
597 }
598
599 Finished = TRUE;
600 goto ON_EXIT;
601 } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
602 //
603 // The QTD is still active, no need to check furthur.
604 //
605 Urb->Result |= EFI_USB_ERR_NOTEXECUTE;
606
607 Finished = FALSE;
608 goto ON_EXIT;
609 } else {
610 //
611 // This QTD is finished OK or met short packet read. Update the
612 // transfer length if it isn't a setup.
613 //
614 if (QtdHw->Pid != QTD_PID_SETUP) {
615 Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;
616 }
617
618 if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {
619 EhcDumpQh (Urb->Qh, "Short packet read", FALSE);
620
621 //
622 // Short packet read condition. If it isn't a setup transfer,
623 // no need to check furthur: the queue head will halt at the
624 // ShortReadStop. If it is a setup transfer, need to check the
625 // Status Stage of the setup transfer to get the finial result
626 //
627 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
628 if (QtdHw->AltNext == QTD_LINK (PciAddr, FALSE)) {
629 DEBUG ((DEBUG_VERBOSE, "EhcCheckUrbResult: Short packet read, break\n"));
630
631 Finished = TRUE;
632 goto ON_EXIT;
633 }
634
635 DEBUG ((DEBUG_VERBOSE, "EhcCheckUrbResult: Short packet read, continue\n"));
636 }
637 }
638 }
639
640ON_EXIT:
641 //
642 // Return the data toggle set by EHCI hardware, bulk and interrupt
643 // transfer will use this to initialize the next transaction. For
644 // Control transfer, it always start a new data toggle sequence for
645 // new transfer.
646 //
647 // NOTICE: don't move DT update before the loop, otherwise there is
648 // a race condition that DT is wrong.
649 //
650 Urb->DataToggle = (UINT8)Urb->Qh->QhHw.DataToggle;
651
652 return Finished;
653}
654
669 IN USB2_HC_DEV *Ehc,
670 IN URB *Urb,
671 IN UINTN TimeOut
672 )
673{
674 EFI_STATUS Status;
675 UINTN Index;
676 UINTN Loop;
677 BOOLEAN Finished;
678 BOOLEAN InfiniteLoop;
679
680 Status = EFI_SUCCESS;
681 Loop = TimeOut * EHC_1_MILLISECOND;
682 Finished = FALSE;
683 InfiniteLoop = FALSE;
684
685 //
686 // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller
687 // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR
688 // is returned.
689 //
690 if (TimeOut == 0) {
691 InfiniteLoop = TRUE;
692 }
693
694 for (Index = 0; InfiniteLoop || (Index < Loop); Index++) {
695 Finished = EhcCheckUrbResult (Ehc, Urb);
696
697 if (Finished) {
698 break;
699 }
700
701 gBS->Stall (EHC_1_MICROSECOND);
702 }
703
704 if (!Finished) {
705 DEBUG ((DEBUG_VERBOSE, "EhcExecTransfer: transfer not finished in %dms\n", (UINT32)TimeOut));
706 EhcDumpQh (Urb->Qh, NULL, FALSE);
707
708 Status = EFI_TIMEOUT;
709 } else if (Urb->Result != EFI_USB_NOERROR) {
710 DEBUG ((DEBUG_ERROR, "EhcExecTransfer: transfer failed with %x\n", Urb->Result));
711 EhcDumpQh (Urb->Qh, NULL, FALSE);
712
713 Status = EFI_DEVICE_ERROR;
714 }
715
716 return Status;
717}
718
734 IN USB2_HC_DEV *Ehc,
735 IN UINT8 DevAddr,
736 IN UINT8 EpNum,
737 OUT UINT8 *DataToggle
738 )
739{
740 LIST_ENTRY *Entry;
741 LIST_ENTRY *Next;
742 URB *Urb;
743 EFI_USB_DATA_DIRECTION Direction;
744
745 Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
746 EpNum &= 0x0F;
747
748 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
749 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
750
751 if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) &&
752 (Urb->Ep.Direction == Direction))
753 {
754 //
755 // Check the URB status to retrieve the next data toggle
756 // from the associated queue head.
757 //
758 EhcCheckUrbResult (Ehc, Urb);
759 *DataToggle = Urb->DataToggle;
760
761 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
762 RemoveEntryList (&Urb->UrbList);
763
764 gBS->FreePool (Urb->Data);
765 EhcFreeUrb (Ehc, Urb);
766 return EFI_SUCCESS;
767 }
768 }
769
770 return EFI_NOT_FOUND;
771}
772
779VOID
781 IN USB2_HC_DEV *Ehc
782 )
783{
784 LIST_ENTRY *Entry;
785 LIST_ENTRY *Next;
786 URB *Urb;
787
788 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
789 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
790
791 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
792 RemoveEntryList (&Urb->UrbList);
793
794 gBS->FreePool (Urb->Data);
795 EhcFreeUrb (Ehc, Urb);
796 }
797}
798
818URB *
820 IN USB2_HC_DEV *Ehc,
821 IN UINT8 DevAddr,
822 IN UINT8 EpAddr,
823 IN UINT8 DevSpeed,
824 IN UINT8 Toggle,
825 IN UINTN MaxPacket,
827 IN UINTN DataLen,
829 IN VOID *Context,
830 IN UINTN Interval
831 )
832{
833 VOID *Data;
834 URB *Urb;
835
836 Data = AllocatePool (DataLen);
837
838 if (Data == NULL) {
839 DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __func__));
840 return NULL;
841 }
842
843 Urb = EhcCreateUrb (
844 Ehc,
845 DevAddr,
846 EpAddr,
847 DevSpeed,
848 Toggle,
849 MaxPacket,
850 Hub,
851 EHC_INT_TRANSFER_ASYNC,
852 NULL,
853 Data,
854 DataLen,
855 Callback,
856 Context,
857 Interval
858 );
859
860 if (Urb == NULL) {
861 DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __func__));
862 gBS->FreePool (Data);
863 return NULL;
864 }
865
866 //
867 // New asynchronous transfer must inserted to the head.
868 // Check the comments in EhcMoniteAsyncRequests
869 //
870 EhcLinkQhToPeriod (Ehc, Urb->Qh);
871 InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);
872
873 return Urb;
874}
875
889 IN USB2_HC_DEV *Ehc,
890 IN URB *Urb
891 )
892{
893 EFI_STATUS Status;
894 EFI_PHYSICAL_ADDRESS PhyAddr;
896 EFI_PCI_IO_PROTOCOL *PciIo;
897 UINTN Len;
898 VOID *Map;
899
900 PciIo = Ehc->PciIo;
901 Len = Urb->DataLen;
902
903 if (Urb->Ep.Direction == EfiUsbDataIn) {
905 } else {
907 }
908
909 Status = PciIo->Unmap (PciIo, Urb->DataMap);
910 if (EFI_ERROR (Status)) {
911 goto ON_ERROR;
912 }
913
914 Urb->DataMap = NULL;
915
916 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
917 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
918 goto ON_ERROR;
919 }
920
921 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);
922 Urb->DataMap = Map;
923 return EFI_SUCCESS;
924
925ON_ERROR:
926 return EFI_DEVICE_ERROR;
927}
928
936VOID
938 IN USB2_HC_DEV *Ehc,
939 IN URB *Urb
940 )
941{
942 LIST_ENTRY *Entry;
943 EHC_QTD *FirstQtd;
944 QH_HW *QhHw;
945 EHC_QTD *Qtd;
946 QTD_HW *QtdHw;
947 UINTN Index;
948 EFI_PHYSICAL_ADDRESS PciAddr;
949
950 Qtd = NULL;
951
952 if (Urb->Result == EFI_USB_NOERROR) {
953 FirstQtd = NULL;
954
955 BASE_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
956 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
957
958 if (FirstQtd == NULL) {
959 FirstQtd = Qtd;
960 }
961
962 //
963 // Update the QTD for next round of transfer. Host control
964 // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/
965 // Current Offset. These fields need to be updated. DT isn't
966 // used by interrupt transfer. It uses DT in queue head.
967 // Current Offset is in Page[0], only need to reset Page[0]
968 // to initial data buffer.
969 //
970 QtdHw = &Qtd->QtdHw;
971 QtdHw->Status = QTD_STAT_ACTIVE;
972 QtdHw->ErrCnt = QTD_MAX_ERR;
973 QtdHw->CurPage = 0;
974 QtdHw->TotalBytes = (UINT32)Qtd->DataLen;
975 //
976 // calculate physical address by offset.
977 //
978 PciAddr = (UINTN)Urb->DataPhy + ((UINTN)Qtd->Data - (UINTN)Urb->Data);
979 QtdHw->Page[0] = EHC_LOW_32BIT (PciAddr);
980 QtdHw->PageHigh[0] = EHC_HIGH_32BIT (PciAddr);
981 }
982
983 //
984 // Update QH for next round of transfer. Host control only
985 // touch the fields in transfer overlay area. Only need to
986 // zero out the overlay area and set NextQtd to the first
987 // QTD. DateToggle bit is left untouched.
988 //
989 QhHw = &Urb->Qh->QhHw;
990 QhHw->CurQtd = QTD_LINK (0, TRUE);
991 QhHw->AltQtd = 0;
992
993 QhHw->Status = 0;
994 QhHw->Pid = 0;
995 QhHw->ErrCnt = 0;
996 QhHw->CurPage = 0;
997 QhHw->Ioc = 0;
998 QhHw->TotalBytes = 0;
999
1000 for (Index = 0; Index < 5; Index++) {
1001 QhHw->Page[Index] = 0;
1002 QhHw->PageHigh[Index] = 0;
1003 }
1004
1005 PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, FirstQtd, sizeof (EHC_QTD));
1006 QhHw->NextQtd = QTD_LINK (PciAddr, FALSE);
1007 }
1008
1009 return;
1010}
1011
1019VOID
1020EFIAPI
1022 IN EFI_EVENT Event,
1023 IN VOID *Context
1024 )
1025{
1026 USB2_HC_DEV *Ehc;
1027 EFI_TPL OldTpl;
1028 LIST_ENTRY *Entry;
1029 LIST_ENTRY *Next;
1030 BOOLEAN Finished;
1031 UINT8 *ProcBuf;
1032 URB *Urb;
1033 EFI_STATUS Status;
1034
1035 OldTpl = gBS->RaiseTPL (EHC_TPL);
1036 Ehc = (USB2_HC_DEV *)Context;
1037
1038 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
1039 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1040
1041 //
1042 // Check the result of URB execution. If it is still
1043 // active, check the next one.
1044 //
1045 Finished = EhcCheckUrbResult (Ehc, Urb);
1046
1047 if (!Finished) {
1048 continue;
1049 }
1050
1051 //
1052 // Flush any PCI posted write transactions from a PCI host
1053 // bridge to system memory.
1054 //
1055 Status = EhcFlushAsyncIntMap (Ehc, Urb);
1056 if (EFI_ERROR (Status)) {
1057 DEBUG ((DEBUG_ERROR, "EhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1058 }
1059
1060 //
1061 // Allocate a buffer then copy the transferred data for user.
1062 // If failed to allocate the buffer, update the URB for next
1063 // round of transfer. Ignore the data of this round.
1064 //
1065 ProcBuf = NULL;
1066
1067 if (Urb->Result == EFI_USB_NOERROR) {
1068 //
1069 // Make sure the data received from HW is no more than expected.
1070 //
1071 if (Urb->Completed <= Urb->DataLen) {
1072 ProcBuf = AllocatePool (Urb->Completed);
1073 }
1074
1075 if (ProcBuf == NULL) {
1076 EhcUpdateAsyncRequest (Ehc, Urb);
1077 continue;
1078 }
1079
1080 CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1081 }
1082
1083 EhcUpdateAsyncRequest (Ehc, Urb);
1084
1085 //
1086 // Leave error recovery to its related device driver. A
1087 // common case of the error recovery is to re-submit the
1088 // interrupt transfer which is linked to the head of the
1089 // list. This function scans from head to tail. So the
1090 // re-submitted interrupt transfer's callback function
1091 // will not be called again in this round. Don't touch this
1092 // URB after the callback, it may have been removed by the
1093 // callback.
1094 //
1095 if (Urb->Callback != NULL) {
1096 //
1097 // Restore the old TPL, USB bus maybe connect device in
1098 // his callback. Some drivers may has a lower TPL restriction.
1099 //
1100 gBS->RestoreTPL (OldTpl);
1101 (Urb->Callback)(ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1102 OldTpl = gBS->RaiseTPL (EHC_TPL);
1103 }
1104
1105 if (ProcBuf != NULL) {
1106 FreePool (ProcBuf);
1107 }
1108 }
1109
1110 gBS->RestoreTPL (OldTpl);
1111}
UINT64 UINTN
LIST_ENTRY *EFIAPI InsertHeadList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:218
#define BASE_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead)
Definition: BaseLib.h:2929
#define BASE_LIST_FOR_EACH(Entry, ListHead)
Definition: BaseLib.h:2913
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID EhcDumpQh(IN EHC_QH *Qh, IN CHAR8 *Msg, IN BOOLEAN DumpBuf)
Definition: EhciDebug.c:116
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)
Definition: EhciSched.c:819
BOOLEAN EhcCheckUrbResult(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciSched.c:549
EFI_STATUS EhcInitSched(IN USB2_HC_DEV *Ehc)
Definition: EhciSched.c:102
EFI_STATUS EhciDelAsyncIntTransfer(IN USB2_HC_DEV *Ehc, IN UINT8 DevAddr, IN UINT8 EpNum, OUT UINT8 *DataToggle)
Definition: EhciSched.c:733
VOID EhcLinkQhToAsync(IN USB2_HC_DEV *Ehc, IN EHC_QH *Qh)
Definition: EhciSched.c:312
VOID EhcUpdateAsyncRequest(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciSched.c:937
VOID EhcFreeSched(IN USB2_HC_DEV *Ehc)
Definition: EhciSched.c:250
VOID EFIAPI EhcMonitorAsyncRequests(IN EFI_EVENT Event, IN VOID *Context)
Definition: EhciSched.c:1021
EFI_STATUS EhcCreateHelpQ(IN USB2_HC_DEV *Ehc)
Definition: EhciSched.c:23
EFI_STATUS EhcExecTransfer(IN USB2_HC_DEV *Ehc, IN URB *Urb, IN UINTN TimeOut)
Definition: EhciSched.c:668
VOID EhcUnlinkQhFromPeriod(IN USB2_HC_DEV *Ehc, IN EHC_QH *Qh)
Definition: EhciSched.c:490
VOID EhciDelAllAsyncIntTransfers(IN USB2_HC_DEV *Ehc)
Definition: EhciSched.c:780
VOID EhcLinkQhToPeriod(IN USB2_HC_DEV *Ehc, IN EHC_QH *Qh)
Definition: EhciSched.c:389
VOID EhcUnlinkQhFromAsync(IN USB2_HC_DEV *Ehc, IN EHC_QH *Qh)
Definition: EhciSched.c:345
EFI_STATUS EhcFlushAsyncIntMap(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciSched.c:888
EHC_QTD * EhcCreateQtd(IN USB2_HC_DEV *Ehc, IN UINT8 *Data, IN UINT8 *DataPhy, IN UINTN DataLen, IN UINT8 PktId, IN UINT8 Toggle, IN UINTN MaxPacket)
Definition: EhciUrb.c:29
EHC_QH * EhcCreateQh(IN USB2_HC_DEV *Ehci, IN USB_ENDPOINT *Ep)
Definition: EhciUrb.c:167
URB * EhcCreateUrb(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 Type, IN EFI_USB_DEVICE_REQUEST *Request, IN VOID *Data, IN UINTN DataLen, IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, IN VOID *Context, IN UINTN Interval)
Definition: EhciUrb.c:528
VOID EhcFreeUrb(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciUrb.c:313
EFI_PHYSICAL_ADDRESS UsbHcGetPciAddressForHostMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:223
EFI_STATUS UsbHcFreeMemPool(IN USBHC_MEM_POOL *Pool)
Definition: UsbHcMem.c:385
VOID UsbHcFreeMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:493
USBHC_MEM_POOL * UsbHcInitMemPool(IN EFI_PCI_IO_PROTOCOL *PciIo, IN BOOLEAN Check4G, IN UINT32 Which4G)
Definition: UsbHcMem.c:348
VOID EhcWriteOpReg(IN USB2_HC_DEV *Ehc, IN UINT32 Offset, IN UINT32 Data)
Definition: EhciReg.c:183
EFI_STATUS EhcSetAndWaitDoorBell(IN USB2_HC_DEV *Ehc, IN UINT32 Timeout)
Definition: EhciReg.c:343
BOOLEAN EhcIsHalt(IN USB2_HC_DEV *Ehc)
Definition: EhciReg.c:442
BOOLEAN EhcIsSysError(IN USB2_HC_DEV *Ehc)
Definition: EhciReg.c:459
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_PCI_IO_PROTOCOL_OPERATION
Definition: PciIo.h:77
@ EfiPciIoOperationBusMasterWrite
Definition: PciIo.h:85
@ EfiPciIoOperationBusMasterRead
Definition: PciIo.h:81
@ EfiPciIoOperationBusMasterCommonBuffer
Definition: PciIo.h:90
EFI_USB_DATA_DIRECTION
Definition: UsbIo.h:44
EFI_STATUS(EFIAPI * EFI_ASYNC_USB_TRANSFER_CALLBACK)(IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Status)
Definition: UsbIo.h:80
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ EfiBootServicesData
@ AllocateAnyPages
Definition: UefiSpec.h:33
Definition: EhciUrb.h:200
Definition: EhciUrb.h:104
Definition: EhciUrb.h:88