Update the SdBlockIoPei 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: Jiewen Yao <jiewen.yao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			250 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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 "SdBlockIoPei.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
 | |
|     );
 | |
| }
 | |
| 
 |