1/** @file
2  Debug Port Library implementation based on usb3 debug port.
3
4  Copyright (c) 2014 - 2015, 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.
9
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.
12
13**/
14#include "DebugCommunicationLibUsb3Internal.h"
15
16/**
17  Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
18
19  @param  Handle      Debug port handle.
20  @param  TrsRing     The transfer ring to sync.
21
22  @retval EFI_SUCCESS The transfer ring is synchronized successfully.
23
24**/
25EFI_STATUS
26EFIAPI
27XhcSyncTrsRing (
28  IN USB3_DEBUG_PORT_HANDLE    *Handle,
29  IN TRANSFER_RING             *TrsRing
30  )
31{
32  UINTN               Index;
33  TRB_TEMPLATE        *TrsTrb;
34  UINT32              CycleBit;
35
36  ASSERT (TrsRing != NULL);
37
38  //
39  // Calculate the latest RingEnqueue and RingPCS
40  //
41  TrsTrb = (TRB_TEMPLATE *)(UINTN) TrsRing->RingEnqueue;
42
43  ASSERT (TrsTrb != NULL);
44
45  for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
46    if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
47      break;
48    }
49    TrsTrb++;
50    if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
51      ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
52      //
53      // set cycle bit in Link TRB as normal
54      //
55      ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
56      //
57      // Toggle PCS maintained by software
58      //
59      TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
60      TrsTrb           = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
61    }
62  }
63  ASSERT (Index != TrsRing->TrbNumber);
64
65  if ((EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb != TrsRing->RingEnqueue) {
66    TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb;
67  }
68
69  //
70  // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
71  //
72  CycleBit = TrsTrb->CycleBit;
73  ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
74  TrsTrb->CycleBit = CycleBit;
75
76  return EFI_SUCCESS;
77}
78
79/**
80  Synchronize the specified event ring to update the enqueue and dequeue pointer.
81
82  @param  Handle      Debug port handle.
83  @param  EvtRing     The event ring to sync.
84
85  @retval EFI_SUCCESS The event ring is synchronized successfully.
86
87**/
88EFI_STATUS
89EFIAPI
90XhcSyncEventRing (
91  IN USB3_DEBUG_PORT_HANDLE  *Handle,
92  IN EVENT_RING                *EvtRing
93  )
94{
95  UINTN               Index;
96  TRB_TEMPLATE        *EvtTrb1;
97
98  ASSERT (EvtRing != NULL);
99
100  //
101  // Calculate the EventRingEnqueue and EventRingCCS.
102  // Note: only support single Segment
103  //
104  EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
105
106  for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
107    if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
108      break;
109    }
110
111    EvtTrb1++;
112
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;
116    }
117  }
118
119  if (Index < EvtRing->TrbNumber) {
120    EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
121  } else {
122    ASSERT (FALSE);
123  }
124
125  return EFI_SUCCESS;
126}
127
128/**
129  Check if there is a new generated event.
130
131  @param  Handle        Debug port handle.
132  @param  EvtRing       The event ring to check.
133  @param  NewEvtTrb     The new event TRB found.
134
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.
137
138**/
139EFI_STATUS
140EFIAPI
141XhcCheckNewEvent (
142  IN  USB3_DEBUG_PORT_HANDLE   *Handle,
143  IN  EVENT_RING               *EvtRing,
144  OUT TRB_TEMPLATE             **NewEvtTrb
145  )
146{
147  EFI_STATUS          Status;
148  TRB_TEMPLATE        *EvtTrb;
149
150  ASSERT (EvtRing != NULL);
151
152  EvtTrb     = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
153  *NewEvtTrb = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
154
155  if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
156    return EFI_NOT_READY;
157  }
158
159  Status = EFI_SUCCESS;
160
161  EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
162  //
163  // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
164  //
165  if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
166    EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
167  }
168
169  return Status;
170}
171
172/**
173  Check if the Trb is a transaction of the URB.
174
175  @param Ring   The transfer ring to be checked.
176  @param Trb    The TRB to be checked.
177
178  @retval TRUE  It is a transaction of the URB.
179  @retval FALSE It is not any transaction of the URB.
180
181**/
182BOOLEAN
183IsTrbInTrsRing (
184  IN  TRANSFER_RING       *Ring,
185  IN  TRB_TEMPLATE        *Trb
186  )
187{
188  TRB_TEMPLATE  *CheckedTrb;
189  UINTN         Index;
190
191  CheckedTrb = (TRB_TEMPLATE *)(UINTN) Ring->RingSeg0;
192
193  ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
194
195  for (Index = 0; Index < Ring->TrbNumber; Index++) {
196    if (Trb == CheckedTrb) {
197      return TRUE;
198    }
199    CheckedTrb++;
200  }
201
202  return FALSE;
203}
204
205/**
206  Check the URB's execution result and update the URB's
207  result accordingly.
208
209  @param  Handle          Debug port handle.
210  @param  Urb             The URB to check result.
211
212**/
213VOID
214XhcCheckUrbResult (
215  IN  USB3_DEBUG_PORT_HANDLE *Handle,
216  IN  URB                      *Urb
217  )
218{
219  EVT_TRB_TRANSFER        *EvtTrb;
220  TRB_TEMPLATE            *TRBPtr;
221  UINTN                   Index;
222  EFI_STATUS              Status;
223  URB                     *CheckedUrb;
224  UINT64                  XhcDequeue;
225  UINT32                  High;
226  UINT32                  Low;
227
228  ASSERT ((Handle != NULL) && (Urb != NULL));
229
230  if (Urb->Finished) {
231    goto EXIT;
232  }
233
234  EvtTrb = NULL;
235
236  //
237  // Traverse the event ring to find out all new events from the previous check.
238  //
239  XhcSyncEventRing (Handle, &Handle->EventRing);
240
241  for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
242
243    Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
244    if (Status == EFI_NOT_READY) {
245      //
246      // All new events are handled, return directly.
247      //
248      goto EXIT;
249    }
250
251    if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
252      continue;
253    }
254
255    TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
256
257    if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
258      CheckedUrb = Urb;
259    } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
260      //
261      // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
262      // Internal buffer is used by next read.
263      //
264      Handle->DataCount = (UINT8) (Handle->UrbIn.DataLen - EvtTrb->Length);
265      CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
266      //
267      // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
268      //
269      TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
270      continue;
271    } else {
272      continue;
273    }
274
275    if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
276        (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS)) {
277      //
278      // The length of data which were transferred.
279      //
280      CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
281    } else {
282      CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;
283    }
284    //
285    // This Urb has been processed
286    //
287    CheckedUrb->Finished = TRUE;
288  }
289
290EXIT:
291  //
292  // Advance event ring to last available entry
293  //
294  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
295  // So divide it to two 32-bytes width register access.
296  //
297  Low  = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
298  High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
299  XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
300
301  if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
302    //
303    // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
304    // So divide it to two 32-bytes width register access.
305    //
306    XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));
307    XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));
308  }
309}
310
311/**
312  Ring the door bell to notify XHCI there is a transaction to be executed.
313
314  @param  Handle        Debug port handle.
315  @param  Urb           The pointer to URB.
316
317  @retval EFI_SUCCESS   Successfully ring the door bell.
318
319**/
320EFI_STATUS
321EFIAPI
322XhcRingDoorBell (
323  IN USB3_DEBUG_PORT_HANDLE    *Handle,
324  IN URB                       *Urb
325  )
326{
327  UINT32      Dcdb;
328
329  //
330  // 7.6.8.2 DCDB Register
331  //
332  Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
333
334  XhcWriteDebugReg (
335    Handle,
336    XHC_DC_DCDB,
337    Dcdb
338    );
339
340  return EFI_SUCCESS;
341}
342
343/**
344  Execute the transfer by polling the URB. This is a synchronous operation.
345
346  @param  Handle            Debug port handle.
347  @param  Urb               The URB to execute.
348  @param  Timeout           The time to wait before abort, in microsecond.
349
350**/
351VOID
352XhcExecTransfer (
353  IN  USB3_DEBUG_PORT_HANDLE   *Handle,
354  IN  URB                      *Urb,
355  IN  UINTN                    Timeout
356  )
357{
358  TRANSFER_RING           *Ring;
359  TRB_TEMPLATE            *Trb;
360  UINTN                   Loop;
361  UINTN                   Index;
362
363  Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
364  if (Timeout == 0) {
365    Loop = 0xFFFFFFFF;
366  }
367  XhcRingDoorBell (Handle, Urb);
368  //
369  // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
370  //
371  for (Index = 0; Index < Loop; Index++) {
372    XhcCheckUrbResult (Handle, Urb);
373    if (Urb->Finished) {
374      break;
375    }
376    MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
377  }
378  if (Index == Loop) {
379    //
380    // If time out occurs.
381    //
382    Urb->Result |= EFI_USB_ERR_TIMEOUT;
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
407/**
408  Create a transfer TRB.
409
410  @param  Handle  Debug port handle.
411  @param  Urb     The urb used to construct the transfer TRB.
412
413  @return Created TRB or NULL
414
415**/
416EFI_STATUS
417XhcCreateTransferTrb (
418  IN USB3_DEBUG_PORT_HANDLE   *Handle,
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
453/**
454  Create a new URB for a new transaction.
455
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
460
461  @return Created URB or NULL
462
463**/
464URB*
465XhcCreateUrb (
466  IN USB3_DEBUG_PORT_HANDLE             *Handle,
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
514/**
515  Submits bulk transfer to a bulk endpoint of a USB device.
516
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 lenght of the data buffer.
522  @param  Timeout               Indicates the maximum time, in microsecond, which
523                                the transfer is allowed to complete.
524
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.
530
531**/
532EFI_STATUS
533EFIAPI
534XhcDataTransfer (
535  IN     USB3_DEBUG_PORT_HANDLE              *Handle,
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  *DataLength     = Urb->Completed;
562
563  Status = EFI_TIMEOUT;
564  if (Urb->Result == EFI_USB_NOERROR) {
565    Status = EFI_SUCCESS;
566  }
567
568  if (Direction == EfiUsbDataIn) {
569    //
570    // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
571    // SMRAM does not allow to do DMA, so we create an internal buffer.
572    //
573    CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
574  }
575
576  return Status;
577}
578
579