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