2 Debug Port Library implementation based on usb3 debug port.
4 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/HobLib.h>
19 #include <Protocol/PciIo.h>
20 #include <Protocol/IoMmu.h>
21 #include <Protocol/DxeSmmReadyToLock.h>
22 #include "DebugCommunicationLibUsb3Internal.h"
24 GUID gUsb3DbgGuid
= USB3_DBG_GUID
;
26 USB3_DEBUG_PORT_HANDLE mUsb3Instance
= {USB3DBG_UNINITIALIZED
};
27 EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr
= 0;
28 EFI_PHYSICAL_ADDRESS
*mUsb3InstanceAddrPtr
= NULL
;
29 EFI_PCI_IO_PROTOCOL
*mUsb3PciIo
= NULL
;
32 Creates a named event that can be signaled.
34 This function creates an event using NotifyTpl, NoifyFunction.
35 If Name is NULL, then ASSERT().
36 If NotifyTpl is not a legal TPL value, then ASSERT().
37 If NotifyFunction is NULL, then ASSERT().
39 @param Name Supplies the GUID name of the event.
40 @param NotifyTpl Supplies the task priority level of the event notifications.
41 @param NotifyFunction Supplies the function to notify when the event is signaled.
42 @param Event A pointer to the event created.
44 @retval EFI_SUCCESS A named event was created.
45 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
50 Usb3NamedEventListen (
51 IN CONST EFI_GUID
*Name
,
53 IN EFI_EVENT_NOTIFY NotifyFunction
,
58 VOID
*RegistrationLocal
;
60 ASSERT (Name
!= NULL
);
61 ASSERT (NotifyFunction
!= NULL
);
62 ASSERT (NotifyTpl
<= TPL_HIGH_LEVEL
);
67 Status
= gBS
->CreateEvent (
74 ASSERT_EFI_ERROR (Status
);
77 // Register for an installation of protocol interface
79 Status
= gBS
->RegisterProtocolNotify (
84 ASSERT_EFI_ERROR (Status
);
90 USB3 map one DMA buffer.
92 @param PciIo Pointer to PciIo for USB3 debug port.
93 @param Address DMA buffer address to be mapped.
94 @param NumberOfBytes Number of bytes to be mapped.
99 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
100 IN EFI_PHYSICAL_ADDRESS Address
,
101 IN UINTN NumberOfBytes
106 EFI_PHYSICAL_ADDRESS DeviceAddress
;
109 HostAddress
= (VOID
*) (UINTN
) Address
;
110 Status
= PciIo
->Map (
112 EfiPciIoOperationBusMasterCommonBuffer
,
118 ASSERT_EFI_ERROR (Status
);
119 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
));
123 USB3 map DMA buffers.
125 @param Instance Pointer to USB3 debug port instance.
126 @param PciIo Pointer to PciIo for USB3 debug port.
131 IN USB3_DEBUG_PORT_HANDLE
*Instance
,
132 IN EFI_PCI_IO_PROTOCOL
*PciIo
135 Usb3MapOneDmaBuffer (
137 Instance
->UrbIn
.Data
,
138 XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
* 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
141 Usb3MapOneDmaBuffer (
143 Instance
->TransferRingIn
.RingSeg0
,
144 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
147 Usb3MapOneDmaBuffer (
149 Instance
->TransferRingOut
.RingSeg0
,
150 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
153 Usb3MapOneDmaBuffer (
155 Instance
->EventRing
.EventRingSeg0
,
156 sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
159 Usb3MapOneDmaBuffer (
161 Instance
->EventRing
.ERSTBase
,
162 sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
165 Usb3MapOneDmaBuffer (
167 Instance
->DebugCapabilityContext
,
168 sizeof (XHC_DC_CONTEXT
)
171 Usb3MapOneDmaBuffer (
173 ((XHC_DC_CONTEXT
*) (UINTN
) Instance
->DebugCapabilityContext
)->DbcInfoContext
.String0DescAddress
,
174 STRING0_DESC_LEN
+ MANU_DESC_LEN
+ PRODUCT_DESC_LEN
+ SERIAL_DESC_LEN
179 Invoke a notification event
181 @param[in] Event Event whose notification function is being invoked.
182 @param[in] Context The pointer to the notification function's context,
183 which is implementation-dependent.
188 Usb3DxeSmmReadyToLockNotify (
193 USB3_DEBUG_PORT_HANDLE
*Instance
;
195 DEBUG ((DEBUG_INFO
, "%a()\n", __FUNCTION__
));
197 Instance
= GetUsb3DebugPortInstance ();
198 ASSERT (Instance
!= NULL
);
200 Instance
->InNotify
= TRUE
;
203 // For the case that the USB3 debug port instance and DMA buffers are
204 // from PEI HOB with IOMMU enabled.
205 // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
206 // by SMM environment.
208 InitializeUsbDebugHardware (Instance
);
211 // Wait some time for host to be ready after re-initialization.
213 MicroSecondDelay (1000000);
215 Instance
->InNotify
= FALSE
;
216 gBS
->CloseEvent (Event
);
220 USB3 get IOMMU protocol.
222 @return Pointer to IOMMU protocol.
225 EDKII_IOMMU_PROTOCOL
*
231 EDKII_IOMMU_PROTOCOL
*IoMmu
;
234 Status
= gBS
->LocateProtocol (
235 &gEdkiiIoMmuProtocolGuid
,
239 if (!EFI_ERROR (Status
) && (IoMmu
!= NULL
)) {
247 Invoke a notification event
249 @param[in] Event Event whose notification function is being invoked.
250 @param[in] Context The pointer to the notification function's context,
251 which is implementation-dependent.
262 UINTN PciIoHandleCount
;
263 EFI_HANDLE
*PciIoHandleBuffer
;
265 EFI_PCI_IO_PROTOCOL
*PciIo
;
268 UINTN PciDeviceNumber
;
269 UINTN PciFunctionNumber
;
271 USB3_DEBUG_PORT_HANDLE
*Instance
;
272 EFI_EVENT SmmReadyToLockEvent
;
274 Status
= gBS
->LocateHandleBuffer (
276 &gEfiPciIoProtocolGuid
,
281 if (!EFI_ERROR (Status
) &&
282 (PciIoHandleBuffer
!= NULL
) &&
283 (PciIoHandleCount
!= 0)) {
284 for (Index
= 0; Index
< PciIoHandleCount
; Index
++) {
285 Status
= gBS
->HandleProtocol (
286 PciIoHandleBuffer
[Index
],
287 &gEfiPciIoProtocolGuid
,
290 ASSERT_EFI_ERROR (Status
);
291 Status
= PciIo
->GetLocation (PciIo
, &PciSegment
, &PciBusNumber
, &PciDeviceNumber
, &PciFunctionNumber
);
292 ASSERT_EFI_ERROR (Status
);
293 PciAddress
= (UINT32
) ((PciBusNumber
<< 20) | (PciDeviceNumber
<< 15) | (PciFunctionNumber
<< 12));
294 if (PciAddress
== PcdGet32(PcdUsbXhciPciAddress
)) {
296 // Found the PciIo for USB3 debug port.
298 DEBUG ((DEBUG_INFO
, "%a()\n", __FUNCTION__
));
299 if (Usb3GetIoMmu () != NULL
) {
300 Instance
= GetUsb3DebugPortInstance ();
301 ASSERT (Instance
!= NULL
);
302 if (Instance
->Ready
) {
303 Instance
->InNotify
= TRUE
;
304 Usb3MapDmaBuffers (Instance
, PciIo
);
305 Instance
->InNotify
= FALSE
;
307 if (Instance
->FromHob
) {
309 Usb3NamedEventListen (
310 &gEfiDxeSmmReadyToLockProtocolGuid
,
312 Usb3DxeSmmReadyToLockNotify
,
318 gBS
->CloseEvent (Event
);
323 gBS
->FreePool (PciIoHandleBuffer
);
328 Return USB3 debug instance address pointer.
331 EFI_PHYSICAL_ADDRESS
*
332 GetUsb3DebugPortInstanceAddrPtr (
336 if (mUsb3InstanceAddrPtr
== NULL
) {
338 // Use the local variables temporarily.
340 mUsb3InstanceAddr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) &mUsb3Instance
;
341 mUsb3InstanceAddrPtr
= &mUsb3InstanceAddr
;
343 return mUsb3InstanceAddrPtr
;
347 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
348 OperationBusMasterCommonBuffer64 mapping.
350 @param PciIo Pointer to PciIo for USB3 debug port.
351 @param Pages The number of pages to allocate.
352 @param Address A pointer to store the base system memory address of the
355 @retval EFI_SUCCESS The requested memory pages were allocated.
356 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
357 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
358 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
359 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
363 Usb3AllocateDmaBuffer (
364 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
372 Status
= PciIo
->AllocateBuffer (
375 EfiRuntimeServicesData
,
380 if (!EFI_ERROR (Status
)) {
381 Usb3MapOneDmaBuffer (
383 (EFI_PHYSICAL_ADDRESS
) (UINTN
) *Address
,
384 EFI_PAGES_TO_SIZE (Pages
)
391 Allocate aligned memory for XHC's usage.
393 @param BufferSize The size, in bytes, of the Buffer.
395 @return A pointer to the allocated buffer or NULL if allocation fails.
399 AllocateAlignBuffer (
403 EFI_PHYSICAL_ADDRESS TmpAddr
;
410 if (mUsb3PciIo
!= NULL
) {
411 Usb3AllocateDmaBuffer (
413 EFI_SIZE_TO_PAGES (BufferSize
),
417 TmpAddr
= 0xFFFFFFFF;
418 Status
= gBS
->AllocatePages (
421 EFI_SIZE_TO_PAGES (BufferSize
),
424 if (!EFI_ERROR (Status
)) {
425 Buf
= (VOID
*) (UINTN
) TmpAddr
;
434 The constructor function initialize USB3 debug port.
436 @param ImageHandle The firmware allocated handle for the EFI image.
437 @param SystemTable A pointer to the EFI System Table.
439 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
444 DebugCommunicationUsb3DxeConstructor (
445 IN EFI_HANDLE ImageHandle
,
446 IN EFI_SYSTEM_TABLE
*SystemTable
449 EFI_PHYSICAL_ADDRESS
*AddrPtr
;
450 USB3_DEBUG_PORT_HANDLE
*Instance
;
451 EFI_PHYSICAL_ADDRESS Address
;
455 Status
= EfiGetSystemConfigurationTable (&gUsb3DbgGuid
, (VOID
**) &AddrPtr
);
456 if (EFI_ERROR (Status
)) {
458 // Instead of using local variables, install system configuration table for
459 // the local instance and the buffer to save instance address pointer.
462 Status
= gBS
->AllocatePages (
465 EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS
) + sizeof (USB3_DEBUG_PORT_HANDLE
)),
468 if (EFI_ERROR (Status
)) {
472 AddrPtr
= (EFI_PHYSICAL_ADDRESS
*) (UINTN
) Address
;
473 ZeroMem (AddrPtr
, sizeof (EFI_PHYSICAL_ADDRESS
) + sizeof (USB3_DEBUG_PORT_HANDLE
));
474 Instance
= (USB3_DEBUG_PORT_HANDLE
*) (AddrPtr
+ 1);
475 CopyMem (Instance
, &mUsb3Instance
, sizeof (USB3_DEBUG_PORT_HANDLE
));
476 *AddrPtr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Instance
;
478 Status
= gBS
->InstallConfigurationTable (&gUsb3DbgGuid
, AddrPtr
);
479 if (EFI_ERROR (Status
)) {
484 if (mUsb3InstanceAddrPtr
!= NULL
) {
485 *AddrPtr
= *mUsb3InstanceAddrPtr
;
487 mUsb3InstanceAddrPtr
= AddrPtr
;
489 Instance
= GetUsb3DebugPortInstance ();
490 ASSERT (Instance
!= NULL
);
492 if (Instance
->PciIoEvent
== 0) {
493 Status
= Usb3NamedEventListen (
494 &gEfiPciIoProtocolGuid
,
499 if (!EFI_ERROR (Status
)) {
500 Instance
->PciIoEvent
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Event
;
508 The destructor function.
510 @param ImageHandle The firmware allocated handle for the EFI image.
511 @param SystemTable A pointer to the EFI System Table.
513 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
518 DebugCommunicationUsb3DxeDestructor (
519 IN EFI_HANDLE ImageHandle
,
520 IN EFI_SYSTEM_TABLE
*SystemTable
523 USB3_DEBUG_PORT_HANDLE
*Instance
;
525 Instance
= GetUsb3DebugPortInstance ();
526 ASSERT (Instance
!= NULL
);
528 if (Instance
->PciIoEvent
!= 0) {
530 // Close the event created.
532 gBS
->CloseEvent ((EFI_EVENT
) (UINTN
) Instance
->PciIoEvent
);
533 Instance
->PciIoEvent
= 0;