2 Debug Port Library implementation based on usb3 debug port.
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/UefiBootServicesTableLib.h>
12 #include <Library/HobLib.h>
13 #include <Protocol/PciIo.h>
14 #include <Protocol/IoMmu.h>
15 #include <Protocol/DxeSmmReadyToLock.h>
16 #include "DebugCommunicationLibUsb3Internal.h"
18 GUID gUsb3DbgGuid
= USB3_DBG_GUID
;
20 USB3_DEBUG_PORT_HANDLE mUsb3Instance
= { USB3DBG_UNINITIALIZED
};
21 EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr
= 0;
22 EFI_PHYSICAL_ADDRESS
*mUsb3InstanceAddrPtr
= NULL
;
23 EFI_PCI_IO_PROTOCOL
*mUsb3PciIo
= NULL
;
26 Creates a named event that can be signaled.
28 This function creates an event using NotifyTpl, NotifyFunction.
29 If Name is NULL, then ASSERT().
30 If NotifyTpl is not a legal TPL value, then ASSERT().
31 If NotifyFunction is NULL, then ASSERT().
33 @param Name Supplies the GUID name of the event.
34 @param NotifyTpl Supplies the task priority level of the event notifications.
35 @param NotifyFunction Supplies the function to notify when the event is signaled.
36 @param Event A pointer to the event created.
38 @retval EFI_SUCCESS A named event was created.
39 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
44 Usb3NamedEventListen (
45 IN CONST EFI_GUID
*Name
,
47 IN EFI_EVENT_NOTIFY NotifyFunction
,
52 VOID
*RegistrationLocal
;
54 ASSERT (Name
!= NULL
);
55 ASSERT (NotifyFunction
!= NULL
);
56 ASSERT (NotifyTpl
<= TPL_HIGH_LEVEL
);
61 Status
= gBS
->CreateEvent (
68 ASSERT_EFI_ERROR (Status
);
71 // Register for an installation of protocol interface
73 Status
= gBS
->RegisterProtocolNotify (
78 ASSERT_EFI_ERROR (Status
);
84 USB3 map one DMA buffer.
86 @param PciIo Pointer to PciIo for USB3 debug port.
87 @param Address DMA buffer address to be mapped.
88 @param NumberOfBytes Number of bytes to be mapped.
93 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
94 IN EFI_PHYSICAL_ADDRESS Address
,
95 IN UINTN NumberOfBytes
100 EFI_PHYSICAL_ADDRESS DeviceAddress
;
103 HostAddress
= (VOID
*)(UINTN
)Address
;
104 Status
= PciIo
->Map (
106 EfiPciIoOperationBusMasterCommonBuffer
,
112 ASSERT_EFI_ERROR (Status
);
113 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
));
117 USB3 map DMA buffers.
119 @param Instance Pointer to USB3 debug port instance.
120 @param PciIo Pointer to PciIo for USB3 debug port.
125 IN USB3_DEBUG_PORT_HANDLE
*Instance
,
126 IN EFI_PCI_IO_PROTOCOL
*PciIo
129 Usb3MapOneDmaBuffer (
131 Instance
->UrbIn
.Data
,
132 XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
* 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
135 Usb3MapOneDmaBuffer (
137 Instance
->TransferRingIn
.RingSeg0
,
138 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
141 Usb3MapOneDmaBuffer (
143 Instance
->TransferRingOut
.RingSeg0
,
144 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
147 Usb3MapOneDmaBuffer (
149 Instance
->EventRing
.EventRingSeg0
,
150 sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
153 Usb3MapOneDmaBuffer (
155 Instance
->EventRing
.ERSTBase
,
156 sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
159 Usb3MapOneDmaBuffer (
161 Instance
->DebugCapabilityContext
,
162 sizeof (XHC_DC_CONTEXT
)
165 Usb3MapOneDmaBuffer (
167 ((XHC_DC_CONTEXT
*)(UINTN
)Instance
->DebugCapabilityContext
)->DbcInfoContext
.String0DescAddress
,
168 STRING0_DESC_LEN
+ MANU_DESC_LEN
+ PRODUCT_DESC_LEN
+ SERIAL_DESC_LEN
173 Invoke a notification event
175 @param[in] Event Event whose notification function is being invoked.
176 @param[in] Context The pointer to the notification function's context,
177 which is implementation-dependent.
182 Usb3DxeSmmReadyToLockNotify (
187 USB3_DEBUG_PORT_HANDLE
*Instance
;
189 DEBUG ((DEBUG_INFO
, "%a()\n", __FUNCTION__
));
191 Instance
= GetUsb3DebugPortInstance ();
192 ASSERT (Instance
!= NULL
);
194 Instance
->InNotify
= TRUE
;
197 // For the case that the USB3 debug port instance and DMA buffers are
198 // from PEI HOB with IOMMU enabled.
199 // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
200 // by SMM environment.
202 InitializeUsbDebugHardware (Instance
);
205 // Wait some time for host to be ready after re-initialization.
207 MicroSecondDelay (1000000);
209 Instance
->InNotify
= FALSE
;
210 gBS
->CloseEvent (Event
);
214 USB3 get IOMMU protocol.
216 @return Pointer to IOMMU protocol.
219 EDKII_IOMMU_PROTOCOL
*
225 EDKII_IOMMU_PROTOCOL
*IoMmu
;
228 Status
= gBS
->LocateProtocol (
229 &gEdkiiIoMmuProtocolGuid
,
233 if (!EFI_ERROR (Status
) && (IoMmu
!= NULL
)) {
241 Invoke a notification event
243 @param[in] Event Event whose notification function is being invoked.
244 @param[in] Context The pointer to the notification function's context,
245 which is implementation-dependent.
256 UINTN PciIoHandleCount
;
257 EFI_HANDLE
*PciIoHandleBuffer
;
259 EFI_PCI_IO_PROTOCOL
*PciIo
;
262 UINTN PciDeviceNumber
;
263 UINTN PciFunctionNumber
;
265 USB3_DEBUG_PORT_HANDLE
*Instance
;
266 EFI_EVENT SmmReadyToLockEvent
;
268 Status
= gBS
->LocateHandleBuffer (
270 &gEfiPciIoProtocolGuid
,
275 if (!EFI_ERROR (Status
) &&
276 (PciIoHandleBuffer
!= NULL
) &&
277 (PciIoHandleCount
!= 0))
279 for (Index
= 0; Index
< PciIoHandleCount
; Index
++) {
280 Status
= gBS
->HandleProtocol (
281 PciIoHandleBuffer
[Index
],
282 &gEfiPciIoProtocolGuid
,
285 ASSERT_EFI_ERROR (Status
);
286 Status
= PciIo
->GetLocation (PciIo
, &PciSegment
, &PciBusNumber
, &PciDeviceNumber
, &PciFunctionNumber
);
287 ASSERT_EFI_ERROR (Status
);
288 PciAddress
= (UINT32
)((PciBusNumber
<< 20) | (PciDeviceNumber
<< 15) | (PciFunctionNumber
<< 12));
289 if (PciAddress
== PcdGet32 (PcdUsbXhciPciAddress
)) {
291 // Found the PciIo for USB3 debug port.
293 DEBUG ((DEBUG_INFO
, "%a()\n", __FUNCTION__
));
294 if (Usb3GetIoMmu () != NULL
) {
295 Instance
= GetUsb3DebugPortInstance ();
296 ASSERT (Instance
!= NULL
);
297 if (Instance
->Ready
) {
298 Instance
->InNotify
= TRUE
;
299 Usb3MapDmaBuffers (Instance
, PciIo
);
300 Instance
->InNotify
= FALSE
;
302 if (Instance
->FromHob
) {
304 Usb3NamedEventListen (
305 &gEfiDxeSmmReadyToLockProtocolGuid
,
307 Usb3DxeSmmReadyToLockNotify
,
314 gBS
->CloseEvent (Event
);
319 gBS
->FreePool (PciIoHandleBuffer
);
324 Return USB3 debug instance address pointer.
327 EFI_PHYSICAL_ADDRESS
*
328 GetUsb3DebugPortInstanceAddrPtr (
332 if (mUsb3InstanceAddrPtr
== NULL
) {
334 // Use the local variables temporarily.
336 mUsb3InstanceAddr
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&mUsb3Instance
;
337 mUsb3InstanceAddrPtr
= &mUsb3InstanceAddr
;
340 return mUsb3InstanceAddrPtr
;
344 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
345 OperationBusMasterCommonBuffer64 mapping.
347 @param PciIo Pointer to PciIo for USB3 debug port.
348 @param Pages The number of pages to allocate.
349 @param Address A pointer to store the base system memory address of the
352 @retval EFI_SUCCESS The requested memory pages were allocated.
353 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
354 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
355 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
356 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
360 Usb3AllocateDmaBuffer (
361 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
369 Status
= PciIo
->AllocateBuffer (
372 EfiRuntimeServicesData
,
377 if (!EFI_ERROR (Status
)) {
378 Usb3MapOneDmaBuffer (
380 (EFI_PHYSICAL_ADDRESS
)(UINTN
)*Address
,
381 EFI_PAGES_TO_SIZE (Pages
)
389 Allocate aligned memory for XHC's usage.
391 @param BufferSize The size, in bytes, of the Buffer.
393 @return A pointer to the allocated buffer or NULL if allocation fails.
397 AllocateAlignBuffer (
401 EFI_PHYSICAL_ADDRESS TmpAddr
;
408 if (mUsb3PciIo
!= NULL
) {
409 Usb3AllocateDmaBuffer (
411 EFI_SIZE_TO_PAGES (BufferSize
),
415 TmpAddr
= 0xFFFFFFFF;
416 Status
= gBS
->AllocatePages (
419 EFI_SIZE_TO_PAGES (BufferSize
),
422 if (!EFI_ERROR (Status
)) {
423 Buf
= (VOID
*)(UINTN
)TmpAddr
;
432 The constructor function initialize USB3 debug port.
434 @param ImageHandle The firmware allocated handle for the EFI image.
435 @param SystemTable A pointer to the EFI System Table.
437 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
442 DebugCommunicationUsb3DxeConstructor (
443 IN EFI_HANDLE ImageHandle
,
444 IN EFI_SYSTEM_TABLE
*SystemTable
447 EFI_PHYSICAL_ADDRESS
*AddrPtr
;
448 USB3_DEBUG_PORT_HANDLE
*Instance
;
449 EFI_PHYSICAL_ADDRESS Address
;
453 Status
= EfiGetSystemConfigurationTable (&gUsb3DbgGuid
, (VOID
**)&AddrPtr
);
454 if (EFI_ERROR (Status
) || (AddrPtr
== NULL
)) {
456 // Instead of using local variables, install system configuration table for
457 // the local instance and the buffer to save instance address pointer.
460 Status
= gBS
->AllocatePages (
463 EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS
) + sizeof (USB3_DEBUG_PORT_HANDLE
)),
466 if (EFI_ERROR (Status
)) {
470 AddrPtr
= (EFI_PHYSICAL_ADDRESS
*)(UINTN
)Address
;
471 ZeroMem (AddrPtr
, sizeof (EFI_PHYSICAL_ADDRESS
) + sizeof (USB3_DEBUG_PORT_HANDLE
));
472 Instance
= (USB3_DEBUG_PORT_HANDLE
*)(AddrPtr
+ 1);
473 CopyMem (Instance
, &mUsb3Instance
, sizeof (USB3_DEBUG_PORT_HANDLE
));
474 *AddrPtr
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Instance
;
476 Status
= gBS
->InstallConfigurationTable (&gUsb3DbgGuid
, AddrPtr
);
477 if (EFI_ERROR (Status
)) {
482 if (mUsb3InstanceAddrPtr
!= NULL
) {
483 *AddrPtr
= *mUsb3InstanceAddrPtr
;
486 mUsb3InstanceAddrPtr
= AddrPtr
;
488 Instance
= GetUsb3DebugPortInstance ();
489 ASSERT (Instance
!= NULL
);
491 if (Instance
->PciIoEvent
== 0) {
492 Status
= Usb3NamedEventListen (
493 &gEfiPciIoProtocolGuid
,
498 if (!EFI_ERROR (Status
)) {
499 Instance
->PciIoEvent
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Event
;
507 The destructor function.
509 @param ImageHandle The firmware allocated handle for the EFI image.
510 @param SystemTable A pointer to the EFI System Table.
512 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
517 DebugCommunicationUsb3DxeDestructor (
518 IN EFI_HANDLE ImageHandle
,
519 IN EFI_SYSTEM_TABLE
*SystemTable
522 USB3_DEBUG_PORT_HANDLE
*Instance
;
524 Instance
= GetUsb3DebugPortInstance ();
525 ASSERT (Instance
!= NULL
);
527 if (Instance
->PciIoEvent
!= 0) {
529 // Close the event created.
531 gBS
->CloseEvent ((EFI_EVENT
)(UINTN
)Instance
->PciIoEvent
);
532 Instance
->PciIoEvent
= 0;