]> git.proxmox.com Git - mirror_edk2.git/blame - SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugCommunicationLibUsb3 / DebugCommunicationLibUsb3Dxe.c
CommitLineData
2cb6eabe
EL
1/** @file\r
2 Debug Port Library implementation based on usb3 debug port.\r
3\r
75787f65 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\r
9#include <Base.h>\r
10#include <PiDxe.h>\r
11#include <Library/UefiBootServicesTableLib.h>\r
75787f65
SZ
12#include <Library/HobLib.h>\r
13#include <Protocol/PciIo.h>\r
14#include <Protocol/IoMmu.h>\r
15#include <Protocol/DxeSmmReadyToLock.h>\r
2cb6eabe
EL
16#include "DebugCommunicationLibUsb3Internal.h"\r
17\r
c1e126b1 18GUID gUsb3DbgGuid = USB3_DBG_GUID;\r
75787f65 19\r
c1e126b1
MK
20USB3_DEBUG_PORT_HANDLE mUsb3Instance = { USB3DBG_UNINITIALIZED };\r
21EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;\r
22EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;\r
23EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;\r
75787f65
SZ
24\r
25/**\r
26 Creates a named event that can be signaled.\r
27\r
1825c24f 28 This function creates an event using NotifyTpl, NotifyFunction.\r
75787f65
SZ
29 If Name is NULL, then ASSERT().\r
30 If NotifyTpl is not a legal TPL value, then ASSERT().\r
31 If NotifyFunction is NULL, then ASSERT().\r
32\r
33 @param Name Supplies the GUID name of the event.\r
34 @param NotifyTpl Supplies the task priority level of the event notifications.\r
35 @param NotifyFunction Supplies the function to notify when the event is signaled.\r
36 @param Event A pointer to the event created.\r
37\r
38 @retval EFI_SUCCESS A named event was created.\r
39 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.\r
40\r
41**/\r
42EFI_STATUS\r
43EFIAPI\r
44Usb3NamedEventListen (\r
45 IN CONST EFI_GUID *Name,\r
46 IN EFI_TPL NotifyTpl,\r
47 IN EFI_EVENT_NOTIFY NotifyFunction,\r
48 IN EFI_EVENT *Event\r
49 )\r
50{\r
51 EFI_STATUS Status;\r
52 VOID *RegistrationLocal;\r
53\r
54 ASSERT (Name != NULL);\r
55 ASSERT (NotifyFunction != NULL);\r
56 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);\r
57\r
58 //\r
59 // Create event\r
60 //\r
61 Status = gBS->CreateEvent (\r
62 EVT_NOTIFY_SIGNAL,\r
63 NotifyTpl,\r
64 NotifyFunction,\r
65 NULL,\r
66 Event\r
67 );\r
68 ASSERT_EFI_ERROR (Status);\r
69\r
70 //\r
71 // Register for an installation of protocol interface\r
72 //\r
73 Status = gBS->RegisterProtocolNotify (\r
c1e126b1 74 (EFI_GUID *)Name,\r
75787f65
SZ
75 *Event,\r
76 &RegistrationLocal\r
77 );\r
78 ASSERT_EFI_ERROR (Status);\r
79\r
80 return Status;\r
81}\r
82\r
83/**\r
84 USB3 map one DMA buffer.\r
85\r
86 @param PciIo Pointer to PciIo for USB3 debug port.\r
87 @param Address DMA buffer address to be mapped.\r
88 @param NumberOfBytes Number of bytes to be mapped.\r
89\r
90**/\r
91VOID\r
92Usb3MapOneDmaBuffer (\r
c1e126b1
MK
93 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
94 IN EFI_PHYSICAL_ADDRESS Address,\r
95 IN UINTN NumberOfBytes\r
75787f65
SZ
96 )\r
97{\r
c1e126b1
MK
98 EFI_STATUS Status;\r
99 VOID *HostAddress;\r
100 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
101 VOID *Mapping;\r
102\r
103 HostAddress = (VOID *)(UINTN)Address;\r
104 Status = PciIo->Map (\r
105 PciIo,\r
106 EfiPciIoOperationBusMasterCommonBuffer,\r
107 HostAddress,\r
108 &NumberOfBytes,\r
109 &DeviceAddress,\r
110 &Mapping\r
111 );\r
75787f65 112 ASSERT_EFI_ERROR (Status);\r
c1e126b1 113 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));\r
75787f65
SZ
114}\r
115\r
116/**\r
117 USB3 map DMA buffers.\r
118\r
119 @param Instance Pointer to USB3 debug port instance.\r
120 @param PciIo Pointer to PciIo for USB3 debug port.\r
121\r
122**/\r
123VOID\r
124Usb3MapDmaBuffers (\r
c1e126b1
MK
125 IN USB3_DEBUG_PORT_HANDLE *Instance,\r
126 IN EFI_PCI_IO_PROTOCOL *PciIo\r
75787f65
SZ
127 )\r
128{\r
129 Usb3MapOneDmaBuffer (\r
130 PciIo,\r
131 Instance->UrbIn.Data,\r
132 XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE\r
133 );\r
134\r
135 Usb3MapOneDmaBuffer (\r
136 PciIo,\r
137 Instance->TransferRingIn.RingSeg0,\r
138 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
139 );\r
140\r
141 Usb3MapOneDmaBuffer (\r
142 PciIo,\r
143 Instance->TransferRingOut.RingSeg0,\r
144 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
145 );\r
146\r
147 Usb3MapOneDmaBuffer (\r
148 PciIo,\r
149 Instance->EventRing.EventRingSeg0,\r
150 sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER\r
151 );\r
152\r
153 Usb3MapOneDmaBuffer (\r
154 PciIo,\r
155 Instance->EventRing.ERSTBase,\r
156 sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER\r
157 );\r
158\r
159 Usb3MapOneDmaBuffer (\r
160 PciIo,\r
161 Instance->DebugCapabilityContext,\r
162 sizeof (XHC_DC_CONTEXT)\r
163 );\r
164\r
165 Usb3MapOneDmaBuffer (\r
166 PciIo,\r
c1e126b1 167 ((XHC_DC_CONTEXT *)(UINTN)Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,\r
75787f65
SZ
168 STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN\r
169 );\r
170}\r
171\r
172/**\r
173 Invoke a notification event\r
174\r
175 @param[in] Event Event whose notification function is being invoked.\r
176 @param[in] Context The pointer to the notification function's context,\r
177 which is implementation-dependent.\r
178\r
179**/\r
180VOID\r
181EFIAPI\r
182Usb3DxeSmmReadyToLockNotify (\r
c1e126b1
MK
183 IN EFI_EVENT Event,\r
184 IN VOID *Context\r
75787f65
SZ
185 )\r
186{\r
c1e126b1 187 USB3_DEBUG_PORT_HANDLE *Instance;\r
75787f65
SZ
188\r
189 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
190\r
191 Instance = GetUsb3DebugPortInstance ();\r
192 ASSERT (Instance != NULL);\r
193\r
194 Instance->InNotify = TRUE;\r
195\r
196 //\r
197 // For the case that the USB3 debug port instance and DMA buffers are\r
198 // from PEI HOB with IOMMU enabled.\r
199 // Reinitialize USB3 debug port with granted DXE DMA buffer accessible\r
200 // by SMM environment.\r
201 //\r
202 InitializeUsbDebugHardware (Instance);\r
203\r
204 //\r
205 // Wait some time for host to be ready after re-initialization.\r
206 //\r
207 MicroSecondDelay (1000000);\r
208\r
209 Instance->InNotify = FALSE;\r
210 gBS->CloseEvent (Event);\r
211}\r
212\r
213/**\r
214 USB3 get IOMMU protocol.\r
215\r
216 @return Pointer to IOMMU protocol.\r
217\r
218**/\r
219EDKII_IOMMU_PROTOCOL *\r
220Usb3GetIoMmu (\r
221 VOID\r
222 )\r
223{\r
c1e126b1
MK
224 EFI_STATUS Status;\r
225 EDKII_IOMMU_PROTOCOL *IoMmu;\r
75787f65 226\r
c1e126b1 227 IoMmu = NULL;\r
75787f65 228 Status = gBS->LocateProtocol (\r
c1e126b1
MK
229 &gEdkiiIoMmuProtocolGuid,\r
230 NULL,\r
231 (VOID **)&IoMmu\r
232 );\r
75787f65
SZ
233 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {\r
234 return IoMmu;\r
235 }\r
236\r
237 return NULL;\r
238}\r
239\r
240/**\r
241 Invoke a notification event\r
242\r
243 @param[in] Event Event whose notification function is being invoked.\r
244 @param[in] Context The pointer to the notification function's context,\r
245 which is implementation-dependent.\r
246\r
247**/\r
248VOID\r
249EFIAPI\r
250Usb3PciIoNotify (\r
c1e126b1
MK
251 IN EFI_EVENT Event,\r
252 IN VOID *Context\r
75787f65
SZ
253 )\r
254{\r
c1e126b1
MK
255 EFI_STATUS Status;\r
256 UINTN PciIoHandleCount;\r
257 EFI_HANDLE *PciIoHandleBuffer;\r
258 UINTN Index;\r
259 EFI_PCI_IO_PROTOCOL *PciIo;\r
260 UINTN PciSegment;\r
261 UINTN PciBusNumber;\r
262 UINTN PciDeviceNumber;\r
263 UINTN PciFunctionNumber;\r
264 UINT32 PciAddress;\r
265 USB3_DEBUG_PORT_HANDLE *Instance;\r
266 EFI_EVENT SmmReadyToLockEvent;\r
75787f65
SZ
267\r
268 Status = gBS->LocateHandleBuffer (\r
269 ByProtocol,\r
270 &gEfiPciIoProtocolGuid,\r
271 NULL,\r
272 &PciIoHandleCount,\r
273 &PciIoHandleBuffer\r
274 );\r
275 if (!EFI_ERROR (Status) &&\r
276 (PciIoHandleBuffer != NULL) &&\r
c1e126b1
MK
277 (PciIoHandleCount != 0))\r
278 {\r
75787f65
SZ
279 for (Index = 0; Index < PciIoHandleCount; Index++) {\r
280 Status = gBS->HandleProtocol (\r
281 PciIoHandleBuffer[Index],\r
282 &gEfiPciIoProtocolGuid,\r
c1e126b1 283 (VOID **)&PciIo\r
75787f65
SZ
284 );\r
285 ASSERT_EFI_ERROR (Status);\r
286 Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);\r
287 ASSERT_EFI_ERROR (Status);\r
c1e126b1
MK
288 PciAddress = (UINT32)((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));\r
289 if (PciAddress == PcdGet32 (PcdUsbXhciPciAddress)) {\r
75787f65
SZ
290 //\r
291 // Found the PciIo for USB3 debug port.\r
292 //\r
293 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
294 if (Usb3GetIoMmu () != NULL) {\r
295 Instance = GetUsb3DebugPortInstance ();\r
296 ASSERT (Instance != NULL);\r
297 if (Instance->Ready) {\r
298 Instance->InNotify = TRUE;\r
299 Usb3MapDmaBuffers (Instance, PciIo);\r
300 Instance->InNotify = FALSE;\r
301\r
302 if (Instance->FromHob) {\r
303 mUsb3PciIo = PciIo;\r
304 Usb3NamedEventListen (\r
305 &gEfiDxeSmmReadyToLockProtocolGuid,\r
306 TPL_NOTIFY,\r
307 Usb3DxeSmmReadyToLockNotify,\r
308 &SmmReadyToLockEvent\r
309 );\r
310 }\r
311 }\r
312 }\r
c1e126b1 313\r
75787f65
SZ
314 gBS->CloseEvent (Event);\r
315 break;\r
316 }\r
317 }\r
318\r
319 gBS->FreePool (PciIoHandleBuffer);\r
320 }\r
321}\r
322\r
323/**\r
324 Return USB3 debug instance address pointer.\r
325\r
77695f4d 326**/\r
75787f65
SZ
327EFI_PHYSICAL_ADDRESS *\r
328GetUsb3DebugPortInstanceAddrPtr (\r
329 VOID\r
330 )\r
331{\r
332 if (mUsb3InstanceAddrPtr == NULL) {\r
333 //\r
334 // Use the local variables temporarily.\r
335 //\r
c1e126b1 336 mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)&mUsb3Instance;\r
75787f65
SZ
337 mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;\r
338 }\r
c1e126b1 339\r
75787f65
SZ
340 return mUsb3InstanceAddrPtr;\r
341}\r
342\r
343/**\r
344 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
345 OperationBusMasterCommonBuffer64 mapping.\r
346\r
347 @param PciIo Pointer to PciIo for USB3 debug port.\r
348 @param Pages The number of pages to allocate.\r
349 @param Address A pointer to store the base system memory address of the\r
350 allocated range.\r
351\r
352 @retval EFI_SUCCESS The requested memory pages were allocated.\r
353 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
354 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
355 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
356 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
357\r
358**/\r
359EFI_STATUS\r
360Usb3AllocateDmaBuffer (\r
c1e126b1
MK
361 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
362 IN UINTN Pages,\r
363 OUT VOID **Address\r
75787f65
SZ
364 )\r
365{\r
c1e126b1 366 EFI_STATUS Status;\r
75787f65
SZ
367\r
368 *Address = NULL;\r
c1e126b1
MK
369 Status = PciIo->AllocateBuffer (\r
370 PciIo,\r
371 AllocateAnyPages,\r
372 EfiRuntimeServicesData,\r
373 Pages,\r
374 Address,\r
375 0\r
376 );\r
75787f65
SZ
377 if (!EFI_ERROR (Status)) {\r
378 Usb3MapOneDmaBuffer (\r
379 PciIo,\r
c1e126b1 380 (EFI_PHYSICAL_ADDRESS)(UINTN)*Address,\r
75787f65
SZ
381 EFI_PAGES_TO_SIZE (Pages)\r
382 );\r
383 }\r
c1e126b1 384\r
75787f65
SZ
385 return Status;\r
386}\r
387\r
2cb6eabe
EL
388/**\r
389 Allocate aligned memory for XHC's usage.\r
390\r
391 @param BufferSize The size, in bytes, of the Buffer.\r
77695f4d 392\r
2cb6eabe
EL
393 @return A pointer to the allocated buffer or NULL if allocation fails.\r
394\r
395**/\r
c1e126b1 396VOID *\r
2cb6eabe 397AllocateAlignBuffer (\r
c1e126b1 398 IN UINTN BufferSize\r
2cb6eabe
EL
399 )\r
400{\r
c1e126b1
MK
401 EFI_PHYSICAL_ADDRESS TmpAddr;\r
402 EFI_STATUS Status;\r
403 VOID *Buf;\r
77695f4d 404\r
2cb6eabe 405 Buf = NULL;\r
77695f4d 406\r
2cb6eabe 407 if (gBS != NULL) {\r
75787f65
SZ
408 if (mUsb3PciIo != NULL) {\r
409 Usb3AllocateDmaBuffer (\r
410 mUsb3PciIo,\r
411 EFI_SIZE_TO_PAGES (BufferSize),\r
412 &Buf\r
413 );\r
414 } else {\r
415 TmpAddr = 0xFFFFFFFF;\r
c1e126b1
MK
416 Status = gBS->AllocatePages (\r
417 AllocateMaxAddress,\r
418 EfiACPIMemoryNVS,\r
419 EFI_SIZE_TO_PAGES (BufferSize),\r
420 &TmpAddr\r
421 );\r
75787f65 422 if (!EFI_ERROR (Status)) {\r
c1e126b1 423 Buf = (VOID *)(UINTN)TmpAddr;\r
75787f65
SZ
424 }\r
425 }\r
426 }\r
427\r
428 return Buf;\r
429}\r
430\r
431/**\r
432 The constructor function initialize USB3 debug port.\r
433\r
434 @param ImageHandle The firmware allocated handle for the EFI image.\r
435 @param SystemTable A pointer to the EFI System Table.\r
436\r
437 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
438\r
439**/\r
440EFI_STATUS\r
441EFIAPI\r
442DebugCommunicationUsb3DxeConstructor (\r
443 IN EFI_HANDLE ImageHandle,\r
444 IN EFI_SYSTEM_TABLE *SystemTable\r
445 )\r
446{\r
c1e126b1
MK
447 EFI_PHYSICAL_ADDRESS *AddrPtr;\r
448 USB3_DEBUG_PORT_HANDLE *Instance;\r
449 EFI_PHYSICAL_ADDRESS Address;\r
450 EFI_STATUS Status;\r
451 EFI_EVENT Event;\r
75787f65 452\r
c1e126b1 453 Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **)&AddrPtr);\r
40535873 454 if (EFI_ERROR (Status) || (AddrPtr == NULL)) {\r
75787f65
SZ
455 //\r
456 // Instead of using local variables, install system configuration table for\r
457 // the local instance and the buffer to save instance address pointer.\r
458 //\r
459 Address = SIZE_4GB;\r
c1e126b1
MK
460 Status = gBS->AllocatePages (\r
461 AllocateMaxAddress,\r
462 EfiACPIMemoryNVS,\r
463 EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),\r
464 &Address\r
465 );\r
75787f65
SZ
466 if (EFI_ERROR (Status)) {\r
467 return Status;\r
468 }\r
469\r
c1e126b1 470 AddrPtr = (EFI_PHYSICAL_ADDRESS *)(UINTN)Address;\r
75787f65 471 ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));\r
c1e126b1 472 Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);\r
75787f65 473 CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));\r
c1e126b1 474 *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;\r
75787f65
SZ
475\r
476 Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);\r
477 if (EFI_ERROR (Status)) {\r
478 return Status;\r
479 }\r
480 }\r
481\r
482 if (mUsb3InstanceAddrPtr != NULL) {\r
483 *AddrPtr = *mUsb3InstanceAddrPtr;\r
484 }\r
c1e126b1 485\r
75787f65
SZ
486 mUsb3InstanceAddrPtr = AddrPtr;\r
487\r
488 Instance = GetUsb3DebugPortInstance ();\r
489 ASSERT (Instance != NULL);\r
490\r
491 if (Instance->PciIoEvent == 0) {\r
492 Status = Usb3NamedEventListen (\r
493 &gEfiPciIoProtocolGuid,\r
494 TPL_NOTIFY,\r
495 Usb3PciIoNotify,\r
496 &Event\r
95055567
ED
497 );\r
498 if (!EFI_ERROR (Status)) {\r
c1e126b1 499 Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS)(UINTN)Event;\r
95055567 500 }\r
2cb6eabe
EL
501 }\r
502\r
75787f65
SZ
503 return EFI_SUCCESS;\r
504}\r
505\r
506/**\r
507 The destructor function.\r
508\r
509 @param ImageHandle The firmware allocated handle for the EFI image.\r
510 @param SystemTable A pointer to the EFI System Table.\r
511\r
512 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.\r
513\r
514**/\r
515EFI_STATUS\r
516EFIAPI\r
517DebugCommunicationUsb3DxeDestructor (\r
518 IN EFI_HANDLE ImageHandle,\r
519 IN EFI_SYSTEM_TABLE *SystemTable\r
520 )\r
521{\r
c1e126b1 522 USB3_DEBUG_PORT_HANDLE *Instance;\r
75787f65
SZ
523\r
524 Instance = GetUsb3DebugPortInstance ();\r
525 ASSERT (Instance != NULL);\r
526\r
527 if (Instance->PciIoEvent != 0) {\r
528 //\r
529 // Close the event created.\r
530 //\r
c1e126b1 531 gBS->CloseEvent ((EFI_EVENT)(UINTN)Instance->PciIoEvent);\r
75787f65
SZ
532 Instance->PciIoEvent = 0;\r
533 }\r
c1e126b1 534\r
75787f65 535 return EFI_SUCCESS;\r
2cb6eabe 536}\r