diff options
| author | Mitchel Humpherys <mitchelh@codeaurora.org> | 2015-03-26 11:59:02 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:11:57 -0700 |
| commit | eadb730a2d0bff616d60368778e087ae6e4c3ec3 (patch) | |
| tree | d6f4f7314870b4367e7a950cd216c4b4dad00479 | |
| parent | 0ae59a3564a4ecebcd6dfc64ecba09bced3322cb (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.h | 1 | ||||
| -rw-r--r-- | arch/arm64/mm/dma-mapping.c | 14 |
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) |
