TianoCore EDK2 master
Loading...
Searching...
No Matches
DebugCommunicationLibUsb3Transfer.c
Go to the documentation of this file.
1
9
20EFIAPI
23 IN TRANSFER_RING *TrsRing
24 )
25{
26 UINTN Index;
27 TRB_TEMPLATE *TrsTrb;
28 UINT32 CycleBit;
29
30 ASSERT (TrsRing != NULL);
31
32 //
33 // Calculate the latest RingEnqueue and RingPCS
34 //
35 TrsTrb = (TRB_TEMPLATE *)(UINTN)TrsRing->RingEnqueue;
36
37 ASSERT (TrsTrb != NULL);
38
39 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
40 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
41 break;
42 }
43
44 TrsTrb++;
45 if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {
46 ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);
47 //
48 // set cycle bit in Link TRB as normal
49 //
50 ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
51 //
52 // Toggle PCS maintained by software
53 //
54 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
55 TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
56 }
57 }
58
59 ASSERT (Index != TrsRing->TrbNumber);
60
61 if ((EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb != TrsRing->RingEnqueue) {
62 TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb;
63 }
64
65 //
66 // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
67 //
68 CycleBit = TrsTrb->CycleBit;
69 ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
70 TrsTrb->CycleBit = CycleBit;
71
72 return EFI_SUCCESS;
73}
74
85EFIAPI
88 IN EVENT_RING *EvtRing
89 )
90{
91 UINTN Index;
92 TRB_TEMPLATE *EvtTrb1;
93
94 ASSERT (EvtRing != NULL);
95
96 //
97 // Calculate the EventRingEnqueue and EventRingCCS.
98 // Note: only support single Segment
99 //
100 EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
101
102 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
103 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
104 break;
105 }
106
107 EvtTrb1++;
108
109 if ((UINTN)EvtTrb1 >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
110 EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingSeg0;
111 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
112 }
113 }
114
115 if (Index < EvtRing->TrbNumber) {
116 EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
117 } else {
118 ASSERT (FALSE);
119 }
120
121 return EFI_SUCCESS;
122}
123
136EFIAPI
139 IN EVENT_RING *EvtRing,
140 OUT TRB_TEMPLATE **NewEvtTrb
141 )
142{
143 EFI_STATUS Status;
144
145 ASSERT (EvtRing != NULL);
146
147 *NewEvtTrb = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
148
149 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
150 return EFI_NOT_READY;
151 }
152
153 Status = EFI_SUCCESS;
154
155 EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
156 //
157 // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
158 //
159 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
160 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
161 }
162
163 return Status;
164}
165
176BOOLEAN
178 IN TRANSFER_RING *Ring,
179 IN TRB_TEMPLATE *Trb
180 )
181{
182 TRB_TEMPLATE *CheckedTrb;
183 UINTN Index;
184
185 CheckedTrb = (TRB_TEMPLATE *)(UINTN)Ring->RingSeg0;
186
187 ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
188
189 for (Index = 0; Index < Ring->TrbNumber; Index++) {
190 if (Trb == CheckedTrb) {
191 return TRUE;
192 }
193
194 CheckedTrb++;
195 }
196
197 return FALSE;
198}
199
208VOID
211 IN URB *Urb
212 )
213{
214 EVT_TRB_TRANSFER *EvtTrb;
215 TRB_TEMPLATE *TRBPtr;
216 UINTN Index;
217 EFI_STATUS Status;
218 URB *CheckedUrb;
219 UINT64 XhcDequeue;
220 UINT32 High;
221 UINT32 Low;
222
223 ASSERT ((Handle != NULL) && (Urb != NULL));
224
225 if (Urb->Finished) {
226 goto EXIT;
227 }
228
229 EvtTrb = NULL;
230
231 //
232 // Traverse the event ring to find out all new events from the previous check.
233 //
234 XhcSyncEventRing (Handle, &Handle->EventRing);
235
236 for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
237 Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
238 if (Status == EFI_NOT_READY) {
239 //
240 // All new events are handled, return directly.
241 //
242 goto EXIT;
243 }
244
245 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
246 continue;
247 }
248
249 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));
250
251 if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
252 CheckedUrb = Urb;
253 } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
254 //
255 // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
256 // Internal buffer is used by next read.
257 //
258 Handle->DataCount = (UINT8)(Handle->UrbIn.DataLen - EvtTrb->Length);
259 CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
260 //
261 // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
262 //
263 TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
264 continue;
265 } else {
266 continue;
267 }
268
269 if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
270 (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS))
271 {
272 //
273 // The length of data which were transferred.
274 //
275 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);
276 } else {
277 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
278 }
279
280 //
281 // This Urb has been processed
282 //
283 CheckedUrb->Finished = TRUE;
284 }
285
286EXIT:
287 //
288 // Advance event ring to last available entry
289 //
290 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
291 // So divide it to two 32-bytes width register access.
292 //
293 Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
294 High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
295 XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);
296
297 if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
298 //
299 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
300 // So divide it to two 32-bytes width register access.
301 //
302 XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));
303 XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));
304 }
305}
306
317EFIAPI
320 IN URB *Urb
321 )
322{
323 UINT32 Dcdb;
324
325 //
326 // 7.6.8.2 DCDB Register
327 //
328 Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
329
331 Handle,
332 XHC_DC_DCDB,
333 Dcdb
334 );
335
336 return EFI_SUCCESS;
337}
338
347VOID
350 IN URB *Urb,
351 IN UINTN Timeout
352 )
353{
354 TRANSFER_RING *Ring;
355 TRB_TEMPLATE *Trb;
356 UINTN Loop;
357 UINTN Index;
358
359 Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
360 if (Timeout == 0) {
361 Loop = 0xFFFFFFFF;
362 }
363
364 XhcRingDoorBell (Handle, Urb);
365 //
366 // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
367 //
368 for (Index = 0; Index < Loop; Index++) {
369 XhcCheckUrbResult (Handle, Urb);
370 if (Urb->Finished) {
371 break;
372 }
373
374 MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
375 }
376
377 if (Index == Loop) {
378 //
379 // If time out occurs.
380 //
381 Urb->Result |= EFI_USB_ERR_TIMEOUT;
382 }
383
384 //
385 // If URB transfer is error, restore transfer ring to original value before URB transfer
386 // This will make the current transfer TRB is always at the latest unused one in transfer ring.
387 //
388 Ring = (TRANSFER_RING *)(UINTN)Urb->Ring;
389 if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {
390 //
391 // Adjust Enqueue pointer
392 //
393 Ring->RingEnqueue = Urb->Trb;
394 //
395 // Clear CCS flag for next use
396 //
397 Trb = (TRB_TEMPLATE *)(UINTN)Urb->Trb;
398 Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
399 } else {
400 //
401 // Update transfer ring for next transfer.
402 //
403 XhcSyncTrsRing (Handle, Ring);
404 }
405}
406
419 IN URB *Urb
420 )
421{
422 TRANSFER_RING *EPRing;
423 TRB *Trb;
424
425 if (Urb->Direction == EfiUsbDataIn) {
426 EPRing = &Handle->TransferRingIn;
427 } else {
428 EPRing = &Handle->TransferRingOut;
429 }
430
431 Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN)EPRing;
432 XhcSyncTrsRing (Handle, EPRing);
433
434 Urb->Trb = EPRing->RingEnqueue;
435 Trb = (TRB *)(UINTN)EPRing->RingEnqueue;
436 Trb->TrbNormal.TRBPtrLo = XHC_LOW_32BIT (Urb->Data);
437 Trb->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT (Urb->Data);
438 Trb->TrbNormal.Length = Urb->DataLen;
439 Trb->TrbNormal.TDSize = 0;
440 Trb->TrbNormal.IntTarget = 0;
441 Trb->TrbNormal.ISP = 1;
442 Trb->TrbNormal.IOC = 1;
443 Trb->TrbNormal.Type = TRB_TYPE_NORMAL;
444
445 //
446 // Update the cycle bit to indicate this TRB has been consumed.
447 //
448 Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
449
450 return EFI_SUCCESS;
451}
452
464URB *
467 IN EFI_USB_DATA_DIRECTION Direction,
468 IN VOID *Data,
469 IN UINTN DataLen
470 )
471{
472 EFI_STATUS Status;
473 URB *Urb;
474 EFI_PHYSICAL_ADDRESS UrbData;
475
476 if (Direction == EfiUsbDataIn) {
477 Urb = &Handle->UrbIn;
478 } else {
479 Urb = &Handle->UrbOut;
480 }
481
482 UrbData = Urb->Data;
483
484 ZeroMem (Urb, sizeof (URB));
485 Urb->Direction = Direction;
486
487 //
488 // Allocate memory to move data from CAR or SMRAM to normal memory
489 // to make XHCI DMA successfully
490 // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
491 //
492 Urb->Data = UrbData;
493
494 if (Direction == EfiUsbDataIn) {
495 //
496 // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
497 //
498 Urb->DataLen = (UINT32)DataLen;
499 } else {
500 //
501 // Put data into URB data out buffer which will create TRBs
502 //
503 ZeroMem ((VOID *)(UINTN)Urb->Data, DataLen);
504 CopyMem ((VOID *)(UINTN)Urb->Data, Data, DataLen);
505 Urb->DataLen = (UINT32)DataLen;
506 }
507
508 Status = XhcCreateTransferTrb (Handle, Urb);
509 ASSERT_EFI_ERROR (Status);
510
511 return Urb;
512}
513
533EFIAPI
536 IN EFI_USB_DATA_DIRECTION Direction,
537 IN OUT VOID *Data,
538 IN OUT UINTN *DataLength,
539 IN UINTN Timeout
540 )
541{
542 URB *Urb;
543 EFI_STATUS Status;
544
545 //
546 // Validate the parameters
547 //
548 if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {
549 return EFI_INVALID_PARAMETER;
550 }
551
552 //
553 // Create a new URB, insert it into the asynchronous
554 // schedule list, then poll the execution status.
555 //
556 Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);
557 ASSERT (Urb != NULL);
558
559 XhcExecTransfer (Handle, Urb, Timeout);
560
561 //
562 // Make sure the data received from HW can fit in the received buffer.
563 //
564 if (Urb->Completed > *DataLength) {
565 return EFI_DEVICE_ERROR;
566 }
567
568 *DataLength = Urb->Completed;
569
570 Status = EFI_TIMEOUT;
571 if (Urb->Result == EFI_USB_NOERROR) {
572 Status = EFI_SUCCESS;
573 }
574
575 if (Direction == EfiUsbDataIn) {
576 //
577 // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
578 // SMRAM does not allow to do DMA, so we create an internal buffer.
579 //
580 CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
581 }
582
583 return Status;
584}
UINT64 UINTN
UINTN EFIAPI MicroSecondDelay(IN UINTN MicroSeconds)
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT32 XhcReadDebugReg(IN USB3_DEBUG_PORT_HANDLE *Handle, IN UINT32 Offset)
VOID XhcWriteDebugReg(IN USB3_DEBUG_PORT_HANDLE *Handle, IN UINT32 Offset, IN UINT32 Data)
URB * XhcCreateUrb(IN USB3_DEBUG_PORT_HANDLE *Handle, IN EFI_USB_DATA_DIRECTION Direction, IN VOID *Data, IN UINTN DataLen)
EFI_STATUS EFIAPI XhcDataTransfer(IN USB3_DEBUG_PORT_HANDLE *Handle, IN EFI_USB_DATA_DIRECTION Direction, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN Timeout)
EFI_STATUS XhcCreateTransferTrb(IN USB3_DEBUG_PORT_HANDLE *Handle, IN URB *Urb)
EFI_STATUS EFIAPI XhcRingDoorBell(IN USB3_DEBUG_PORT_HANDLE *Handle, IN URB *Urb)
BOOLEAN IsTrbInTrsRing(IN TRANSFER_RING *Ring, IN TRB_TEMPLATE *Trb)
VOID XhcCheckUrbResult(IN USB3_DEBUG_PORT_HANDLE *Handle, IN URB *Urb)
VOID XhcExecTransfer(IN USB3_DEBUG_PORT_HANDLE *Handle, IN URB *Urb, IN UINTN Timeout)
EFI_STATUS EFIAPI XhcCheckNewEvent(IN USB3_DEBUG_PORT_HANDLE *Handle, IN EVENT_RING *EvtRing, OUT TRB_TEMPLATE **NewEvtTrb)
EFI_STATUS EFIAPI XhcSyncTrsRing(IN USB3_DEBUG_PORT_HANDLE *Handle, IN TRANSFER_RING *TrsRing)
EFI_STATUS EFIAPI XhcSyncEventRing(IN USB3_DEBUG_PORT_HANDLE *Handle, IN EVENT_RING *EvtRing)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
EFI_USB_DATA_DIRECTION
Definition: UsbIo.h:44
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:200