/** @file Debug Port Library implementation based on usb3 debug port. Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include "DebugCommunicationLibUsb3Internal.h" GUID gUsb3DbgGuid = USB3_DBG_GUID; /** USB3 IOMMU PPI notify. @param[in] PeiServices Pointer to PEI Services Table. @param[in] NotifyDesc Pointer to the descriptor for the Notification event that caused this function to execute. @param[in] Ppi Pointer to the PPI data associated with this function. @retval EFI_STATUS Always return EFI_SUCCESS **/ EFI_STATUS EFIAPI Usb3IoMmuPpiNotify ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, IN VOID *Ppi ) { USB3_DEBUG_PORT_HANDLE *Instance; DEBUG ((DEBUG_INFO, "%a()\n", __func__)); Instance = GetUsb3DebugPortInstance (); ASSERT (Instance != NULL); if (!Instance->Ready) { return EFI_SUCCESS; } Instance->InNotify = TRUE; // // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI. // InitializeUsbDebugHardware (Instance); // // Wait some time for host to be ready after re-initialization. // MicroSecondDelay (1000000); Instance->InNotify = FALSE; return EFI_SUCCESS; } EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEdkiiIoMmuPpiGuid, Usb3IoMmuPpiNotify }; /** Allocates pages that are suitable for an OperationBusMasterCommonBuffer or OperationBusMasterCommonBuffer64 mapping. @param IoMmu Pointer to IOMMU PPI. @param Pages The number of pages to allocate. @param HostAddress A pointer to store the base system memory address of the allocated range. @param DeviceAddress The resulting map address for the bus master PCI controller to use to access the hosts HostAddress. @param Mapping A resulting value to pass to Unmap(). @retval EFI_SUCCESS The requested memory pages were allocated. @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are MEMORY_WRITE_COMBINE and MEMORY_CACHED. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. **/ EFI_STATUS IoMmuAllocateBuffer ( IN EDKII_IOMMU_PPI *IoMmu, IN UINTN Pages, OUT VOID **HostAddress, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping ) { EFI_STATUS Status; UINTN NumberOfBytes; *HostAddress = NULL; *DeviceAddress = 0; *Mapping = NULL; Status = IoMmu->AllocateBuffer ( IoMmu, EfiRuntimeServicesData, Pages, HostAddress, 0 ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } NumberOfBytes = EFI_PAGES_TO_SIZE (Pages); Status = IoMmu->Map ( IoMmu, EdkiiIoMmuOperationBusMasterCommonBuffer, *HostAddress, &NumberOfBytes, DeviceAddress, Mapping ); if (EFI_ERROR (Status)) { IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); *HostAddress = NULL; return EFI_OUT_OF_RESOURCES; } Status = IoMmu->SetAttribute ( IoMmu, *Mapping, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE ); if (EFI_ERROR (Status)) { IoMmu->Unmap (IoMmu, *Mapping); IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); *Mapping = NULL; *HostAddress = NULL; return Status; } return Status; } /** USB3 get IOMMU PPI. @return Pointer to IOMMU PPI. **/ EDKII_IOMMU_PPI * Usb3GetIoMmu ( VOID ) { EFI_STATUS Status; EDKII_IOMMU_PPI *IoMmu; IoMmu = NULL; Status = PeiServicesLocatePpi ( &gEdkiiIoMmuPpiGuid, 0, NULL, (VOID **)&IoMmu ); if (!EFI_ERROR (Status) && (IoMmu != NULL)) { return IoMmu; } return NULL; } /** Return USB3 debug instance address pointer. **/ EFI_PHYSICAL_ADDRESS * GetUsb3DebugPortInstanceAddrPtr ( VOID ) { USB3_DEBUG_PORT_HANDLE *Instance; EFI_PHYSICAL_ADDRESS *AddrPtr; EFI_PEI_HOB_POINTERS Hob; EFI_STATUS Status; Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid); if (Hob.Raw == NULL) { // // Build HOB for the local instance and the buffer to save instance address pointer. // Use the local instance in HOB temporarily. // AddrPtr = BuildGuidHob ( &gUsb3DbgGuid, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE) ); ASSERT (AddrPtr != NULL); ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)); Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1); *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance; Instance->FromHob = TRUE; Instance->Initialized = USB3DBG_UNINITIALIZED; if (Usb3GetIoMmu () == NULL) { Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc); ASSERT_EFI_ERROR (Status); } } else { AddrPtr = GET_GUID_HOB_DATA (Hob.Guid); } return AddrPtr; } /** Allocate aligned memory for XHC's usage. @param BufferSize The size, in bytes, of the Buffer. @return A pointer to the allocated buffer or NULL if allocation fails. **/ VOID * AllocateAlignBuffer ( IN UINTN BufferSize ) { VOID *Buf; EFI_PHYSICAL_ADDRESS Address; EFI_STATUS Status; VOID *MemoryDiscoveredPpi; EDKII_IOMMU_PPI *IoMmu; VOID *HostAddress; VOID *Mapping; Buf = NULL; // // Make sure the allocated memory is physical memory. // Status = PeiServicesLocatePpi ( &gEfiPeiMemoryDiscoveredPpiGuid, 0, NULL, (VOID **)&MemoryDiscoveredPpi ); if (!EFI_ERROR (Status)) { IoMmu = Usb3GetIoMmu (); if (IoMmu != NULL) { Status = IoMmuAllocateBuffer ( IoMmu, EFI_SIZE_TO_PAGES (BufferSize), &HostAddress, &Address, &Mapping ); if (!EFI_ERROR (Status)) { ASSERT (Address == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress)); Buf = (VOID *)(UINTN)Address; } } else { Status = PeiServicesAllocatePages ( EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (BufferSize), &Address ); if (!EFI_ERROR (Status)) { Buf = (VOID *)(UINTN)Address; } } } return Buf; }