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