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