2 Debug Port Library implementation based on usb3 debug port.
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "DebugCommunicationLibUsb3Internal.h"
11 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
13 @param Handle Debug port handle.
14 @param TrsRing The transfer ring to sync.
16 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
22 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
23 IN TRANSFER_RING
*TrsRing
30 ASSERT (TrsRing
!= NULL
);
33 // Calculate the latest RingEnqueue and RingPCS
35 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
) TrsRing
->RingEnqueue
;
37 ASSERT (TrsTrb
!= NULL
);
39 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
40 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
44 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
45 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
47 // set cycle bit in Link TRB as normal
49 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
51 // Toggle PCS maintained by software
53 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
54 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
)((TrsTrb
->Parameter1
| LShiftU64 ((UINT64
)TrsTrb
->Parameter2
, 32)) & ~0x0F);
57 ASSERT (Index
!= TrsRing
->TrbNumber
);
59 if ((EFI_PHYSICAL_ADDRESS
)(UINTN
) TrsTrb
!= TrsRing
->RingEnqueue
) {
60 TrsRing
->RingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) TrsTrb
;
64 // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
66 CycleBit
= TrsTrb
->CycleBit
;
67 ZeroMem (TrsTrb
, sizeof (TRB_TEMPLATE
));
68 TrsTrb
->CycleBit
= CycleBit
;
74 Synchronize the specified event ring to update the enqueue and dequeue pointer.
76 @param Handle Debug port handle.
77 @param EvtRing The event ring to sync.
79 @retval EFI_SUCCESS The event ring is synchronized successfully.
85 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
86 IN EVENT_RING
*EvtRing
90 TRB_TEMPLATE
*EvtTrb1
;
92 ASSERT (EvtRing
!= NULL
);
95 // Calculate the EventRingEnqueue and EventRingCCS.
96 // Note: only support single Segment
98 EvtTrb1
= (TRB_TEMPLATE
*)(UINTN
) EvtRing
->EventRingDequeue
;
100 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
101 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
107 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
108 EvtTrb1
= (TRB_TEMPLATE
*)(UINTN
) EvtRing
->EventRingSeg0
;
109 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
113 if (Index
< EvtRing
->TrbNumber
) {
114 EvtRing
->EventRingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)EvtTrb1
;
123 Check if there is a new generated event.
125 @param Handle Debug port handle.
126 @param EvtRing The event ring to check.
127 @param NewEvtTrb The new event TRB found.
129 @retval EFI_SUCCESS Found a new event TRB at the event ring.
130 @retval EFI_NOT_READY The event ring has no new event.
136 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
137 IN EVENT_RING
*EvtRing
,
138 OUT TRB_TEMPLATE
**NewEvtTrb
143 ASSERT (EvtRing
!= NULL
);
145 *NewEvtTrb
= (TRB_TEMPLATE
*)(UINTN
) EvtRing
->EventRingDequeue
;
147 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
148 return EFI_NOT_READY
;
151 Status
= EFI_SUCCESS
;
153 EvtRing
->EventRingDequeue
+= sizeof (TRB_TEMPLATE
);
155 // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
157 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
158 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
165 Check if the Trb is a transaction of the URB.
167 @param Ring The transfer ring to be checked.
168 @param Trb The TRB to be checked.
170 @retval TRUE It is a transaction of the URB.
171 @retval FALSE It is not any transaction of the URB.
176 IN TRANSFER_RING
*Ring
,
180 TRB_TEMPLATE
*CheckedTrb
;
183 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) Ring
->RingSeg0
;
185 ASSERT (Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
187 for (Index
= 0; Index
< Ring
->TrbNumber
; Index
++) {
188 if (Trb
== CheckedTrb
) {
198 Check the URB's execution result and update the URB's
201 @param Handle Debug port handle.
202 @param Urb The URB to check result.
207 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
211 EVT_TRB_TRANSFER
*EvtTrb
;
212 TRB_TEMPLATE
*TRBPtr
;
220 ASSERT ((Handle
!= NULL
) && (Urb
!= NULL
));
229 // Traverse the event ring to find out all new events from the previous check.
231 XhcSyncEventRing (Handle
, &Handle
->EventRing
);
233 for (Index
= 0; Index
< Handle
->EventRing
.TrbNumber
; Index
++) {
235 Status
= XhcCheckNewEvent (Handle
, &Handle
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
236 if (Status
== EFI_NOT_READY
) {
238 // All new events are handled, return directly.
243 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
247 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
249 if (IsTrbInTrsRing ((TRANSFER_RING
*)(UINTN
)(Urb
->Ring
), TRBPtr
)) {
251 } else if (IsTrbInTrsRing ((TRANSFER_RING
*)(UINTN
)(Handle
->UrbIn
.Ring
), TRBPtr
)) {
253 // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
254 // Internal buffer is used by next read.
256 Handle
->DataCount
= (UINT8
) (Handle
->UrbIn
.DataLen
- EvtTrb
->Length
);
257 CopyMem ((VOID
*)(UINTN
)Handle
->Data
, (VOID
*)(UINTN
)Handle
->UrbIn
.Data
, Handle
->DataCount
);
259 // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
261 TRBPtr
->CycleBit
= (TRBPtr
->CycleBit
& BIT0
) ? 0 : 1;
267 if ((EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) ||
268 (EvtTrb
->Completecode
== TRB_COMPLETION_SUCCESS
)) {
270 // The length of data which were transferred.
272 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
274 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
277 // This Urb has been processed
279 CheckedUrb
->Finished
= TRUE
;
284 // Advance event ring to last available entry
286 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
287 // So divide it to two 32-bytes width register access.
289 Low
= XhcReadDebugReg (Handle
, XHC_DC_DCERDP
);
290 High
= XhcReadDebugReg (Handle
, XHC_DC_DCERDP
+ 4);
291 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
293 if ((XhcDequeue
& (~0x0F)) != ((UINT64
)(UINTN
)Handle
->EventRing
.EventRingDequeue
& (~0x0F))) {
295 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
296 // So divide it to two 32-bytes width register access.
298 XhcWriteDebugReg (Handle
, XHC_DC_DCERDP
, XHC_LOW_32BIT (Handle
->EventRing
.EventRingDequeue
));
299 XhcWriteDebugReg (Handle
, XHC_DC_DCERDP
+ 4, XHC_HIGH_32BIT (Handle
->EventRing
.EventRingDequeue
));
304 Ring the door bell to notify XHCI there is a transaction to be executed.
306 @param Handle Debug port handle.
307 @param Urb The pointer to URB.
309 @retval EFI_SUCCESS Successfully ring the door bell.
315 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
322 // 7.6.8.2 DCDB Register
324 Dcdb
= (Urb
->Direction
== EfiUsbDataIn
) ? 0x100 : 0x0;
336 Execute the transfer by polling the URB. This is a synchronous operation.
338 @param Handle Debug port handle.
339 @param Urb The URB to execute.
340 @param Timeout The time to wait before abort, in microsecond.
345 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
355 Loop
= Timeout
/ XHC_DEBUG_PORT_1_MILLISECOND
;
359 XhcRingDoorBell (Handle
, Urb
);
361 // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
363 for (Index
= 0; Index
< Loop
; Index
++) {
364 XhcCheckUrbResult (Handle
, Urb
);
368 MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND
);
372 // If time out occurs.
374 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
377 // If URB transfer is error, restore transfer ring to original value before URB transfer
378 // This will make the current transfer TRB is always at the latest unused one in transfer ring.
380 Ring
= (TRANSFER_RING
*)(UINTN
) Urb
->Ring
;
381 if ((Urb
->Result
!= EFI_USB_NOERROR
) && (Urb
->Direction
== EfiUsbDataIn
)) {
383 // Adjust Enqueue pointer
385 Ring
->RingEnqueue
= Urb
->Trb
;
387 // Clear CCS flag for next use
389 Trb
= (TRB_TEMPLATE
*)(UINTN
) Urb
->Trb
;
390 Trb
->CycleBit
= ((~Ring
->RingPCS
) & BIT0
);
393 // Update transfer ring for next transfer.
395 XhcSyncTrsRing (Handle
, Ring
);
400 Create a transfer TRB.
402 @param Handle Debug port handle.
403 @param Urb The urb used to construct the transfer TRB.
405 @return Created TRB or NULL
409 XhcCreateTransferTrb (
410 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
414 TRANSFER_RING
*EPRing
;
417 if (Urb
->Direction
== EfiUsbDataIn
) {
418 EPRing
= &Handle
->TransferRingIn
;
420 EPRing
= &Handle
->TransferRingOut
;
423 Urb
->Ring
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) EPRing
;
424 XhcSyncTrsRing (Handle
, EPRing
);
426 Urb
->Trb
= EPRing
->RingEnqueue
;
427 Trb
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
428 Trb
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->Data
);
429 Trb
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->Data
);
430 Trb
->TrbNormal
.Length
= Urb
->DataLen
;
431 Trb
->TrbNormal
.TDSize
= 0;
432 Trb
->TrbNormal
.IntTarget
= 0;
433 Trb
->TrbNormal
.ISP
= 1;
434 Trb
->TrbNormal
.IOC
= 1;
435 Trb
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
438 // Update the cycle bit to indicate this TRB has been consumed.
440 Trb
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
446 Create a new URB for a new transaction.
448 @param Handle Debug port handle.
449 @param Direction The direction of data flow.
450 @param Data The user data to transfer
451 @param DataLen The length of data buffer
453 @return Created URB or NULL
458 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
459 IN EFI_USB_DATA_DIRECTION Direction
,
466 EFI_PHYSICAL_ADDRESS UrbData
;
468 if (Direction
== EfiUsbDataIn
) {
469 Urb
= &Handle
->UrbIn
;
471 Urb
= &Handle
->UrbOut
;
476 ZeroMem (Urb
, sizeof (URB
));
477 Urb
->Direction
= Direction
;
480 // Allocate memory to move data from CAR or SMRAM to normal memory
481 // to make XHCI DMA successfully
482 // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
486 if (Direction
== EfiUsbDataIn
) {
488 // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
490 Urb
->DataLen
= (UINT32
) DataLen
;
493 // Put data into URB data out buffer which will create TRBs
495 ZeroMem ((VOID
*)(UINTN
) Urb
->Data
, DataLen
);
496 CopyMem ((VOID
*)(UINTN
) Urb
->Data
, Data
, DataLen
);
497 Urb
->DataLen
= (UINT32
) DataLen
;
500 Status
= XhcCreateTransferTrb (Handle
, Urb
);
501 ASSERT_EFI_ERROR (Status
);
507 Submits bulk transfer to a bulk endpoint of a USB device.
509 @param Handle Debug port handle.
510 @param Direction The direction of data transfer.
511 @param Data Array of pointers to the buffers of data to transmit
512 from or receive into.
513 @param DataLength The length of the data buffer.
514 @param Timeout Indicates the maximum time, in microsecond, which
515 the transfer is allowed to complete.
517 @retval EFI_SUCCESS The transfer was completed successfully.
518 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
519 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
520 @retval EFI_TIMEOUT The transfer failed due to timeout.
521 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
527 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
528 IN EFI_USB_DATA_DIRECTION Direction
,
530 IN OUT UINTN
*DataLength
,
538 // Validate the parameters
540 if ((DataLength
== NULL
) || (*DataLength
== 0) || (Data
== NULL
)) {
541 return EFI_INVALID_PARAMETER
;
545 // Create a new URB, insert it into the asynchronous
546 // schedule list, then poll the execution status.
548 Urb
= XhcCreateUrb (Handle
, Direction
, Data
, *DataLength
);
549 ASSERT (Urb
!= NULL
);
551 XhcExecTransfer (Handle
, Urb
, Timeout
);
554 // Make sure the data received from HW can fit in the received buffer.
556 if (Urb
->Completed
> *DataLength
) {
557 return EFI_DEVICE_ERROR
;
560 *DataLength
= Urb
->Completed
;
562 Status
= EFI_TIMEOUT
;
563 if (Urb
->Result
== EFI_USB_NOERROR
) {
564 Status
= EFI_SUCCESS
;
567 if (Direction
== EfiUsbDataIn
) {
569 // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
570 // SMRAM does not allow to do DMA, so we create an internal buffer.
572 CopyMem (Data
, (VOID
*)(UINTN
)Urb
->Data
, *DataLength
);