2 Debug Port Library implementation based on usb3 debug port.
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #include "DebugCommunicationLibUsb3Internal.h"
17 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
19 @param Handle Debug port handle.
20 @param TrsRing The transfer ring to sync.
22 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
28 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
29 IN TRANSFER_RING
*TrsRing
36 ASSERT (TrsRing
!= NULL
);
39 // Calculate the latest RingEnqueue and RingPCS
41 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
) TrsRing
->RingEnqueue
;
43 ASSERT (TrsTrb
!= NULL
);
45 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
46 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
50 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
51 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
53 // set cycle bit in Link TRB as normal
55 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
57 // Toggle PCS maintained by software
59 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
60 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
)((TrsTrb
->Parameter1
| LShiftU64 ((UINT64
)TrsTrb
->Parameter2
, 32)) & ~0x0F);
63 ASSERT (Index
!= TrsRing
->TrbNumber
);
65 if ((EFI_PHYSICAL_ADDRESS
)(UINTN
) TrsTrb
!= TrsRing
->RingEnqueue
) {
66 TrsRing
->RingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) TrsTrb
;
70 // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
72 CycleBit
= TrsTrb
->CycleBit
;
73 ZeroMem (TrsTrb
, sizeof (TRB_TEMPLATE
));
74 TrsTrb
->CycleBit
= CycleBit
;
80 Synchronize the specified event ring to update the enqueue and dequeue pointer.
82 @param Handle Debug port handle.
83 @param EvtRing The event ring to sync.
85 @retval EFI_SUCCESS The event ring is synchronized successfully.
91 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
92 IN EVENT_RING
*EvtRing
96 TRB_TEMPLATE
*EvtTrb1
;
98 ASSERT (EvtRing
!= NULL
);
101 // Calculate the EventRingEnqueue and EventRingCCS.
102 // Note: only support single Segment
104 EvtTrb1
= (TRB_TEMPLATE
*)(UINTN
) EvtRing
->EventRingDequeue
;
106 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
107 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
113 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
114 EvtTrb1
= (TRB_TEMPLATE
*)(UINTN
) EvtRing
->EventRingSeg0
;
115 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
119 if (Index
< EvtRing
->TrbNumber
) {
120 EvtRing
->EventRingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)EvtTrb1
;
129 Check if there is a new generated event.
131 @param Handle Debug port handle.
132 @param EvtRing The event ring to check.
133 @param NewEvtTrb The new event TRB found.
135 @retval EFI_SUCCESS Found a new event TRB at the event ring.
136 @retval EFI_NOT_READY The event ring has no new event.
142 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
143 IN EVENT_RING
*EvtRing
,
144 OUT TRB_TEMPLATE
**NewEvtTrb
149 ASSERT (EvtRing
!= NULL
);
151 *NewEvtTrb
= (TRB_TEMPLATE
*)(UINTN
) EvtRing
->EventRingDequeue
;
153 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
154 return EFI_NOT_READY
;
157 Status
= EFI_SUCCESS
;
159 EvtRing
->EventRingDequeue
+= sizeof (TRB_TEMPLATE
);
161 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
163 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
164 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
171 Check if the Trb is a transaction of the URB.
173 @param Ring The transfer ring to be checked.
174 @param Trb The TRB to be checked.
176 @retval TRUE It is a transaction of the URB.
177 @retval FALSE It is not any transaction of the URB.
182 IN TRANSFER_RING
*Ring
,
186 TRB_TEMPLATE
*CheckedTrb
;
189 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) Ring
->RingSeg0
;
191 ASSERT (Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
193 for (Index
= 0; Index
< Ring
->TrbNumber
; Index
++) {
194 if (Trb
== CheckedTrb
) {
204 Check the URB's execution result and update the URB's
207 @param Handle Debug port handle.
208 @param Urb The URB to check result.
213 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
217 EVT_TRB_TRANSFER
*EvtTrb
;
218 TRB_TEMPLATE
*TRBPtr
;
226 ASSERT ((Handle
!= NULL
) && (Urb
!= NULL
));
235 // Traverse the event ring to find out all new events from the previous check.
237 XhcSyncEventRing (Handle
, &Handle
->EventRing
);
239 for (Index
= 0; Index
< Handle
->EventRing
.TrbNumber
; Index
++) {
241 Status
= XhcCheckNewEvent (Handle
, &Handle
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
242 if (Status
== EFI_NOT_READY
) {
244 // All new events are handled, return directly.
249 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
253 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
255 if (IsTrbInTrsRing ((TRANSFER_RING
*)(UINTN
)(Urb
->Ring
), TRBPtr
)) {
257 } else if (IsTrbInTrsRing ((TRANSFER_RING
*)(UINTN
)(Handle
->UrbIn
.Ring
), TRBPtr
)) {
259 // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
260 // Internal buffer is used by next read.
262 Handle
->DataCount
= (UINT8
) (Handle
->UrbIn
.DataLen
- EvtTrb
->Length
);
263 CopyMem ((VOID
*)(UINTN
)Handle
->Data
, (VOID
*)(UINTN
)Handle
->UrbIn
.Data
, Handle
->DataCount
);
265 // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
267 TRBPtr
->CycleBit
= (TRBPtr
->CycleBit
& BIT0
) ? 0 : 1;
273 if ((EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) ||
274 (EvtTrb
->Completecode
== TRB_COMPLETION_SUCCESS
)) {
276 // The length of data which were transferred.
278 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
280 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
283 // This Urb has been processed
285 CheckedUrb
->Finished
= TRUE
;
290 // Advance event ring to last available entry
292 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
293 // So divide it to two 32-bytes width register access.
295 Low
= XhcReadDebugReg (Handle
, XHC_DC_DCERDP
);
296 High
= XhcReadDebugReg (Handle
, XHC_DC_DCERDP
+ 4);
297 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
299 if ((XhcDequeue
& (~0x0F)) != ((UINT64
)(UINTN
)Handle
->EventRing
.EventRingDequeue
& (~0x0F))) {
301 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
302 // So divide it to two 32-bytes width register access.
304 XhcWriteDebugReg (Handle
, XHC_DC_DCERDP
, XHC_LOW_32BIT (Handle
->EventRing
.EventRingDequeue
));
305 XhcWriteDebugReg (Handle
, XHC_DC_DCERDP
+ 4, XHC_HIGH_32BIT (Handle
->EventRing
.EventRingDequeue
));
310 Ring the door bell to notify XHCI there is a transaction to be executed.
312 @param Handle Debug port handle.
313 @param Urb The pointer to URB.
315 @retval EFI_SUCCESS Successfully ring the door bell.
321 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
328 // 7.6.8.2 DCDB Register
330 Dcdb
= (Urb
->Direction
== EfiUsbDataIn
) ? 0x100 : 0x0;
342 Execute the transfer by polling the URB. This is a synchronous operation.
344 @param Handle Debug port handle.
345 @param Urb The URB to execute.
346 @param Timeout The time to wait before abort, in microsecond.
351 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
361 Loop
= Timeout
/ XHC_DEBUG_PORT_1_MILLISECOND
;
365 XhcRingDoorBell (Handle
, Urb
);
367 // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
369 for (Index
= 0; Index
< Loop
; Index
++) {
370 XhcCheckUrbResult (Handle
, Urb
);
374 MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND
);
378 // If time out occurs.
380 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
383 // If URB transfer is error, restore transfer ring to original value before URB transfer
384 // This will make the current transfer TRB is always at the latest unused one in transfer ring.
386 Ring
= (TRANSFER_RING
*)(UINTN
) Urb
->Ring
;
387 if ((Urb
->Result
!= EFI_USB_NOERROR
) && (Urb
->Direction
== EfiUsbDataIn
)) {
389 // Adjust Enqueue pointer
391 Ring
->RingEnqueue
= Urb
->Trb
;
393 // Clear CCS flag for next use
395 Trb
= (TRB_TEMPLATE
*)(UINTN
) Urb
->Trb
;
396 Trb
->CycleBit
= ((~Ring
->RingPCS
) & BIT0
);
399 // Update transfer ring for next transfer.
401 XhcSyncTrsRing (Handle
, Ring
);
406 Create a transfer TRB.
408 @param Handle Debug port handle.
409 @param Urb The urb used to construct the transfer TRB.
411 @return Created TRB or NULL
415 XhcCreateTransferTrb (
416 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
420 TRANSFER_RING
*EPRing
;
423 if (Urb
->Direction
== EfiUsbDataIn
) {
424 EPRing
= &Handle
->TransferRingIn
;
426 EPRing
= &Handle
->TransferRingOut
;
429 Urb
->Ring
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) EPRing
;
430 XhcSyncTrsRing (Handle
, EPRing
);
432 Urb
->Trb
= EPRing
->RingEnqueue
;
433 Trb
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
434 Trb
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->Data
);
435 Trb
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->Data
);
436 Trb
->TrbNormal
.Length
= Urb
->DataLen
;
437 Trb
->TrbNormal
.TDSize
= 0;
438 Trb
->TrbNormal
.IntTarget
= 0;
439 Trb
->TrbNormal
.ISP
= 1;
440 Trb
->TrbNormal
.IOC
= 1;
441 Trb
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
444 // Update the cycle bit to indicate this TRB has been consumed.
446 Trb
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
452 Create a new URB for a new transaction.
454 @param Handle Debug port handle.
455 @param Direction The direction of data flow.
456 @param Data The user data to transfer
457 @param DataLen The length of data buffer
459 @return Created URB or NULL
464 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
465 IN EFI_USB_DATA_DIRECTION Direction
,
472 EFI_PHYSICAL_ADDRESS UrbData
;
474 if (Direction
== EfiUsbDataIn
) {
475 Urb
= &Handle
->UrbIn
;
477 Urb
= &Handle
->UrbOut
;
482 ZeroMem (Urb
, sizeof (URB
));
483 Urb
->Direction
= Direction
;
486 // Allocate memory to move data from CAR or SMRAM to normal memory
487 // to make XHCI DMA successfully
488 // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
492 if (Direction
== EfiUsbDataIn
) {
494 // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
496 Urb
->DataLen
= (UINT32
) DataLen
;
499 // Put data into URB data out buffer which will create TRBs
501 ZeroMem ((VOID
*)(UINTN
) Urb
->Data
, DataLen
);
502 CopyMem ((VOID
*)(UINTN
) Urb
->Data
, Data
, DataLen
);
503 Urb
->DataLen
= (UINT32
) DataLen
;
506 Status
= XhcCreateTransferTrb (Handle
, Urb
);
507 ASSERT_EFI_ERROR (Status
);
513 Submits bulk transfer to a bulk endpoint of a USB device.
515 @param Handle Debug port handle.
516 @param Direction The direction of data transfer.
517 @param Data Array of pointers to the buffers of data to transmit
518 from or receive into.
519 @param DataLength The lenght of the data buffer.
520 @param Timeout Indicates the maximum time, in microsecond, which
521 the transfer is allowed to complete.
523 @retval EFI_SUCCESS The transfer was completed successfully.
524 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
525 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
526 @retval EFI_TIMEOUT The transfer failed due to timeout.
527 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
533 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
534 IN EFI_USB_DATA_DIRECTION Direction
,
536 IN OUT UINTN
*DataLength
,
544 // Validate the parameters
546 if ((DataLength
== NULL
) || (*DataLength
== 0) || (Data
== NULL
)) {
547 return EFI_INVALID_PARAMETER
;
551 // Create a new URB, insert it into the asynchronous
552 // schedule list, then poll the execution status.
554 Urb
= XhcCreateUrb (Handle
, Direction
, Data
, *DataLength
);
555 ASSERT (Urb
!= NULL
);
557 XhcExecTransfer (Handle
, Urb
, Timeout
);
560 // Make sure the data received from HW can fit in the received buffer.
562 if (Urb
->Completed
> *DataLength
) {
563 return EFI_DEVICE_ERROR
;
566 *DataLength
= Urb
->Completed
;
568 Status
= EFI_TIMEOUT
;
569 if (Urb
->Result
== EFI_USB_NOERROR
) {
570 Status
= EFI_SUCCESS
;
573 if (Direction
== EfiUsbDataIn
) {
575 // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
576 // SMRAM does not allow to do DMA, so we create an internal buffer.
578 CopyMem (Data
, (VOID
*)(UINTN
)Urb
->Data
, *DataLength
);