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)) {
278 for (Index
= 0; Index
< PciIoHandleCount
; Index
++) {
279 Status
= gBS
->HandleProtocol (
280 PciIoHandleBuffer
[Index
],
281 &gEfiPciIoProtocolGuid
,
284 ASSERT_EFI_ERROR (Status
);
285 Status
= PciIo
->GetLocation (PciIo
, &PciSegment
, &PciBusNumber
, &PciDeviceNumber
, &PciFunctionNumber
);
286 ASSERT_EFI_ERROR (Status
);
287 PciAddress
= (UINT32
) ((PciBusNumber
<< 20) | (PciDeviceNumber
<< 15) | (PciFunctionNumber
<< 12));
288 if (PciAddress
== PcdGet32(PcdUsbXhciPciAddress
)) {
290 // Found the PciIo for USB3 debug port.
292 DEBUG ((DEBUG_INFO
, "%a()\n", __FUNCTION__
));
293 if (Usb3GetIoMmu () != NULL
) {
294 Instance
= GetUsb3DebugPortInstance ();
295 ASSERT (Instance
!= NULL
);
296 if (Instance
->Ready
) {
297 Instance
->InNotify
= TRUE
;
298 Usb3MapDmaBuffers (Instance
, PciIo
);
299 Instance
->InNotify
= FALSE
;
301 if (Instance
->FromHob
) {
303 Usb3NamedEventListen (
304 &gEfiDxeSmmReadyToLockProtocolGuid
,
306 Usb3DxeSmmReadyToLockNotify
,
312 gBS
->CloseEvent (Event
);
317 gBS
->FreePool (PciIoHandleBuffer
);
322 Return USB3 debug instance address pointer.
325 EFI_PHYSICAL_ADDRESS
*
326 GetUsb3DebugPortInstanceAddrPtr (
330 if (mUsb3InstanceAddrPtr
== NULL
) {
332 // Use the local variables temporarily.
334 mUsb3InstanceAddr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) &mUsb3Instance
;
335 mUsb3InstanceAddrPtr
= &mUsb3InstanceAddr
;
337 return mUsb3InstanceAddrPtr
;
341 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
342 OperationBusMasterCommonBuffer64 mapping.
344 @param PciIo Pointer to PciIo for USB3 debug port.
345 @param Pages The number of pages to allocate.
346 @param Address A pointer to store the base system memory address of the
349 @retval EFI_SUCCESS The requested memory pages were allocated.
350 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
351 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
352 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
353 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
357 Usb3AllocateDmaBuffer (
358 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
366 Status
= PciIo
->AllocateBuffer (
369 EfiRuntimeServicesData
,
374 if (!EFI_ERROR (Status
)) {
375 Usb3MapOneDmaBuffer (
377 (EFI_PHYSICAL_ADDRESS
) (UINTN
) *Address
,
378 EFI_PAGES_TO_SIZE (Pages
)
385 Allocate aligned memory for XHC's usage.
387 @param BufferSize The size, in bytes, of the Buffer.
389 @return A pointer to the allocated buffer or NULL if allocation fails.
393 AllocateAlignBuffer (
397 EFI_PHYSICAL_ADDRESS TmpAddr
;
404 if (mUsb3PciIo
!= NULL
) {
405 Usb3AllocateDmaBuffer (
407 EFI_SIZE_TO_PAGES (BufferSize
),
411 TmpAddr
= 0xFFFFFFFF;
412 Status
= gBS
->AllocatePages (
415 EFI_SIZE_TO_PAGES (BufferSize
),
418 if (!EFI_ERROR (Status
)) {
419 Buf
= (VOID
*) (UINTN
) TmpAddr
;
428 The constructor function initialize USB3 debug port.
430 @param ImageHandle The firmware allocated handle for the EFI image.
431 @param SystemTable A pointer to the EFI System Table.
433 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
438 DebugCommunicationUsb3DxeConstructor (
439 IN EFI_HANDLE ImageHandle
,
440 IN EFI_SYSTEM_TABLE
*SystemTable
443 EFI_PHYSICAL_ADDRESS
*AddrPtr
;
444 USB3_DEBUG_PORT_HANDLE
*Instance
;
445 EFI_PHYSICAL_ADDRESS Address
;
449 Status
= EfiGetSystemConfigurationTable (&gUsb3DbgGuid
, (VOID
**) &AddrPtr
);
450 if (EFI_ERROR (Status
) || (AddrPtr
== NULL
)) {
452 // Instead of using local variables, install system configuration table for
453 // the local instance and the buffer to save instance address pointer.
456 Status
= gBS
->AllocatePages (
459 EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS
) + sizeof (USB3_DEBUG_PORT_HANDLE
)),
462 if (EFI_ERROR (Status
)) {
466 AddrPtr
= (EFI_PHYSICAL_ADDRESS
*) (UINTN
) Address
;
467 ZeroMem (AddrPtr
, sizeof (EFI_PHYSICAL_ADDRESS
) + sizeof (USB3_DEBUG_PORT_HANDLE
));
468 Instance
= (USB3_DEBUG_PORT_HANDLE
*) (AddrPtr
+ 1);
469 CopyMem (Instance
, &mUsb3Instance
, sizeof (USB3_DEBUG_PORT_HANDLE
));
470 *AddrPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Instance
;
472 Status
= gBS
->InstallConfigurationTable (&gUsb3DbgGuid
, AddrPtr
);
473 if (EFI_ERROR (Status
)) {
478 if (mUsb3InstanceAddrPtr
!= NULL
) {
479 *AddrPtr
= *mUsb3InstanceAddrPtr
;
481 mUsb3InstanceAddrPtr
= AddrPtr
;
483 Instance
= GetUsb3DebugPortInstance ();
484 ASSERT (Instance
!= NULL
);
486 if (Instance
->PciIoEvent
== 0) {
487 Status
= Usb3NamedEventListen (
488 &gEfiPciIoProtocolGuid
,
493 if (!EFI_ERROR (Status
)) {
494 Instance
->PciIoEvent
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Event
;
502 The destructor function.
504 @param ImageHandle The firmware allocated handle for the EFI image.
505 @param SystemTable A pointer to the EFI System Table.
507 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
512 DebugCommunicationUsb3DxeDestructor (
513 IN EFI_HANDLE ImageHandle
,
514 IN EFI_SYSTEM_TABLE
*SystemTable
517 USB3_DEBUG_PORT_HANDLE
*Instance
;
519 Instance
= GetUsb3DebugPortInstance ();
520 ASSERT (Instance
!= NULL
);
522 if (Instance
->PciIoEvent
!= 0) {
524 // Close the event created.
526 gBS
->CloseEvent ((EFI_EVENT
) (UINTN
) Instance
->PciIoEvent
);
527 Instance
->PciIoEvent
= 0;