]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
MdeModulePkg EhciDxe: Use common buffer for AsyncInterruptTransfer
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / EhciUrb.c
1 /** @file
2
3 This file contains URB request, each request is warpped in a
4 URB (Usb Request Block).
5
6 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Ehci.h"
18
19
20 /**
21 Create a single QTD to hold the data.
22
23 @param Ehc The EHCI device.
24 @param Data The cpu memory address of current data not associated with a QTD.
25 @param DataPhy The pci bus address of current data not associated with a QTD.
26 @param DataLen The length of the data.
27 @param PktId Packet ID to use in the QTD.
28 @param Toggle Data toggle to use in the QTD.
29 @param MaxPacket Maximu packet length of the endpoint.
30
31 @return Created QTD or NULL if failed to create one.
32
33 **/
34 EHC_QTD *
35 EhcCreateQtd (
36 IN USB2_HC_DEV *Ehc,
37 IN UINT8 *Data,
38 IN UINT8 *DataPhy,
39 IN UINTN DataLen,
40 IN UINT8 PktId,
41 IN UINT8 Toggle,
42 IN UINTN MaxPacket
43 )
44 {
45 EHC_QTD *Qtd;
46 QTD_HW *QtdHw;
47 UINTN Index;
48 UINTN Len;
49 UINTN ThisBufLen;
50
51 ASSERT (Ehc != NULL);
52
53 Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));
54
55 if (Qtd == NULL) {
56 return NULL;
57 }
58
59 Qtd->Signature = EHC_QTD_SIG;
60 Qtd->Data = Data;
61 Qtd->DataLen = 0;
62
63 InitializeListHead (&Qtd->QtdList);
64
65 QtdHw = &Qtd->QtdHw;
66 QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
67 QtdHw->AltNext = QTD_LINK (NULL, TRUE);
68 QtdHw->Status = QTD_STAT_ACTIVE;
69 QtdHw->Pid = PktId;
70 QtdHw->ErrCnt = QTD_MAX_ERR;
71 QtdHw->Ioc = 0;
72 QtdHw->TotalBytes = 0;
73 QtdHw->DataToggle = Toggle;
74
75 //
76 // Fill in the buffer points
77 //
78 if (Data != NULL) {
79 Len = 0;
80
81 for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
82 //
83 // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
84 // compute the offset and clear Reserved fields. This is already
85 // done in the data point.
86 //
87 QtdHw->Page[Index] = EHC_LOW_32BIT (DataPhy);
88 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (DataPhy);
89
90 ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (DataPhy) & QTD_BUF_MASK);
91
92 if (Len + ThisBufLen >= DataLen) {
93 Len = DataLen;
94 break;
95 }
96
97 Len += ThisBufLen;
98 Data += ThisBufLen;
99 DataPhy += ThisBufLen;
100 }
101
102 //
103 // Need to fix the last pointer if the Qtd can't hold all the
104 // user's data to make sure that the length is in the unit of
105 // max packets. If it can hold all the data, there is no such
106 // need.
107 //
108 if (Len < DataLen) {
109 Len = Len - Len % MaxPacket;
110 }
111
112 QtdHw->TotalBytes = (UINT32) Len;
113 Qtd->DataLen = Len;
114 }
115
116 return Qtd;
117 }
118
119
120
121 /**
122 Initialize the queue head for interrupt transfer,
123 that is, initialize the following three fields:
124 1. SplitXState in the Status field
125 2. Microframe S-mask
126 3. Microframe C-mask
127
128 @param Ep The queue head's related endpoint.
129 @param QhHw The queue head to initialize.
130
131 **/
132 VOID
133 EhcInitIntQh (
134 IN USB_ENDPOINT *Ep,
135 IN QH_HW *QhHw
136 )
137 {
138 //
139 // Because UEFI interface can't utilitize an endpoint with
140 // poll rate faster than 1ms, only need to set one bit in
141 // the queue head. simple. But it may be changed later. If
142 // sub-1ms interrupt is supported, need to update the S-Mask
143 // here
144 //
145 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
146 QhHw->SMask = QH_MICROFRAME_0;
147 return ;
148 }
149
150 //
151 // For low/full speed device, the transfer must go through
152 // the split transaction. Need to update three fields
153 // 1. SplitXState in the status
154 // 2. Microframe S-Mask
155 // 3. Microframe C-Mask
156 // UEFI USB doesn't exercise admission control. It simplely
157 // schedule the high speed transactions in microframe 0, and
158 // full/low speed transactions at microframe 1. This also
159 // avoid the use of FSTN.
160 //
161 QhHw->SMask = QH_MICROFRAME_1;
162 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
163 }
164
165
166
167 /**
168 Allocate and initialize a EHCI queue head.
169
170 @param Ehci The EHCI device.
171 @param Ep The endpoint to create queue head for.
172
173 @return Created queue head or NULL if failed to create one.
174
175 **/
176 EHC_QH *
177 EhcCreateQh (
178 IN USB2_HC_DEV *Ehci,
179 IN USB_ENDPOINT *Ep
180 )
181 {
182 EHC_QH *Qh;
183 QH_HW *QhHw;
184
185 Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));
186
187 if (Qh == NULL) {
188 return NULL;
189 }
190
191 Qh->Signature = EHC_QH_SIG;
192 Qh->NextQh = NULL;
193 Qh->Interval = Ep->PollRate;
194
195 InitializeListHead (&Qh->Qtds);
196
197 QhHw = &Qh->QhHw;
198 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
199 QhHw->DeviceAddr = Ep->DevAddr;
200 QhHw->Inactive = 0;
201 QhHw->EpNum = Ep->EpAddr;
202 QhHw->EpSpeed = Ep->DevSpeed;
203 QhHw->DtCtrl = 0;
204 QhHw->ReclaimHead = 0;
205 QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;
206 QhHw->CtrlEp = 0;
207 QhHw->NakReload = QH_NAK_RELOAD;
208 QhHw->HubAddr = Ep->HubAddr;
209 QhHw->PortNum = Ep->HubPort;
210 QhHw->Multiplier = 1;
211 QhHw->DataToggle = Ep->Toggle;
212
213 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
214 QhHw->Status |= QTD_STAT_DO_SS;
215 }
216
217 switch (Ep->Type) {
218 case EHC_CTRL_TRANSFER:
219 //
220 // Special initialization for the control transfer:
221 // 1. Control transfer initialize data toggle from each QTD
222 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
223 //
224 QhHw->DtCtrl = 1;
225
226 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
227 QhHw->CtrlEp = 1;
228 }
229 break;
230
231 case EHC_INT_TRANSFER_ASYNC:
232 case EHC_INT_TRANSFER_SYNC:
233 //
234 // Special initialization for the interrupt transfer
235 // to set the S-Mask and C-Mask
236 //
237 QhHw->NakReload = 0;
238 EhcInitIntQh (Ep, QhHw);
239 break;
240
241 case EHC_BULK_TRANSFER:
242 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
243 QhHw->Status |= QTD_STAT_DO_PING;
244 }
245
246 break;
247 }
248
249 return Qh;
250 }
251
252
253 /**
254 Convert the poll interval from application to that
255 be used by EHCI interface data structure. Only need
256 to get the max 2^n that is less than interval. UEFI
257 can't support high speed endpoint with a interval less
258 than 8 microframe because interval is specified in
259 the unit of ms (millisecond).
260
261 @param Interval The interval to convert.
262
263 @return The converted interval.
264
265 **/
266 UINTN
267 EhcConvertPollRate (
268 IN UINTN Interval
269 )
270 {
271 UINTN BitCount;
272
273 if (Interval == 0) {
274 return 1;
275 }
276
277 //
278 // Find the index (1 based) of the highest non-zero bit
279 //
280 BitCount = 0;
281
282 while (Interval != 0) {
283 Interval >>= 1;
284 BitCount++;
285 }
286
287 return (UINTN)1 << (BitCount - 1);
288 }
289
290
291 /**
292 Free a list of QTDs.
293
294 @param Ehc The EHCI device.
295 @param Qtds The list head of the QTD.
296
297 **/
298 VOID
299 EhcFreeQtds (
300 IN USB2_HC_DEV *Ehc,
301 IN LIST_ENTRY *Qtds
302 )
303 {
304 LIST_ENTRY *Entry;
305 LIST_ENTRY *Next;
306 EHC_QTD *Qtd;
307
308 EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
309 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
310
311 RemoveEntryList (&Qtd->QtdList);
312 UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));
313 }
314 }
315
316
317 /**
318 Free an allocated URB. It is possible for it to be partially inited.
319
320 @param Ehc The EHCI device.
321 @param Urb The URB to free.
322
323 **/
324 VOID
325 EhcFreeUrb (
326 IN USB2_HC_DEV *Ehc,
327 IN URB *Urb
328 )
329 {
330 EFI_PCI_IO_PROTOCOL *PciIo;
331
332 PciIo = Ehc->PciIo;
333
334 if (Urb->RequestPhy != NULL) {
335 PciIo->Unmap (PciIo, Urb->RequestMap);
336 }
337
338 if (Urb->DataMap != NULL) {
339 PciIo->Unmap (PciIo, Urb->DataMap);
340 }
341
342 if (Urb->AllocateCommonBuffer) {
343 PciIo->FreeBuffer (
344 PciIo,
345 EFI_SIZE_TO_PAGES (Urb->DataLen),
346 Urb->Data
347 );
348 }
349
350 if (Urb->Qh != NULL) {
351 //
352 // Ensure that this queue head has been unlinked from the
353 // schedule data structures. Free all the associated QTDs
354 //
355 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
356 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));
357 }
358
359 gBS->FreePool (Urb);
360 }
361
362
363 /**
364 Create a list of QTDs for the URB.
365
366 @param Ehc The EHCI device.
367 @param Urb The URB to create QTDs for.
368
369 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
370 @retval EFI_SUCCESS The QTDs are allocated for the URB.
371
372 **/
373 EFI_STATUS
374 EhcCreateQtds (
375 IN USB2_HC_DEV *Ehc,
376 IN URB *Urb
377 )
378 {
379 USB_ENDPOINT *Ep;
380 EHC_QH *Qh;
381 EHC_QTD *Qtd;
382 EHC_QTD *StatusQtd;
383 EHC_QTD *NextQtd;
384 LIST_ENTRY *Entry;
385 UINT32 AlterNext;
386 UINT8 Toggle;
387 UINTN Len;
388 UINT8 Pid;
389 EFI_PHYSICAL_ADDRESS PhyAddr;
390
391 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
392
393 //
394 // EHCI follows the alternet next QTD pointer if it meets
395 // a short read and the AlterNext pointer is valid. UEFI
396 // EHCI driver should terminate the transfer except the
397 // control transfer.
398 //
399 Toggle = 0;
400 Qh = Urb->Qh;
401 Ep = &Urb->Ep;
402 StatusQtd = NULL;
403 AlterNext = QTD_LINK (NULL, TRUE);
404
405 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
406 if (Ep->Direction == EfiUsbDataIn) {
407 AlterNext = QTD_LINK (PhyAddr, FALSE);
408 }
409
410 //
411 // Build the Setup and status packets for control transfer
412 //
413 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
414 Len = sizeof (EFI_USB_DEVICE_REQUEST);
415 Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
416
417 if (Qtd == NULL) {
418 return EFI_OUT_OF_RESOURCES;
419 }
420
421 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
422
423 //
424 // Create the status packet now. Set the AlterNext to it. So, when
425 // EHCI meets a short control read, it can resume at the status stage.
426 // Use the opposite direction of the data stage, or IN if there is
427 // no data stage.
428 //
429 if (Ep->Direction == EfiUsbDataIn) {
430 Pid = QTD_PID_OUTPUT;
431 } else {
432 Pid = QTD_PID_INPUT;
433 }
434
435 StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);
436
437 if (StatusQtd == NULL) {
438 goto ON_ERROR;
439 }
440
441 if (Ep->Direction == EfiUsbDataIn) {
442 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));
443 AlterNext = QTD_LINK (PhyAddr, FALSE);
444 }
445
446 Toggle = 1;
447 }
448
449 //
450 // Build the data packets for all the transfers
451 //
452 if (Ep->Direction == EfiUsbDataIn) {
453 Pid = QTD_PID_INPUT;
454 } else {
455 Pid = QTD_PID_OUTPUT;
456 }
457
458 Qtd = NULL;
459 Len = 0;
460
461 while (Len < Urb->DataLen) {
462 Qtd = EhcCreateQtd (
463 Ehc,
464 (UINT8 *) Urb->Data + Len,
465 (UINT8 *) Urb->DataPhy + Len,
466 Urb->DataLen - Len,
467 Pid,
468 Toggle,
469 Ep->MaxPacket
470 );
471
472 if (Qtd == NULL) {
473 goto ON_ERROR;
474 }
475
476 Qtd->QtdHw.AltNext = AlterNext;
477 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
478
479 //
480 // Switch the Toggle bit if odd number of packets are included in the QTD.
481 //
482 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
483 Toggle = (UINT8) (1 - Toggle);
484 }
485
486 Len += Qtd->DataLen;
487 }
488
489 //
490 // Insert the status packet for control transfer
491 //
492 if (Ep->Type == EHC_CTRL_TRANSFER) {
493 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
494 }
495
496 //
497 // OK, all the QTDs needed are created. Now, fix the NextQtd point
498 //
499 EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {
500 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
501
502 //
503 // break if it is the last entry on the list
504 //
505 if (Entry->ForwardLink == &Qh->Qtds) {
506 break;
507 }
508
509 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);
510 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
511 Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
512 }
513
514 //
515 // Link the QTDs to the queue head
516 //
517 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);
518 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
519 Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
520 return EFI_SUCCESS;
521
522 ON_ERROR:
523 EhcFreeQtds (Ehc, &Qh->Qtds);
524 return EFI_OUT_OF_RESOURCES;
525 }
526
527
528 /**
529 Create a new URB and its associated QTD.
530
531 @param Ehc The EHCI device.
532 @param DevAddr The device address.
533 @param EpAddr Endpoint addrress & its direction.
534 @param DevSpeed The device speed.
535 @param Toggle Initial data toggle to use.
536 @param MaxPacket The max packet length of the endpoint.
537 @param Hub The transaction translator to use.
538 @param Type The transaction type.
539 @param Request The standard USB request for control transfer.
540 @param AllocateCommonBuffer Indicate whether need to allocate common buffer for data transfer.
541 @param Data The user data to transfer, NULL if AllocateCommonBuffer is TRUE.
542 @param DataLen The length of data buffer.
543 @param Callback The function to call when data is transferred.
544 @param Context The context to the callback.
545 @param Interval The interval for interrupt transfer.
546
547 @return Created URB or NULL.
548
549 **/
550 URB *
551 EhcCreateUrb (
552 IN USB2_HC_DEV *Ehc,
553 IN UINT8 DevAddr,
554 IN UINT8 EpAddr,
555 IN UINT8 DevSpeed,
556 IN UINT8 Toggle,
557 IN UINTN MaxPacket,
558 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
559 IN UINTN Type,
560 IN EFI_USB_DEVICE_REQUEST *Request,
561 IN BOOLEAN AllocateCommonBuffer,
562 IN VOID *Data,
563 IN UINTN DataLen,
564 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
565 IN VOID *Context,
566 IN UINTN Interval
567 )
568 {
569 USB_ENDPOINT *Ep;
570 EFI_PHYSICAL_ADDRESS PhyAddr;
571 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
572 EFI_PCI_IO_PROTOCOL *PciIo;
573 EFI_STATUS Status;
574 UINTN Len;
575 URB *Urb;
576 VOID *Map;
577
578 Urb = AllocateZeroPool (sizeof (URB));
579
580 if (Urb == NULL) {
581 return NULL;
582 }
583
584 Urb->Signature = EHC_URB_SIG;
585 InitializeListHead (&Urb->UrbList);
586
587 Ep = &Urb->Ep;
588 Ep->DevAddr = DevAddr;
589 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);
590 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
591 Ep->DevSpeed = DevSpeed;
592 Ep->MaxPacket = MaxPacket;
593
594 Ep->HubAddr = 0;
595 Ep->HubPort = 0;
596
597 if (DevSpeed != EFI_USB_SPEED_HIGH) {
598 ASSERT (Hub != NULL);
599
600 Ep->HubAddr = Hub->TranslatorHubAddress;
601 Ep->HubPort = Hub->TranslatorPortNumber;
602 }
603
604 Ep->Toggle = Toggle;
605 Ep->Type = Type;
606 Ep->PollRate = EhcConvertPollRate (Interval);
607
608 Urb->Request = Request;
609 if (AllocateCommonBuffer) {
610 ASSERT (Data == NULL);
611 Status = Ehc->PciIo->AllocateBuffer (
612 Ehc->PciIo,
613 AllocateAnyPages,
614 EfiBootServicesData,
615 EFI_SIZE_TO_PAGES (DataLen),
616 &Data,
617 0
618 );
619 if (EFI_ERROR (Status) || (Data == NULL)) {
620 FreePool (Urb);
621 return NULL;
622 }
623 }
624 Urb->Data = Data;
625 Urb->DataLen = DataLen;
626 Urb->AllocateCommonBuffer = AllocateCommonBuffer;
627 Urb->Callback = Callback;
628 Urb->Context = Context;
629
630 PciIo = Ehc->PciIo;
631 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
632
633 if (Urb->Qh == NULL) {
634 goto ON_ERROR;
635 }
636
637 //
638 // Map the request and user data
639 //
640 if (Request != NULL) {
641 Len = sizeof (EFI_USB_DEVICE_REQUEST);
642 MapOp = EfiPciIoOperationBusMasterRead;
643 Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);
644
645 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
646 goto ON_ERROR;
647 }
648
649 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
650 Urb->RequestMap = Map;
651 }
652
653 if (Data != NULL) {
654 Len = DataLen;
655
656 if (Urb->AllocateCommonBuffer) {
657 MapOp = EfiPciIoOperationBusMasterCommonBuffer;
658 } else {
659 if (Ep->Direction == EfiUsbDataIn) {
660 MapOp = EfiPciIoOperationBusMasterWrite;
661 } else {
662 MapOp = EfiPciIoOperationBusMasterRead;
663 }
664 }
665
666 Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);
667
668 if (EFI_ERROR (Status) || (Len != DataLen)) {
669 goto ON_ERROR;
670 }
671
672 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
673 Urb->DataMap = Map;
674 }
675
676 Status = EhcCreateQtds (Ehc, Urb);
677
678 if (EFI_ERROR (Status)) {
679 goto ON_ERROR;
680 }
681
682 return Urb;
683
684 ON_ERROR:
685 EhcFreeUrb (Ehc, Urb);
686 return NULL;
687 }