From e6d572ba03ff15d758e885cfd746621fb2386226 Mon Sep 17 00:00:00 2001 From: oliviermartin Date: Mon, 15 Aug 2011 16:55:05 +0000 Subject: ArmPkg/ArmDmaLib: Fix coherency issues in DmaLib Some coherencies issues were existing in the former version of DmaLib. These issues could have for consequences to not make the MdeModulePkg/Bus/Usb software stack not work. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12137 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPkg/Library/ArmDmaLib/ArmDmaLib.c | 74 ++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 32 deletions(-) (limited to 'ArmPkg') diff --git a/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c b/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c index adea97ff29..f8d8a7542b 100755 --- a/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c +++ b/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c @@ -13,9 +13,10 @@ **/ -#include +#include #include #include +#include #include #include #include @@ -38,9 +39,6 @@ typedef struct { EFI_CPU_ARCH_PROTOCOL *gCpu; UINTN gCacheAlignment = 0; - - - /** Provides the DMA controller-specific addresses needed to access system memory. @@ -71,15 +69,14 @@ DmaMap ( OUT VOID **Mapping ) { - EFI_STATUS Status; - MAP_INFO_INSTANCE *Map; - VOID *Buffer; + EFI_STATUS Status; + MAP_INFO_INSTANCE *Map; + VOID *Buffer; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; - if ( HostAddress == NULL || NumberOfBytes == NULL || - DeviceAddress == NULL || Mapping == NULL ) { + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL ) { return EFI_INVALID_PARAMETER; } - if (Operation >= MapOperationMaximum) { return EFI_INVALID_PARAMETER; @@ -97,20 +94,44 @@ DmaMap ( if ((((UINTN)HostAddress & (gCacheAlignment - 1)) != 0) || ((*NumberOfBytes % gCacheAlignment) != 0)) { - // - // If the buffer does not fill entire cache lines we must double buffer into - // uncached memory. Device (PCI) address becomes uncached page. - // - Map->DoubleBuffer = TRUE; - Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer); - if (EFI_ERROR (Status)) { + + // Get the cacheability of the region + Status = gDS->GetMemorySpaceDescriptor (HostAddress, &GcdDescriptor); + if (EFI_ERROR(Status)) { return Status; } - - *DeviceAddress = (PHYSICAL_ADDRESS)(UINTN)Buffer; - + + // If the mapped buffer is not an uncached buffer + if (GcdDescriptor.Attributes != EFI_MEMORY_UC) { + // + // If the buffer does not fill entire cache lines we must double buffer into + // uncached memory. Device (PCI) address becomes uncached page. + // + Map->DoubleBuffer = TRUE; + Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Operation == MapOperationBusMasterRead) || (Operation == MapOperationBusMasterCommonBuffer)) { + CopyMem (Buffer, HostAddress, *NumberOfBytes); + } + + *DeviceAddress = (PHYSICAL_ADDRESS)(UINTN)Buffer; + } else { + Map->DoubleBuffer = FALSE; + } } else { Map->DoubleBuffer = FALSE; + + // Flush the Data Cache (should not have any effect if the memory region is uncached) + gCpu->FlushDataCache (gCpu, *DeviceAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate); + + if ((Operation == MapOperationBusMasterRead) || (Operation == MapOperationBusMasterCommonBuffer)) { + // In case the buffer is used for instance to send command to a PCI controller, we must ensure the memory is uncached + Status = gDS->SetMemorySpaceAttributes (ALIGN_VALUE(*DeviceAddress - BASE_4KB - 1,BASE_4KB), ALIGN_VALUE(*NumberOfBytes,BASE_4KB), EFI_MEMORY_UC); + ASSERT_EFI_ERROR (Status); + } } Map->HostAddress = (UINTN)HostAddress; @@ -118,17 +139,6 @@ DmaMap ( Map->NumberOfBytes = *NumberOfBytes; Map->Operation = Operation; - if (Map->DoubleBuffer) { - if (Map->Operation == MapOperationBusMasterWrite) { - CopyMem ((VOID *)(UINTN)Map->DeviceAddress, (VOID *)(UINTN)Map->HostAddress, Map->NumberOfBytes); - } - } else { - // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate - if (Map->Operation == MapOperationBusMasterWrite || Map->Operation == MapOperationBusMasterRead) { - gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate); - } - } - return EFI_SUCCESS; } @@ -159,7 +169,7 @@ DmaUnmap ( Map = (MAP_INFO_INSTANCE *)Mapping; if (Map->DoubleBuffer) { - if (Map->Operation == MapOperationBusMasterRead) { + if ((Map->Operation == MapOperationBusMasterWrite) || (Map->Operation == MapOperationBusMasterCommonBuffer)) { CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes); } -- cgit v1.2.3