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