TianoCore EDK2 master
Loading...
Searching...
No Matches
EhciUrb.c
Go to the documentation of this file.
1
12#include "EhcPeim.h"
13
31 IN UINT8 *Data,
32 IN UINTN DataLen,
33 IN UINT8 PktId,
34 IN UINT8 Toggle,
35 IN UINTN MaxPacket
36 )
37{
38 PEI_EHC_QTD *Qtd;
39 QTD_HW *QtdHw;
40 UINTN Index;
41 UINTN Len;
42 UINTN ThisBufLen;
43
44 ASSERT (Ehc != NULL);
45
46 Qtd = UsbHcAllocateMem (Ehc, Ehc->MemPool, sizeof (PEI_EHC_QTD));
47
48 if (Qtd == NULL) {
49 return NULL;
50 }
51
52 Qtd->Signature = EHC_QTD_SIG;
53 Qtd->Data = Data;
54 Qtd->DataLen = 0;
55
56 InitializeListHead (&Qtd->QtdList);
57
58 QtdHw = &Qtd->QtdHw;
59 QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
60 QtdHw->AltNext = QTD_LINK (NULL, TRUE);
61 QtdHw->Status = QTD_STAT_ACTIVE;
62 QtdHw->Pid = PktId;
63 QtdHw->ErrCnt = QTD_MAX_ERR;
64 QtdHw->Ioc = 0;
65 QtdHw->TotalBytes = 0;
66 QtdHw->DataToggle = Toggle;
67
68 //
69 // Fill in the buffer points
70 //
71 if (Data != NULL) {
72 Len = 0;
73
74 for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
75 //
76 // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
77 // compute the offset and clear Reserved fields. This is already
78 // done in the data point.
79 //
80 QtdHw->Page[Index] = EHC_LOW_32BIT (Data);
81 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data);
82
83 ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);
84
85 if (Len + ThisBufLen >= DataLen) {
86 Len = DataLen;
87 break;
88 }
89
90 Len += ThisBufLen;
91 Data += ThisBufLen;
92 }
93
94 //
95 // Need to fix the last pointer if the Qtd can't hold all the
96 // user's data to make sure that the length is in the unit of
97 // max packets. If it can hold all the data, there is no such
98 // need.
99 //
100 if (Len < DataLen) {
101 Len = Len - Len % MaxPacket;
102 }
103
104 QtdHw->TotalBytes = (UINT32)Len;
105 Qtd->DataLen = Len;
106 }
107
108 return Qtd;
109}
110
122VOID
124 IN USB_ENDPOINT *Ep,
125 IN QH_HW *QhHw
126 )
127{
128 //
129 // Because UEFI interface can't utilitize an endpoint with
130 // poll rate faster than 1ms, only need to set one bit in
131 // the queue head. simple. But it may be changed later. If
132 // sub-1ms interrupt is supported, need to update the S-Mask
133 // here
134 //
135 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
136 QhHw->SMask = QH_MICROFRAME_0;
137 return;
138 }
139
140 //
141 // For low/full speed device, the transfer must go through
142 // the split transaction. Need to update three fields
143 // 1. SplitXState in the status
144 // 2. Microframe S-Mask
145 // 3. Microframe C-Mask
146 // UEFI USB doesn't exercise admission control. It simplely
147 // schedule the high speed transactions in microframe 0, and
148 // full/low speed transactions at microframe 1. This also
149 // avoid the use of FSTN.
150 //
151 QhHw->SMask = QH_MICROFRAME_1;
152 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
153}
154
166 IN PEI_USB2_HC_DEV *Ehci,
167 IN USB_ENDPOINT *Ep
168 )
169{
170 PEI_EHC_QH *Qh;
171 QH_HW *QhHw;
172
173 Qh = UsbHcAllocateMem (Ehci, Ehci->MemPool, sizeof (PEI_EHC_QH));
174
175 if (Qh == NULL) {
176 return NULL;
177 }
178
179 Qh->Signature = EHC_QH_SIG;
180 Qh->NextQh = NULL;
181 Qh->Interval = Ep->PollRate;
182
183 InitializeListHead (&Qh->Qtds);
184
185 QhHw = &Qh->QhHw;
186 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
187 QhHw->DeviceAddr = Ep->DevAddr;
188 QhHw->Inactive = 0;
189 QhHw->EpNum = Ep->EpAddr;
190 QhHw->EpSpeed = Ep->DevSpeed;
191 QhHw->DtCtrl = 0;
192 QhHw->ReclaimHead = 0;
193 QhHw->MaxPacketLen = (UINT32)Ep->MaxPacket;
194 QhHw->CtrlEp = 0;
195 QhHw->NakReload = QH_NAK_RELOAD;
196 QhHw->HubAddr = Ep->HubAddr;
197 QhHw->PortNum = Ep->HubPort;
198 QhHw->Multiplier = 1;
199 QhHw->DataToggle = Ep->Toggle;
200
201 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
202 QhHw->Status |= QTD_STAT_DO_SS;
203 }
204
205 switch (Ep->Type) {
206 case EHC_CTRL_TRANSFER:
207 //
208 // Special initialization for the control transfer:
209 // 1. Control transfer initialize data toggle from each QTD
210 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
211 //
212 QhHw->DtCtrl = 1;
213
214 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
215 QhHw->CtrlEp = 1;
216 }
217
218 break;
219
220 case EHC_INT_TRANSFER_ASYNC:
221 case EHC_INT_TRANSFER_SYNC:
222 //
223 // Special initialization for the interrupt transfer
224 // to set the S-Mask and C-Mask
225 //
226 QhHw->NakReload = 0;
227 EhcInitIntQh (Ep, QhHw);
228 break;
229
230 case EHC_BULK_TRANSFER:
231 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
232 QhHw->Status |= QTD_STAT_DO_PING;
233 }
234
235 break;
236 }
237
238 return Qh;
239}
240
254UINTN
256 IN UINTN Interval
257 )
258{
259 UINTN BitCount;
260
261 if (Interval == 0) {
262 return 1;
263 }
264
265 //
266 // Find the index (1 based) of the highest non-zero bit
267 //
268 BitCount = 0;
269
270 while (Interval != 0) {
271 Interval >>= 1;
272 BitCount++;
273 }
274
275 return (UINTN)1 << (BitCount - 1);
276}
277
285VOID
287 IN PEI_USB2_HC_DEV *Ehc,
288 IN EFI_LIST_ENTRY *Qtds
289 )
290{
291 EFI_LIST_ENTRY *Entry;
292 EFI_LIST_ENTRY *Next;
293 PEI_EHC_QTD *Qtd;
294
295 BASE_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
296 Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
297
298 RemoveEntryList (&Qtd->QtdList);
299 UsbHcFreeMem (Ehc, Ehc->MemPool, Qtd, sizeof (PEI_EHC_QTD));
300 }
301}
302
310VOID
312 IN PEI_USB2_HC_DEV *Ehc,
313 IN PEI_URB *Urb
314 )
315{
316 if (Urb->RequestPhy != NULL) {
317 IoMmuUnmap (Ehc->IoMmu, Urb->RequestMap);
318 }
319
320 if (Urb->DataMap != NULL) {
321 IoMmuUnmap (Ehc->IoMmu, Urb->DataMap);
322 }
323
324 if (Urb->Qh != NULL) {
325 //
326 // Ensure that this queue head has been unlinked from the
327 // schedule data structures. Free all the associated QTDs
328 //
329 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
330 UsbHcFreeMem (Ehc, Ehc->MemPool, Urb->Qh, sizeof (PEI_EHC_QH));
331 }
332}
333
346 IN PEI_USB2_HC_DEV *Ehc,
347 IN PEI_URB *Urb
348 )
349{
350 USB_ENDPOINT *Ep;
351 PEI_EHC_QH *Qh;
352 PEI_EHC_QTD *Qtd;
353 PEI_EHC_QTD *StatusQtd;
354 PEI_EHC_QTD *NextQtd;
355 EFI_LIST_ENTRY *Entry;
356 UINT32 AlterNext;
357 UINT8 Toggle;
358 UINTN Len;
359 UINT8 Pid;
360
361 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
362
363 //
364 // EHCI follows the alternet next QTD pointer if it meets
365 // a short read and the AlterNext pointer is valid. UEFI
366 // EHCI driver should terminate the transfer except the
367 // control transfer.
368 //
369 Toggle = 0;
370 Qh = Urb->Qh;
371 Ep = &Urb->Ep;
372 StatusQtd = NULL;
373 AlterNext = QTD_LINK (NULL, TRUE);
374
375 if (Ep->Direction == EfiUsbDataIn) {
376 AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);
377 }
378
379 //
380 // Build the Setup and status packets for control transfer
381 //
382 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
383 Len = sizeof (EFI_USB_DEVICE_REQUEST);
384 Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
385
386 if (Qtd == NULL) {
387 return EFI_OUT_OF_RESOURCES;
388 }
389
390 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
391
392 //
393 // Create the status packet now. Set the AlterNext to it. So, when
394 // EHCI meets a short control read, it can resume at the status stage.
395 // Use the opposite direction of the data stage, or IN if there is
396 // no data stage.
397 //
398 if (Ep->Direction == EfiUsbDataIn) {
399 Pid = QTD_PID_OUTPUT;
400 } else {
401 Pid = QTD_PID_INPUT;
402 }
403
404 StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);
405
406 if (StatusQtd == NULL) {
407 goto ON_ERROR;
408 }
409
410 if (Ep->Direction == EfiUsbDataIn) {
411 AlterNext = QTD_LINK (StatusQtd, FALSE);
412 }
413
414 Toggle = 1;
415 }
416
417 //
418 // Build the data packets for all the transfers
419 //
420 if (Ep->Direction == EfiUsbDataIn) {
421 Pid = QTD_PID_INPUT;
422 } else {
423 Pid = QTD_PID_OUTPUT;
424 }
425
426 Qtd = NULL;
427 Len = 0;
428
429 while (Len < Urb->DataLen) {
430 Qtd = EhcCreateQtd (
431 Ehc,
432 (UINT8 *)Urb->DataPhy + Len,
433 Urb->DataLen - Len,
434 Pid,
435 Toggle,
436 Ep->MaxPacket
437 );
438
439 if (Qtd == NULL) {
440 goto ON_ERROR;
441 }
442
443 Qtd->QtdHw.AltNext = AlterNext;
444 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
445
446 //
447 // Switch the Toggle bit if odd number of packets are included in the QTD.
448 //
449 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
450 Toggle = (UINT8)(1 - Toggle);
451 }
452
453 Len += Qtd->DataLen;
454 }
455
456 //
457 // Insert the status packet for control transfer
458 //
459 if (Ep->Type == EHC_CTRL_TRANSFER) {
460 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
461 }
462
463 //
464 // OK, all the QTDs needed are created. Now, fix the NextQtd point
465 //
466 BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {
467 Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
468
469 //
470 // break if it is the last entry on the list
471 //
472 if (Entry->ForwardLink == &Qh->Qtds) {
473 break;
474 }
475
476 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, PEI_EHC_QTD, QtdList);
477 Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);
478 }
479
480 //
481 // Link the QTDs to the queue head
482 //
483 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, PEI_EHC_QTD, QtdList);
484 Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);
485 return EFI_SUCCESS;
486
487ON_ERROR:
488 EhcFreeQtds (Ehc, &Qh->Qtds);
489 return EFI_OUT_OF_RESOURCES;
490}
491
513PEI_URB *
515 IN PEI_USB2_HC_DEV *Ehc,
516 IN UINT8 DevAddr,
517 IN UINT8 EpAddr,
518 IN UINT8 DevSpeed,
519 IN UINT8 Toggle,
520 IN UINTN MaxPacket,
522 IN UINTN Type,
523 IN EFI_USB_DEVICE_REQUEST *Request,
524 IN VOID *Data,
525 IN UINTN DataLen,
527 IN VOID *Context,
528 IN UINTN Interval
529 )
530{
531 USB_ENDPOINT *Ep;
532 EFI_PHYSICAL_ADDRESS PhyAddr;
534 EFI_STATUS Status;
535 UINTN Len;
536 PEI_URB *Urb;
537 VOID *Map;
538
539 Map = NULL;
540
541 Urb = Ehc->Urb;
542 Urb->Signature = EHC_URB_SIG;
543 InitializeListHead (&Urb->UrbList);
544
545 Ep = &Urb->Ep;
546 Ep->DevAddr = DevAddr;
547 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);
548 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
549 Ep->DevSpeed = DevSpeed;
550 Ep->MaxPacket = MaxPacket;
551
552 Ep->HubAddr = 0;
553 Ep->HubPort = 0;
554
555 if (DevSpeed != EFI_USB_SPEED_HIGH) {
556 ASSERT (Hub != NULL);
557
558 Ep->HubAddr = Hub->TranslatorHubAddress;
559 Ep->HubPort = Hub->TranslatorPortNumber;
560 }
561
562 Ep->Toggle = Toggle;
563 Ep->Type = Type;
564 Ep->PollRate = EhcConvertPollRate (Interval);
565
566 Urb->Request = Request;
567 Urb->Data = Data;
568 Urb->DataLen = DataLen;
569 Urb->Callback = Callback;
570 Urb->Context = Context;
571 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
572
573 if (Urb->Qh == NULL) {
574 goto ON_ERROR;
575 }
576
577 Urb->RequestPhy = NULL;
578 Urb->RequestMap = NULL;
579 Urb->DataPhy = NULL;
580 Urb->DataMap = NULL;
581
582 //
583 // Map the request and user data
584 //
585 if (Request != NULL) {
586 Len = sizeof (EFI_USB_DEVICE_REQUEST);
588 Status = IoMmuMap (Ehc->IoMmu, MapOp, Request, &Len, &PhyAddr, &Map);
589
590 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
591 goto ON_ERROR;
592 }
593
594 Urb->RequestPhy = (VOID *)((UINTN)PhyAddr);
595 Urb->RequestMap = Map;
596 }
597
598 if (Data != NULL) {
599 Len = DataLen;
600
601 if (Ep->Direction == EfiUsbDataIn) {
603 } else {
605 }
606
607 Status = IoMmuMap (Ehc->IoMmu, MapOp, Data, &Len, &PhyAddr, &Map);
608
609 if (EFI_ERROR (Status) || (Len != DataLen)) {
610 goto ON_ERROR;
611 }
612
613 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);
614 Urb->DataMap = Map;
615 }
616
617 Status = EhcCreateQtds (Ehc, Urb);
618
619 if (EFI_ERROR (Status)) {
620 goto ON_ERROR;
621 }
622
623 return Urb;
624
625ON_ERROR:
626 EhcFreeUrb (Ehc, Urb);
627 return NULL;
628}
UINT64 UINTN
EFI_STATUS IoMmuUnmap(IN VOID *Mapping)
Definition: DmaMem.c:132
EFI_STATUS IoMmuMap(IN EDKII_IOMMU_OPERATION Operation, IN VOID *HostAddress, IN OUT UINTN *NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: DmaMem.c:60
#define BASE_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead)
Definition: BaseLib.h:2929
#define BASE_LIST_FOR_EACH(Entry, ListHead)
Definition: BaseLib.h:2913
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID EhcFreeQtds(IN USB2_HC_DEV *Ehc, IN LIST_ENTRY *Qtds)
Definition: EhciUrb.c:288
VOID EhcInitIntQh(IN USB_ENDPOINT *Ep, IN QH_HW *QhHw)
Definition: EhciUrb.c:125
EFI_STATUS EhcCreateQtds(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciUrb.c:353
EHC_QTD * EhcCreateQtd(IN USB2_HC_DEV *Ehc, IN UINT8 *Data, IN UINT8 *DataPhy, IN UINTN DataLen, IN UINT8 PktId, IN UINT8 Toggle, IN UINTN MaxPacket)
Definition: EhciUrb.c:29
EHC_QH * EhcCreateQh(IN USB2_HC_DEV *Ehci, IN USB_ENDPOINT *Ep)
Definition: EhciUrb.c:167
UINTN EhcConvertPollRate(IN UINTN Interval)
Definition: EhciUrb.c:257
URB * EhcCreateUrb(IN USB2_HC_DEV *Ehc, IN UINT8 DevAddr, IN UINT8 EpAddr, IN UINT8 DevSpeed, IN UINT8 Toggle, IN UINTN MaxPacket, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub, IN UINTN Type, IN EFI_USB_DEVICE_REQUEST *Request, IN VOID *Data, IN UINTN DataLen, IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, IN VOID *Context, IN UINTN Interval)
Definition: EhciUrb.c:528
VOID EhcFreeUrb(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciUrb.c:313
VOID UsbHcFreeMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:493
VOID * UsbHcAllocateMem(IN USBHC_MEM_POOL *Pool, IN UINTN Size)
Definition: UsbHcMem.c:419
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
EFI_STATUS(EFIAPI * EFI_ASYNC_USB_TRANSFER_CALLBACK)(IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Status)
Definition: UsbIo.h:80
EDKII_IOMMU_OPERATION
Definition: IoMmu.h:44
@ EdkiiIoMmuOperationBusMasterWrite
Definition: IoMmu.h:54
@ EdkiiIoMmuOperationBusMasterRead
Definition: IoMmu.h:49
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
Definition: EhciUrb.h:104
Definition: EhciUrb.h:88