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