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
)) {
45 if ((UINT8
)TrsTrb
->Type
== TRB_TYPE_LINK
) {
46 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
48 // set cycle bit in Link TRB as normal
50 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
52 // Toggle PCS maintained by software
54 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
55 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
)((TrsTrb
->Parameter1
| LShiftU64 ((UINT64
)TrsTrb
->Parameter2
, 32)) & ~0x0F);
59 ASSERT (Index
!= TrsRing
->TrbNumber
);
61 if ((EFI_PHYSICAL_ADDRESS
)(UINTN
)TrsTrb
!= TrsRing
->RingEnqueue
) {
62 TrsRing
->RingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)TrsTrb
;
66 // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
68 CycleBit
= TrsTrb
->CycleBit
;
69 ZeroMem (TrsTrb
, sizeof (TRB_TEMPLATE
));
70 TrsTrb
->CycleBit
= CycleBit
;
76 Synchronize the specified event ring to update the enqueue and dequeue pointer.
78 @param Handle Debug port handle.
79 @param EvtRing The event ring to sync.
81 @retval EFI_SUCCESS The event ring is synchronized successfully.
87 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
88 IN EVENT_RING
*EvtRing
92 TRB_TEMPLATE
*EvtTrb1
;
94 ASSERT (EvtRing
!= NULL
);
97 // Calculate the EventRingEnqueue and EventRingCCS.
98 // Note: only support single Segment
100 EvtTrb1
= (TRB_TEMPLATE
*)(UINTN
)EvtRing
->EventRingDequeue
;
102 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
103 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
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;
115 if (Index
< EvtRing
->TrbNumber
) {
116 EvtRing
->EventRingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)EvtTrb1
;
125 Check if there is a new generated event.
127 @param Handle Debug port handle.
128 @param EvtRing The event ring to check.
129 @param NewEvtTrb The new event TRB found.
131 @retval EFI_SUCCESS Found a new event TRB at the event ring.
132 @retval EFI_NOT_READY The event ring has no new event.
138 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
139 IN EVENT_RING
*EvtRing
,
140 OUT TRB_TEMPLATE
**NewEvtTrb
145 ASSERT (EvtRing
!= NULL
);
147 *NewEvtTrb
= (TRB_TEMPLATE
*)(UINTN
)EvtRing
->EventRingDequeue
;
149 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
150 return EFI_NOT_READY
;
153 Status
= EFI_SUCCESS
;
155 EvtRing
->EventRingDequeue
+= sizeof (TRB_TEMPLATE
);
157 // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
159 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
)EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
160 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
167 Check if the Trb is a transaction of the URB.
169 @param Ring The transfer ring to be checked.
170 @param Trb The TRB to be checked.
172 @retval TRUE It is a transaction of the URB.
173 @retval FALSE It is not any transaction of the URB.
178 IN TRANSFER_RING
*Ring
,
182 TRB_TEMPLATE
*CheckedTrb
;
185 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
)Ring
->RingSeg0
;
187 ASSERT (Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
189 for (Index
= 0; Index
< Ring
->TrbNumber
; Index
++) {
190 if (Trb
== CheckedTrb
) {
201 Check the URB's execution result and update the URB's
204 @param Handle Debug port handle.
205 @param Urb The URB to check result.
210 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
214 EVT_TRB_TRANSFER
*EvtTrb
;
215 TRB_TEMPLATE
*TRBPtr
;
223 ASSERT ((Handle
!= NULL
) && (Urb
!= NULL
));
232 // Traverse the event ring to find out all new events from the previous check.
234 XhcSyncEventRing (Handle
, &Handle
->EventRing
);
236 for (Index
= 0; Index
< Handle
->EventRing
.TrbNumber
; Index
++) {
237 Status
= XhcCheckNewEvent (Handle
, &Handle
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
238 if (Status
== EFI_NOT_READY
) {
240 // All new events are handled, return directly.
245 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
249 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
)EvtTrb
->TRBPtrHi
, 32));
251 if (IsTrbInTrsRing ((TRANSFER_RING
*)(UINTN
)(Urb
->Ring
), TRBPtr
)) {
253 } else if (IsTrbInTrsRing ((TRANSFER_RING
*)(UINTN
)(Handle
->UrbIn
.Ring
), TRBPtr
)) {
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.
258 Handle
->DataCount
= (UINT8
)(Handle
->UrbIn
.DataLen
- EvtTrb
->Length
);
259 CopyMem ((VOID
*)(UINTN
)Handle
->Data
, (VOID
*)(UINTN
)Handle
->UrbIn
.Data
, Handle
->DataCount
);
261 // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
263 TRBPtr
->CycleBit
= (TRBPtr
->CycleBit
& BIT0
) ? 0 : 1;
269 if ((EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) ||
270 (EvtTrb
->Completecode
== TRB_COMPLETION_SUCCESS
))
273 // The length of data which were transferred.
275 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
277 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
281 // This Urb has been processed
283 CheckedUrb
->Finished
= TRUE
;
288 // Advance event ring to last available entry
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.
293 Low
= XhcReadDebugReg (Handle
, XHC_DC_DCERDP
);
294 High
= XhcReadDebugReg (Handle
, XHC_DC_DCERDP
+ 4);
295 XhcDequeue
= (UINT64
)(LShiftU64 ((UINT64
)High
, 32) | Low
);
297 if ((XhcDequeue
& (~0x0F)) != ((UINT64
)(UINTN
)Handle
->EventRing
.EventRingDequeue
& (~0x0F))) {
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.
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
));
308 Ring the door bell to notify XHCI there is a transaction to be executed.
310 @param Handle Debug port handle.
311 @param Urb The pointer to URB.
313 @retval EFI_SUCCESS Successfully ring the door bell.
319 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
326 // 7.6.8.2 DCDB Register
328 Dcdb
= (Urb
->Direction
== EfiUsbDataIn
) ? 0x100 : 0x0;
340 Execute the transfer by polling the URB. This is a synchronous operation.
342 @param Handle Debug port handle.
343 @param Urb The URB to execute.
344 @param Timeout The time to wait before abort, in microsecond.
349 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
359 Loop
= Timeout
/ XHC_DEBUG_PORT_1_MILLISECOND
;
364 XhcRingDoorBell (Handle
, Urb
);
366 // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
368 for (Index
= 0; Index
< Loop
; Index
++) {
369 XhcCheckUrbResult (Handle
, Urb
);
374 MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND
);
379 // If time out occurs.
381 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
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.
388 Ring
= (TRANSFER_RING
*)(UINTN
)Urb
->Ring
;
389 if ((Urb
->Result
!= EFI_USB_NOERROR
) && (Urb
->Direction
== EfiUsbDataIn
)) {
391 // Adjust Enqueue pointer
393 Ring
->RingEnqueue
= Urb
->Trb
;
395 // Clear CCS flag for next use
397 Trb
= (TRB_TEMPLATE
*)(UINTN
)Urb
->Trb
;
398 Trb
->CycleBit
= ((~Ring
->RingPCS
) & BIT0
);
401 // Update transfer ring for next transfer.
403 XhcSyncTrsRing (Handle
, Ring
);
408 Create a transfer TRB.
410 @param Handle Debug port handle.
411 @param Urb The urb used to construct the transfer TRB.
413 @return Created TRB or NULL
417 XhcCreateTransferTrb (
418 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
422 TRANSFER_RING
*EPRing
;
425 if (Urb
->Direction
== EfiUsbDataIn
) {
426 EPRing
= &Handle
->TransferRingIn
;
428 EPRing
= &Handle
->TransferRingOut
;
431 Urb
->Ring
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)EPRing
;
432 XhcSyncTrsRing (Handle
, EPRing
);
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
;
446 // Update the cycle bit to indicate this TRB has been consumed.
448 Trb
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
454 Create a new URB for a new transaction.
456 @param Handle Debug port handle.
457 @param Direction The direction of data flow.
458 @param Data The user data to transfer
459 @param DataLen The length of data buffer
461 @return Created URB or NULL
466 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
467 IN EFI_USB_DATA_DIRECTION Direction
,
474 EFI_PHYSICAL_ADDRESS UrbData
;
476 if (Direction
== EfiUsbDataIn
) {
477 Urb
= &Handle
->UrbIn
;
479 Urb
= &Handle
->UrbOut
;
484 ZeroMem (Urb
, sizeof (URB
));
485 Urb
->Direction
= Direction
;
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
494 if (Direction
== EfiUsbDataIn
) {
496 // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
498 Urb
->DataLen
= (UINT32
)DataLen
;
501 // Put data into URB data out buffer which will create TRBs
503 ZeroMem ((VOID
*)(UINTN
)Urb
->Data
, DataLen
);
504 CopyMem ((VOID
*)(UINTN
)Urb
->Data
, Data
, DataLen
);
505 Urb
->DataLen
= (UINT32
)DataLen
;
508 Status
= XhcCreateTransferTrb (Handle
, Urb
);
509 ASSERT_EFI_ERROR (Status
);
515 Submits bulk transfer to a bulk endpoint of a USB device.
517 @param Handle Debug port handle.
518 @param Direction The direction of data transfer.
519 @param Data Array of pointers to the buffers of data to transmit
520 from or receive into.
521 @param DataLength The length of the data buffer.
522 @param Timeout Indicates the maximum time, in microsecond, which
523 the transfer is allowed to complete.
525 @retval EFI_SUCCESS The transfer was completed successfully.
526 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
527 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
528 @retval EFI_TIMEOUT The transfer failed due to timeout.
529 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
535 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
536 IN EFI_USB_DATA_DIRECTION Direction
,
538 IN OUT UINTN
*DataLength
,
546 // Validate the parameters
548 if ((DataLength
== NULL
) || (*DataLength
== 0) || (Data
== NULL
)) {
549 return EFI_INVALID_PARAMETER
;
553 // Create a new URB, insert it into the asynchronous
554 // schedule list, then poll the execution status.
556 Urb
= XhcCreateUrb (Handle
, Direction
, Data
, *DataLength
);
557 ASSERT (Urb
!= NULL
);
559 XhcExecTransfer (Handle
, Urb
, Timeout
);
562 // Make sure the data received from HW can fit in the received buffer.
564 if (Urb
->Completed
> *DataLength
) {
565 return EFI_DEVICE_ERROR
;
568 *DataLength
= Urb
->Completed
;
570 Status
= EFI_TIMEOUT
;
571 if (Urb
->Result
== EFI_USB_NOERROR
) {
572 Status
= EFI_SUCCESS
;
575 if (Direction
== EfiUsbDataIn
) {
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.
580 CopyMem (Data
, (VOID
*)(UINTN
)Urb
->Data
, *DataLength
);