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 **/
25 EFI_STATUS
26 EFIAPI
XhcSyncTrsRing(IN USB3_DEBUG_PORT_HANDLE * Handle,IN TRANSFER_RING * TrsRing)27 XhcSyncTrsRing (
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 **/
88 EFI_STATUS
89 EFIAPI
XhcSyncEventRing(IN USB3_DEBUG_PORT_HANDLE * Handle,IN EVENT_RING * EvtRing)90 XhcSyncEventRing (
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 **/
139 EFI_STATUS
140 EFIAPI
XhcCheckNewEvent(IN USB3_DEBUG_PORT_HANDLE * Handle,IN EVENT_RING * EvtRing,OUT TRB_TEMPLATE ** NewEvtTrb)141 XhcCheckNewEvent (
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 **/
182 BOOLEAN
IsTrbInTrsRing(IN TRANSFER_RING * Ring,IN TRB_TEMPLATE * Trb)183 IsTrbInTrsRing (
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 **/
213 VOID
XhcCheckUrbResult(IN USB3_DEBUG_PORT_HANDLE * Handle,IN URB * Urb)214 XhcCheckUrbResult (
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 
290 EXIT:
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 **/
320 EFI_STATUS
321 EFIAPI
XhcRingDoorBell(IN USB3_DEBUG_PORT_HANDLE * Handle,IN URB * Urb)322 XhcRingDoorBell (
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 **/
351 VOID
XhcExecTransfer(IN USB3_DEBUG_PORT_HANDLE * Handle,IN URB * Urb,IN UINTN Timeout)352 XhcExecTransfer (
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 **/
416 EFI_STATUS
XhcCreateTransferTrb(IN USB3_DEBUG_PORT_HANDLE * Handle,IN URB * Urb)417 XhcCreateTransferTrb (
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 **/
464 URB*
XhcCreateUrb(IN USB3_DEBUG_PORT_HANDLE * Handle,IN EFI_USB_DATA_DIRECTION Direction,IN VOID * Data,IN UINTN DataLen)465 XhcCreateUrb (
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 **/
532 EFI_STATUS
533 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)534 XhcDataTransfer (
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