summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchel Humpherys <mitchelh@codeaurora.org>2015-03-26 11:59:02 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:11:57 -0700
commiteadb730a2d0bff616d60368778e087ae6e4c3ec3 (patch)
treed6f4f7314870b4367e7a950cd216c4b4dad00479
parent0ae59a3564a4ecebcd6dfc64ecba09bced3322cb (diff)
arm64: dma-mapping: avoid calling iommu_iova_to_phys
We're currently asking the IOMMU layer to do an iova-to-phys translation in .unmap_page and .sync_single_for_* in the IOMMU DMA mapper. This can be a costly operation since it will need to walk the domain's page tables, either in software or in hardware. Also, in some less-than-ideal implementations of iommu_iova_to_phys this might actually involve sleeping operations. Avoid this overhead by saving the physical address of the buffer in the dma_iommu_mapping structure in .map_page, using it later instead of iommu_iova_to_phys. Change-Id: Ic53b91a222dab01cfcdc34246a847a8c399adfb6 Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
-rw-r--r--arch/arm64/include/asm/dma-iommu.h1
-rw-r--r--arch/arm64/mm/dma-mapping.c14
2 files changed, 8 insertions, 7 deletions
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
index db51643163f2..1886afb02ff7 100644
--- a/arch/arm64/include/asm/dma-iommu.h
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -17,6 +17,7 @@ struct dma_iommu_mapping {
size_t bits;
unsigned int order;
dma_addr_t base;
+ phys_addr_t phys;
spinlock_t lock;
struct kref kref;
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index e10eb3ab4749..fd5d20234956 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1814,6 +1814,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev,
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
dma_addr_t dma_addr;
int ret, prot, len = PAGE_ALIGN(size + offset);
+ phys_addr_t phys = page_to_phys(page);
dma_addr = __alloc_iova(mapping, len);
if (dma_addr == DMA_ERROR_CODE)
@@ -1821,11 +1822,13 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev,
prot = __dma_direction_to_prot(dir);
- ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len,
+ ret = iommu_map(mapping->domain, dma_addr, phys, len,
prot);
if (ret < 0)
goto fail;
+ mapping->phys = phys;
+
return dma_addr + offset;
fail:
__free_iova(mapping, dma_addr, len);
@@ -1892,8 +1895,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
dma_addr_t iova = handle & PAGE_MASK;
- struct page *page = phys_to_page(iommu_iova_to_phys(
- mapping->domain, iova));
+ struct page *page = phys_to_page(mapping->phys);
int offset = handle & ~PAGE_MASK;
int len = PAGE_ALIGN(size + offset);
@@ -1912,8 +1914,7 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev,
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
dma_addr_t iova = handle & PAGE_MASK;
- struct page *page = phys_to_page(iommu_iova_to_phys(
- mapping->domain, iova));
+ struct page *page = phys_to_page(mapping->phys);
unsigned int offset = handle & ~PAGE_MASK;
if (!iova)
@@ -1927,8 +1928,7 @@ static void arm_iommu_sync_single_for_device(struct device *dev,
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
dma_addr_t iova = handle & PAGE_MASK;
- struct page *page = phys_to_page(iommu_iova_to_phys(
- mapping->domain, iova));
+ struct page *page = phys_to_page(mapping->phys);
unsigned int offset = handle & ~PAGE_MASK;
if (!iova)