]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
262cfab3fbb40a8b3eaa430f7c14316fd664dc40
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb3 / DebugCommunicationLibUsb3Transfer.c
1 /** @file
2 Debug Port Library implementation based on usb3 debug port.
3
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8 #include "DebugCommunicationLibUsb3Internal.h"
9
10 /**
11 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
12
13 @param Handle Debug port handle.
14 @param TrsRing The transfer ring to sync.
15
16 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
17
18 **/
19 EFI_STATUS
20 EFIAPI
21 XhcSyncTrsRing (
22 IN USB3_DEBUG_PORT_HANDLE *Handle,
23 IN TRANSFER_RING *TrsRing
24 )
25 {
26 UINTN Index;
27 TRB_TEMPLATE *TrsTrb;
28 UINT32 CycleBit;
29
30 ASSERT (TrsRing != NULL);
31
32 //
33 // Calculate the latest RingEnqueue and RingPCS
34 //
35 TrsTrb = (TRB_TEMPLATE *)(UINTN) TrsRing->RingEnqueue;
36
37 ASSERT (TrsTrb != NULL);
38
39 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
40 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
41 break;
42 }
43 TrsTrb++;
44 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
45 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
46 //
47 // set cycle bit in Link TRB as normal
48 //
49 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
50 //
51 // Toggle PCS maintained by software
52 //
53 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
54 TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
55 }
56 }
57 ASSERT (Index != TrsRing->TrbNumber);
58
59 if ((EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb != TrsRing->RingEnqueue) {
60 TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb;
61 }
62
63 //
64 // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
65 //
66 CycleBit = TrsTrb->CycleBit;
67 ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
68 TrsTrb->CycleBit = CycleBit;
69
70 return EFI_SUCCESS;
71 }
72
73 /**
74 Synchronize the specified event ring to update the enqueue and dequeue pointer.
75
76 @param Handle Debug port handle.
77 @param EvtRing The event ring to sync.
78
79 @retval EFI_SUCCESS The event ring is synchronized successfully.
80
81 **/
82 EFI_STATUS
83 EFIAPI
84 XhcSyncEventRing (
85 IN USB3_DEBUG_PORT_HANDLE *Handle,
86 IN EVENT_RING *EvtRing
87 )
88 {
89 UINTN Index;
90 TRB_TEMPLATE *EvtTrb1;
91
92 ASSERT (EvtRing != NULL);
93
94 //
95 // Calculate the EventRingEnqueue and EventRingCCS.
96 // Note: only support single Segment
97 //
98 EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
99
100 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
101 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
102 break;
103 }
104
105 EvtTrb1++;
106
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;
110 }
111 }
112
113 if (Index < EvtRing->TrbNumber) {
114 EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
115 } else {
116 ASSERT (FALSE);
117 }
118
119 return EFI_SUCCESS;
120 }
121
122 /**
123 Check if there is a new generated event.
124
125 @param Handle Debug port handle.
126 @param EvtRing The event ring to check.
127 @param NewEvtTrb The new event TRB found.
128
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.
131
132 **/
133 EFI_STATUS
134 EFIAPI
135 XhcCheckNewEvent (
136 IN USB3_DEBUG_PORT_HANDLE *Handle,
137 IN EVENT_RING *EvtRing,
138 OUT TRB_TEMPLATE **NewEvtTrb
139 )
140 {
141 EFI_STATUS Status;
142
143 ASSERT (EvtRing != NULL);
144
145 *NewEvtTrb = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
146
147 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
148 return EFI_NOT_READY;
149 }
150
151 Status = EFI_SUCCESS;
152
153 EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
154 //
155 // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
156 //
157 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
158 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
159 }
160
161 return Status;
162 }
163
164 /**
165 Check if the Trb is a transaction of the URB.
166
167 @param Ring The transfer ring to be checked.
168 @param Trb The TRB to be checked.
169
170 @retval TRUE It is a transaction of the URB.
171 @retval FALSE It is not any transaction of the URB.
172
173 **/
174 BOOLEAN
175 IsTrbInTrsRing (
176 IN TRANSFER_RING *Ring,
177 IN TRB_TEMPLATE *Trb
178 )
179 {
180 TRB_TEMPLATE *CheckedTrb;
181 UINTN Index;
182
183 CheckedTrb = (TRB_TEMPLATE *)(UINTN) Ring->RingSeg0;
184
185 ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
186
187 for (Index = 0; Index < Ring->TrbNumber; Index++) {
188 if (Trb == CheckedTrb) {
189 return TRUE;
190 }
191 CheckedTrb++;
192 }
193
194 return FALSE;
195 }
196
197 /**
198 Check the URB's execution result and update the URB's
199 result accordingly.
200
201 @param Handle Debug port handle.
202 @param Urb The URB to check result.
203
204 **/
205 VOID
206 XhcCheckUrbResult (
207 IN USB3_DEBUG_PORT_HANDLE *Handle,
208 IN URB *Urb
209 )
210 {
211 EVT_TRB_TRANSFER *EvtTrb;
212 TRB_TEMPLATE *TRBPtr;
213 UINTN Index;
214 EFI_STATUS Status;
215 URB *CheckedUrb;
216 UINT64 XhcDequeue;
217 UINT32 High;
218 UINT32 Low;
219
220 ASSERT ((Handle != NULL) && (Urb != NULL));
221
222 if (Urb->Finished) {
223 goto EXIT;
224 }
225
226 EvtTrb = NULL;
227
228 //
229 // Traverse the event ring to find out all new events from the previous check.
230 //
231 XhcSyncEventRing (Handle, &Handle->EventRing);
232
233 for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
234
235 Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
236 if (Status == EFI_NOT_READY) {
237 //
238 // All new events are handled, return directly.
239 //
240 goto EXIT;
241 }
242
243 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
244 continue;
245 }
246
247 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
248
249 if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
250 CheckedUrb = Urb;
251 } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
252 //
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.
255 //
256 Handle->DataCount = (UINT8) (Handle->UrbIn.DataLen - EvtTrb->Length);
257 CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
258 //
259 // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
260 //
261 TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
262 continue;
263 } else {
264 continue;
265 }
266
267 if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
268 (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS)) {
269 //
270 // The length of data which were transferred.
271 //
272 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
273 } else {
274 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
275 }
276 //
277 // This Urb has been processed
278 //
279 CheckedUrb->Finished = TRUE;
280 }
281
282 EXIT:
283 //
284 // Advance event ring to last available entry
285 //
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.
288 //
289 Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
290 High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
291 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
292
293 if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
294 //
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.
297 //
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));
300 }
301 }
302
303 /**
304 Ring the door bell to notify XHCI there is a transaction to be executed.
305
306 @param Handle Debug port handle.
307 @param Urb The pointer to URB.
308
309 @retval EFI_SUCCESS Successfully ring the door bell.
310
311 **/
312 EFI_STATUS
313 EFIAPI
314 XhcRingDoorBell (
315 IN USB3_DEBUG_PORT_HANDLE *Handle,
316 IN URB *Urb
317 )
318 {
319 UINT32 Dcdb;
320
321 //
322 // 7.6.8.2 DCDB Register
323 //
324 Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
325
326 XhcWriteDebugReg (
327 Handle,
328 XHC_DC_DCDB,
329 Dcdb
330 );
331
332 return EFI_SUCCESS;
333 }
334
335 /**
336 Execute the transfer by polling the URB. This is a synchronous operation.
337
338 @param Handle Debug port handle.
339 @param Urb The URB to execute.
340 @param Timeout The time to wait before abort, in microsecond.
341
342 **/
343 VOID
344 XhcExecTransfer (
345 IN USB3_DEBUG_PORT_HANDLE *Handle,
346 IN URB *Urb,
347 IN UINTN Timeout
348 )
349 {
350 TRANSFER_RING *Ring;
351 TRB_TEMPLATE *Trb;
352 UINTN Loop;
353 UINTN Index;
354
355 Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
356 if (Timeout == 0) {
357 Loop = 0xFFFFFFFF;
358 }
359 XhcRingDoorBell (Handle, Urb);
360 //
361 // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
362 //
363 for (Index = 0; Index < Loop; Index++) {
364 XhcCheckUrbResult (Handle, Urb);
365 if (Urb->Finished) {
366 break;
367 }
368 MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
369 }
370 if (Index == Loop) {
371 //
372 // If time out occurs.
373 //
374 Urb->Result |= EFI_USB_ERR_TIMEOUT;
375 }
376 //
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.
379 //
380 Ring = (TRANSFER_RING *)(UINTN) Urb->Ring;
381 if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {
382 //
383 // Adjust Enqueue pointer
384 //
385 Ring->RingEnqueue = Urb->Trb;
386 //
387 // Clear CCS flag for next use
388 //
389 Trb = (TRB_TEMPLATE *)(UINTN) Urb->Trb;
390 Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
391 } else {
392 //
393 // Update transfer ring for next transfer.
394 //
395 XhcSyncTrsRing (Handle, Ring);
396 }
397 }
398
399 /**
400 Create a transfer TRB.
401
402 @param Handle Debug port handle.
403 @param Urb The urb used to construct the transfer TRB.
404
405 @return Created TRB or NULL
406
407 **/
408 EFI_STATUS
409 XhcCreateTransferTrb (
410 IN USB3_DEBUG_PORT_HANDLE *Handle,
411 IN URB *Urb
412 )
413 {
414 TRANSFER_RING *EPRing;
415 TRB *Trb;
416
417 if (Urb->Direction == EfiUsbDataIn) {
418 EPRing = &Handle->TransferRingIn;
419 } else {
420 EPRing = &Handle->TransferRingOut;
421 }
422
423 Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN) EPRing;
424 XhcSyncTrsRing (Handle, EPRing);
425
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;
436
437 //
438 // Update the cycle bit to indicate this TRB has been consumed.
439 //
440 Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
441
442 return EFI_SUCCESS;
443 }
444
445 /**
446 Create a new URB for a new transaction.
447
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
452
453 @return Created URB or NULL
454
455 **/
456 URB*
457 XhcCreateUrb (
458 IN USB3_DEBUG_PORT_HANDLE *Handle,
459 IN EFI_USB_DATA_DIRECTION Direction,
460 IN VOID *Data,
461 IN UINTN DataLen
462 )
463 {
464 EFI_STATUS Status;
465 URB *Urb;
466 EFI_PHYSICAL_ADDRESS UrbData;
467
468 if (Direction == EfiUsbDataIn) {
469 Urb = &Handle->UrbIn;
470 } else {
471 Urb = &Handle->UrbOut;
472 }
473
474 UrbData = Urb->Data;
475
476 ZeroMem (Urb, sizeof (URB));
477 Urb->Direction = Direction;
478
479 //
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
483 //
484 Urb->Data = UrbData;
485
486 if (Direction == EfiUsbDataIn) {
487 //
488 // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
489 //
490 Urb->DataLen = (UINT32) DataLen;
491 } else {
492 //
493 // Put data into URB data out buffer which will create TRBs
494 //
495 ZeroMem ((VOID*)(UINTN) Urb->Data, DataLen);
496 CopyMem ((VOID*)(UINTN) Urb->Data, Data, DataLen);
497 Urb->DataLen = (UINT32) DataLen;
498 }
499
500 Status = XhcCreateTransferTrb (Handle, Urb);
501 ASSERT_EFI_ERROR (Status);
502
503 return Urb;
504 }
505
506 /**
507 Submits bulk transfer to a bulk endpoint of a USB device.
508
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.
516
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.
522
523 **/
524 EFI_STATUS
525 EFIAPI
526 XhcDataTransfer (
527 IN USB3_DEBUG_PORT_HANDLE *Handle,
528 IN EFI_USB_DATA_DIRECTION Direction,
529 IN OUT VOID *Data,
530 IN OUT UINTN *DataLength,
531 IN UINTN Timeout
532 )
533 {
534 URB *Urb;
535 EFI_STATUS Status;
536
537 //
538 // Validate the parameters
539 //
540 if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 //
545 // Create a new URB, insert it into the asynchronous
546 // schedule list, then poll the execution status.
547 //
548 Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);
549 ASSERT (Urb != NULL);
550
551 XhcExecTransfer (Handle, Urb, Timeout);
552
553 //
554 // Make sure the data received from HW can fit in the received buffer.
555 //
556 if (Urb->Completed > *DataLength) {
557 return EFI_DEVICE_ERROR;
558 }
559
560 *DataLength = Urb->Completed;
561
562 Status = EFI_TIMEOUT;
563 if (Urb->Result == EFI_USB_NOERROR) {
564 Status = EFI_SUCCESS;
565 }
566
567 if (Direction == EfiUsbDataIn) {
568 //
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.
571 //
572 CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
573 }
574
575 return Status;
576 }
577