+GUID gUsb3DbgGuid = USB3_DBG_GUID;\r
+\r
+USB3_DEBUG_PORT_HANDLE mUsb3Instance = {USB3DBG_UNINITIALIZED};\r
+EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;\r
+EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;\r
+EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;\r
+\r
+/**\r
+ Creates a named event that can be signaled.\r
+\r
+ This function creates an event using NotifyTpl, NoifyFunction.\r
+ If Name is NULL, then ASSERT().\r
+ If NotifyTpl is not a legal TPL value, then ASSERT().\r
+ If NotifyFunction is NULL, then ASSERT().\r
+\r
+ @param Name Supplies the GUID name of the event.\r
+ @param NotifyTpl Supplies the task priority level of the event notifications.\r
+ @param NotifyFunction Supplies the function to notify when the event is signaled.\r
+ @param Event A pointer to the event created.\r
+\r
+ @retval EFI_SUCCESS A named event was created.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Usb3NamedEventListen (\r
+ IN CONST EFI_GUID *Name,\r
+ IN EFI_TPL NotifyTpl,\r
+ IN EFI_EVENT_NOTIFY NotifyFunction,\r
+ IN EFI_EVENT *Event\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *RegistrationLocal;\r
+\r
+ ASSERT (Name != NULL);\r
+ ASSERT (NotifyFunction != NULL);\r
+ ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);\r
+\r
+ //\r
+ // Create event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ NotifyTpl,\r
+ NotifyFunction,\r
+ NULL,\r
+ Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Register for an installation of protocol interface\r
+ //\r
+ Status = gBS->RegisterProtocolNotify (\r
+ (EFI_GUID *) Name,\r
+ *Event,\r
+ &RegistrationLocal\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ USB3 map one DMA buffer.\r
+\r
+ @param PciIo Pointer to PciIo for USB3 debug port.\r
+ @param Address DMA buffer address to be mapped.\r
+ @param NumberOfBytes Number of bytes to be mapped.\r
+\r
+**/\r
+VOID\r
+Usb3MapOneDmaBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_PHYSICAL_ADDRESS Address,\r
+ IN UINTN NumberOfBytes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *HostAddress;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+ VOID *Mapping;\r
+\r
+ HostAddress = (VOID *) (UINTN) Address;\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ HostAddress,\r
+ &NumberOfBytes,\r
+ &DeviceAddress,\r
+ &Mapping\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));\r
+}\r
+\r
+/**\r
+ USB3 map DMA buffers.\r
+\r
+ @param Instance Pointer to USB3 debug port instance.\r
+ @param PciIo Pointer to PciIo for USB3 debug port.\r
+\r
+**/\r
+VOID\r
+Usb3MapDmaBuffers (\r
+ IN USB3_DEBUG_PORT_HANDLE *Instance,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ Instance->UrbIn.Data,\r
+ XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE\r
+ );\r
+\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ Instance->TransferRingIn.RingSeg0,\r
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+ );\r
+\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ Instance->TransferRingOut.RingSeg0,\r
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+ );\r
+\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ Instance->EventRing.EventRingSeg0,\r
+ sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER\r
+ );\r
+\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ Instance->EventRing.ERSTBase,\r
+ sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER\r
+ );\r
+\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ Instance->DebugCapabilityContext,\r
+ sizeof (XHC_DC_CONTEXT)\r
+ );\r
+\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,\r
+ STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN\r
+ );\r
+}\r
+\r
+/**\r
+ Invoke a notification event\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Usb3DxeSmmReadyToLockNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ USB3_DEBUG_PORT_HANDLE *Instance;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ Instance = GetUsb3DebugPortInstance ();\r
+ ASSERT (Instance != NULL);\r
+\r
+ Instance->InNotify = TRUE;\r
+\r
+ //\r
+ // For the case that the USB3 debug port instance and DMA buffers are\r
+ // from PEI HOB with IOMMU enabled.\r
+ // Reinitialize USB3 debug port with granted DXE DMA buffer accessible\r
+ // by SMM environment.\r
+ //\r
+ InitializeUsbDebugHardware (Instance);\r
+\r
+ //\r
+ // Wait some time for host to be ready after re-initialization.\r
+ //\r
+ MicroSecondDelay (1000000);\r
+\r
+ Instance->InNotify = FALSE;\r
+ gBS->CloseEvent (Event);\r
+}\r
+\r
+/**\r
+ USB3 get IOMMU protocol.\r
+\r
+ @return Pointer to IOMMU protocol.\r
+\r
+**/\r
+EDKII_IOMMU_PROTOCOL *\r
+Usb3GetIoMmu (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_IOMMU_PROTOCOL *IoMmu;\r
+\r
+ IoMmu = NULL;\r
+ Status = gBS->LocateProtocol (\r
+ &gEdkiiIoMmuProtocolGuid,\r
+ NULL,\r
+ (VOID **) &IoMmu\r
+ );\r
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {\r
+ return IoMmu;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Invoke a notification event\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Usb3PciIoNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN PciIoHandleCount;\r
+ EFI_HANDLE *PciIoHandleBuffer;\r
+ UINTN Index;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINTN PciSegment;\r
+ UINTN PciBusNumber;\r
+ UINTN PciDeviceNumber;\r
+ UINTN PciFunctionNumber;\r
+ UINT32 PciAddress;\r
+ USB3_DEBUG_PORT_HANDLE *Instance;\r
+ EFI_EVENT SmmReadyToLockEvent;\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiPciIoProtocolGuid,\r
+ NULL,\r
+ &PciIoHandleCount,\r
+ &PciIoHandleBuffer\r
+ );\r
+ if (!EFI_ERROR (Status) &&\r
+ (PciIoHandleBuffer != NULL) &&\r
+ (PciIoHandleCount != 0)) { \r
+ for (Index = 0; Index < PciIoHandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ PciIoHandleBuffer[Index],\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);\r
+ ASSERT_EFI_ERROR (Status);\r
+ PciAddress = (UINT32) ((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));\r
+ if (PciAddress == PcdGet32(PcdUsbXhciPciAddress)) {\r
+ //\r
+ // Found the PciIo for USB3 debug port.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+ if (Usb3GetIoMmu () != NULL) {\r
+ Instance = GetUsb3DebugPortInstance ();\r
+ ASSERT (Instance != NULL);\r
+ if (Instance->Ready) {\r
+ Instance->InNotify = TRUE;\r
+ Usb3MapDmaBuffers (Instance, PciIo);\r
+ Instance->InNotify = FALSE;\r
+\r
+ if (Instance->FromHob) {\r
+ mUsb3PciIo = PciIo;\r
+ Usb3NamedEventListen (\r
+ &gEfiDxeSmmReadyToLockProtocolGuid,\r
+ TPL_NOTIFY,\r
+ Usb3DxeSmmReadyToLockNotify,\r
+ &SmmReadyToLockEvent\r
+ );\r
+ }\r
+ }\r
+ }\r
+ gBS->CloseEvent (Event);\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (PciIoHandleBuffer);\r
+ }\r
+}\r
+\r
+/**\r
+ Return USB3 debug instance address pointer.\r
+\r
+**/ \r
+EFI_PHYSICAL_ADDRESS *\r
+GetUsb3DebugPortInstanceAddrPtr (\r
+ VOID\r
+ )\r
+{\r
+ if (mUsb3InstanceAddrPtr == NULL) {\r
+ //\r
+ // Use the local variables temporarily.\r
+ //\r
+ mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) &mUsb3Instance;\r
+ mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;\r
+ }\r
+ return mUsb3InstanceAddrPtr;\r
+}\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param PciIo Pointer to PciIo for USB3 debug port.\r
+ @param Pages The number of pages to allocate.\r
+ @param Address A pointer to store the base system memory address of the\r
+ allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+Usb3AllocateDmaBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINTN Pages,\r
+ OUT VOID **Address\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ *Address = NULL;\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiRuntimeServicesData,\r
+ Pages,\r
+ Address,\r
+ 0\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Usb3MapOneDmaBuffer (\r
+ PciIo,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,\r
+ EFI_PAGES_TO_SIZE (Pages)\r
+ );\r
+ }\r
+ return Status;\r
+}\r
+\r