\r
**/\r
\r
-#include <Base.h>\r
+#include <PiDxe.h>\r
#include <Library/DebugLib.h>\r
#include <Library/DmaLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/UncachedMemoryAllocationLib.h>\r
EFI_CPU_ARCH_PROTOCOL *gCpu;\r
UINTN gCacheAlignment = 0;\r
\r
-\r
-\r
-\r
/** \r
Provides the DMA controller-specific addresses needed to access system memory.\r
\r
OUT VOID **Mapping\r
)\r
{\r
- EFI_STATUS Status;\r
- MAP_INFO_INSTANCE *Map;\r
- VOID *Buffer;\r
+ EFI_STATUS Status;\r
+ MAP_INFO_INSTANCE *Map;\r
+ VOID *Buffer;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
\r
- if ( HostAddress == NULL || NumberOfBytes == NULL || \r
- DeviceAddress == NULL || Mapping == NULL ) {\r
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL ) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
\r
if (Operation >= MapOperationMaximum) {\r
return EFI_INVALID_PARAMETER;\r
\r
*Mapping = Map;\r
\r
- if (((UINTN)HostAddress & (gCacheAlignment - 1)) != 0) {\r
- Map->DoubleBuffer = TRUE;\r
- Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer);\r
- if (EFI_ERROR (Status)) {\r
+ if ((((UINTN)HostAddress & (gCacheAlignment - 1)) != 0) ||\r
+ ((*NumberOfBytes % gCacheAlignment) != 0)) {\r
+\r
+ // Get the cacheability of the region\r
+ Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor);\r
+ if (EFI_ERROR(Status)) {\r
return Status;\r
}\r
- \r
- *DeviceAddress = (PHYSICAL_ADDRESS)(UINTN)Buffer;\r
- \r
+\r
+ // If the mapped buffer is not an uncached buffer\r
+ if (GcdDescriptor.Attributes != EFI_MEMORY_UC) {\r
+ //\r
+ // If the buffer does not fill entire cache lines we must double buffer into\r
+ // uncached memory. Device (PCI) address becomes uncached page.\r
+ //\r
+ Map->DoubleBuffer = TRUE;\r
+ Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Operation == MapOperationBusMasterRead) || (Operation == MapOperationBusMasterCommonBuffer)) {\r
+ CopyMem (Buffer, HostAddress, *NumberOfBytes);\r
+ }\r
+\r
+ *DeviceAddress = (PHYSICAL_ADDRESS)(UINTN)Buffer;\r
+ } else {\r
+ Map->DoubleBuffer = FALSE;\r
+ }\r
} else {\r
Map->DoubleBuffer = FALSE;\r
+\r
+ // Flush the Data Cache (should not have any effect if the memory region is uncached)\r
+ gCpu->FlushDataCache (gCpu, *DeviceAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);\r
+\r
+ if ((Operation == MapOperationBusMasterRead) || (Operation == MapOperationBusMasterCommonBuffer)) {\r
+ // In case the buffer is used for instance to send command to a PCI controller, we must ensure the memory is uncached\r
+ Status = gDS->SetMemorySpaceAttributes (ALIGN_VALUE(*DeviceAddress - BASE_4KB - 1,BASE_4KB), ALIGN_VALUE(*NumberOfBytes,BASE_4KB), EFI_MEMORY_UC);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
}\r
\r
- *NumberOfBytes &= *NumberOfBytes & ~(gCacheAlignment - 1); // Only do it on full cache lines\r
- \r
Map->HostAddress = (UINTN)HostAddress;\r
Map->DeviceAddress = *DeviceAddress;\r
Map->NumberOfBytes = *NumberOfBytes;\r
Map->Operation = Operation;\r
\r
- if (Map->DoubleBuffer) {\r
- if (Map->Operation == MapOperationBusMasterWrite) {\r
- CopyMem ((VOID *)(UINTN)Map->DeviceAddress, (VOID *)(UINTN)Map->HostAddress, Map->NumberOfBytes);\r
- }\r
- } else {\r
- // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate\r
- if (Map->Operation == MapOperationBusMasterWrite || Map->Operation == MapOperationBusMasterRead) {\r
- gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);\r
- }\r
- }\r
- \r
return EFI_SUCCESS;\r
}\r
\r
Map = (MAP_INFO_INSTANCE *)Mapping;\r
\r
if (Map->DoubleBuffer) {\r
- if (Map->Operation == MapOperationBusMasterRead) {\r
+ if ((Map->Operation == MapOperationBusMasterWrite) || (Map->Operation == MapOperationBusMasterCommonBuffer)) {\r
CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes);\r
}\r
\r
//\r
if (MemoryType == EfiBootServicesData) {\r
*HostAddress = UncachedAllocatePages (Pages);\r
- } else if (MemoryType != EfiRuntimeServicesData) {\r
+ } else if (MemoryType == EfiRuntimeServicesData) {\r
*HostAddress = UncachedAllocateRuntimePages (Pages);\r
} else {\r
return EFI_INVALID_PARAMETER;\r