MdeModulePkg/XhciPei: Support IoMmu.
Update XHCI driver to consume IOMMU_PPI to allocate DMA buffer. If no IOMMU_PPI exists, this driver still calls PEI service to allocate DMA buffer, with assumption that DRAM==DMA. This is a compatible change. Cc: Star Zeng <star.zeng@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
This commit is contained in:
		
							
								
								
									
										249
									
								
								MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | ||||
| /** @file | ||||
| The DMA memory help function. | ||||
|  | ||||
| Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> | ||||
|  | ||||
| This program and the accompanying materials | ||||
| are licensed and made available under the terms and conditions | ||||
| of the BSD License which accompanies this distribution.  The | ||||
| full text of the license may be found at | ||||
| http://opensource.org/licenses/bsd-license.php | ||||
|  | ||||
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | ||||
|  | ||||
| **/ | ||||
|  | ||||
| #include "XhcPeim.h" | ||||
|  | ||||
| EDKII_IOMMU_PPI  *mIoMmu; | ||||
|  | ||||
| /** | ||||
|   Provides the controller-specific addresses required to access system memory from a | ||||
|   DMA bus master. | ||||
|  | ||||
|   @param  Operation             Indicates if the bus master is going to read or write to system memory. | ||||
|   @param  HostAddress           The system memory address to map to the PCI controller. | ||||
|   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes | ||||
|                                 that were mapped. | ||||
|   @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 range was mapped for the returned NumberOfBytes. | ||||
|   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer. | ||||
|   @retval EFI_INVALID_PARAMETER One or more parameters are invalid. | ||||
|   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources. | ||||
|   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address. | ||||
|  | ||||
| **/ | ||||
| EFI_STATUS | ||||
| IoMmuMap ( | ||||
|   IN  EDKII_IOMMU_OPERATION Operation, | ||||
|   IN VOID                   *HostAddress, | ||||
|   IN  OUT UINTN             *NumberOfBytes, | ||||
|   OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress, | ||||
|   OUT VOID                  **Mapping | ||||
|   ) | ||||
| { | ||||
|   EFI_STATUS  Status; | ||||
|   UINT64      Attribute; | ||||
|  | ||||
|   if (mIoMmu != NULL) { | ||||
|     Status = mIoMmu->Map ( | ||||
|                        mIoMmu, | ||||
|                        Operation, | ||||
|                        HostAddress, | ||||
|                        NumberOfBytes, | ||||
|                        DeviceAddress, | ||||
|                        Mapping | ||||
|                        ); | ||||
|     if (EFI_ERROR (Status)) { | ||||
|       return EFI_OUT_OF_RESOURCES; | ||||
|     } | ||||
|     switch (Operation) { | ||||
|     case EdkiiIoMmuOperationBusMasterRead: | ||||
|     case EdkiiIoMmuOperationBusMasterRead64: | ||||
|       Attribute = EDKII_IOMMU_ACCESS_READ; | ||||
|       break; | ||||
|     case EdkiiIoMmuOperationBusMasterWrite: | ||||
|     case EdkiiIoMmuOperationBusMasterWrite64: | ||||
|       Attribute = EDKII_IOMMU_ACCESS_WRITE; | ||||
|       break; | ||||
|     case EdkiiIoMmuOperationBusMasterCommonBuffer: | ||||
|     case EdkiiIoMmuOperationBusMasterCommonBuffer64: | ||||
|       Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE; | ||||
|       break; | ||||
|     default: | ||||
|       ASSERT(FALSE); | ||||
|       return EFI_INVALID_PARAMETER; | ||||
|     } | ||||
|     Status = mIoMmu->SetAttribute ( | ||||
|                        mIoMmu, | ||||
|                        *Mapping, | ||||
|                        Attribute | ||||
|                        ); | ||||
|     if (EFI_ERROR (Status)) { | ||||
|       return Status; | ||||
|     } | ||||
|   } else { | ||||
|     *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; | ||||
|     *Mapping = NULL; | ||||
|     Status = EFI_SUCCESS; | ||||
|   } | ||||
|   return Status; | ||||
| } | ||||
|  | ||||
| /** | ||||
|   Completes the Map() operation and releases any corresponding resources. | ||||
|  | ||||
|   @param  Mapping               The mapping value returned from Map(). | ||||
|  | ||||
|   @retval EFI_SUCCESS           The range was unmapped. | ||||
|   @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). | ||||
|   @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory. | ||||
| **/ | ||||
| EFI_STATUS | ||||
| IoMmuUnmap ( | ||||
|   IN VOID                  *Mapping | ||||
|   ) | ||||
| { | ||||
|   EFI_STATUS  Status; | ||||
|  | ||||
|   if (mIoMmu != NULL) { | ||||
|     Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0); | ||||
|     Status = mIoMmu->Unmap (mIoMmu, Mapping); | ||||
|   } else { | ||||
|     Status = EFI_SUCCESS; | ||||
|   } | ||||
|   return Status; | ||||
| } | ||||
|  | ||||
| /** | ||||
|   Allocates pages that are suitable for an OperationBusMasterCommonBuffer or | ||||
|   OperationBusMasterCommonBuffer64 mapping. | ||||
|  | ||||
|   @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 UINTN                  Pages, | ||||
|   OUT VOID                  **HostAddress, | ||||
|   OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress, | ||||
|   OUT VOID                  **Mapping | ||||
|   ) | ||||
| { | ||||
|   EFI_STATUS            Status; | ||||
|   UINTN                 NumberOfBytes; | ||||
|   EFI_PHYSICAL_ADDRESS  HostPhyAddress; | ||||
|  | ||||
|   *HostAddress = NULL; | ||||
|   *DeviceAddress = 0; | ||||
|  | ||||
|   if (mIoMmu != NULL) { | ||||
|     Status = mIoMmu->AllocateBuffer ( | ||||
|                        mIoMmu, | ||||
|                        EfiBootServicesData, | ||||
|                        Pages, | ||||
|                        HostAddress, | ||||
|                        0 | ||||
|                        ); | ||||
|     if (EFI_ERROR (Status)) { | ||||
|       return EFI_OUT_OF_RESOURCES; | ||||
|     } | ||||
|  | ||||
|     NumberOfBytes = EFI_PAGES_TO_SIZE(Pages); | ||||
|     Status = mIoMmu->Map ( | ||||
|                        mIoMmu, | ||||
|                        EdkiiIoMmuOperationBusMasterCommonBuffer, | ||||
|                        *HostAddress, | ||||
|                        &NumberOfBytes, | ||||
|                        DeviceAddress, | ||||
|                        Mapping | ||||
|                        ); | ||||
|     if (EFI_ERROR (Status)) { | ||||
|       return EFI_OUT_OF_RESOURCES; | ||||
|     } | ||||
|     Status = mIoMmu->SetAttribute ( | ||||
|                        mIoMmu, | ||||
|                        *Mapping, | ||||
|                        EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE | ||||
|                        ); | ||||
|     if (EFI_ERROR (Status)) { | ||||
|       return Status; | ||||
|     } | ||||
|   } else { | ||||
|     Status = PeiServicesAllocatePages ( | ||||
|                EfiBootServicesData, | ||||
|                Pages, | ||||
|                &HostPhyAddress | ||||
|                ); | ||||
|     if (EFI_ERROR (Status)) { | ||||
|       return EFI_OUT_OF_RESOURCES; | ||||
|     } | ||||
|     *HostAddress = (VOID *)(UINTN)HostPhyAddress; | ||||
|     *DeviceAddress = HostPhyAddress; | ||||
|     *Mapping = NULL; | ||||
|   } | ||||
|   return Status; | ||||
| } | ||||
|  | ||||
| /** | ||||
|   Frees memory that was allocated with AllocateBuffer(). | ||||
|  | ||||
|   @param  Pages                 The number of pages to free. | ||||
|   @param  HostAddress           The base system memory address of the allocated range. | ||||
|   @param  Mapping               The mapping value returned from Map(). | ||||
|  | ||||
|   @retval EFI_SUCCESS           The requested memory pages were freed. | ||||
|   @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages | ||||
|                                 was not allocated with AllocateBuffer(). | ||||
|  | ||||
| **/ | ||||
| EFI_STATUS | ||||
| IoMmuFreeBuffer ( | ||||
|   IN UINTN                  Pages, | ||||
|   IN VOID                   *HostAddress, | ||||
|   IN VOID                   *Mapping | ||||
|   ) | ||||
| { | ||||
|   EFI_STATUS  Status; | ||||
|  | ||||
|   if (mIoMmu != NULL) { | ||||
|     Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0); | ||||
|     Status = mIoMmu->Unmap (mIoMmu, Mapping); | ||||
|     Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress); | ||||
|   } else { | ||||
|     Status = EFI_SUCCESS; | ||||
|   } | ||||
|   return Status; | ||||
| } | ||||
|  | ||||
| /** | ||||
|   Initialize IOMMU. | ||||
| **/ | ||||
| VOID | ||||
| IoMmuInit ( | ||||
|   VOID | ||||
|   ) | ||||
| { | ||||
|   PeiServicesLocatePpi ( | ||||
|     &gEdkiiIoMmuPpiGuid, | ||||
|     0, | ||||
|     NULL, | ||||
|     (VOID **)&mIoMmu | ||||
|     ); | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user