iommu: dma-mapping-fast: Respect device coherency in IOMMU mapper

Coherent devices can make use of the CPU cache, so they should get
coherent IOMMU mappings and should have their cache maintenance
operations skipped.  Implement this for the "fast" arm64 IOMMU mapper.

Change-Id: I30db64cae2cc4cda0baa3cdd3860dc079f22bf71
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
This commit is contained in:
Mitchel Humpherys 2016-06-23 13:25:12 -07:00 committed by Gerrit - the friendly Code Review server
parent 5f701acda4
commit 486496dc03

View file

@ -25,6 +25,29 @@
#define FAST_PAGE_MASK (~(PAGE_SIZE - 1))
#define FAST_PTE_ADDR_MASK ((av8l_fast_iopte)0xfffffffff000)
static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
bool coherent)
{
if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
return pgprot_noncached(prot);
else if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
return pgprot_writecombine(prot);
return prot;
}
static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
bool coherent)
{
if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
prot |= IOMMU_NOEXEC;
if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
prot |= IOMMU_DEVICE;
if (coherent)
prot |= IOMMU_CACHE;
return prot;
}
static void fast_dmac_clean_range(struct dma_fast_smmu_mapping *mapping,
void *start, void *end)
{
@ -289,11 +312,11 @@ static dma_addr_t fast_smmu_map_page(struct device *dev, struct page *page,
int nptes = len >> FAST_PAGE_SHIFT;
bool skip_sync = dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
int prot = __fast_dma_direction_to_prot(dir);
bool is_coherent = is_device_dma_coherent(dev);
if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
prot |= IOMMU_DEVICE;
prot = __get_iommu_pgprot(attrs, prot, is_coherent);
if (!skip_sync)
if (!skip_sync && !is_coherent)
__fast_dma_page_cpu_to_dev(phys_to_page(phys_to_map),
offset_from_phys_to_map, size, dir);
@ -333,8 +356,9 @@ static void fast_smmu_unmap_page(struct device *dev, dma_addr_t iova,
int nptes = len >> FAST_PAGE_SHIFT;
struct page *page = phys_to_page((*pmd & FAST_PTE_ADDR_MASK));
bool skip_sync = dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs);
bool is_coherent = is_device_dma_coherent(dev);
if (!skip_sync)
if (!skip_sync && !is_coherent)
__fast_dma_page_dev_to_cpu(page, offset, size, dir);
spin_lock_irqsave(&mapping->lock, flags);
@ -442,9 +466,12 @@ static void *fast_smmu_alloc(struct device *dev, size_t size,
struct sg_mapping_iter miter;
unsigned int count = ALIGN(size, SZ_4K) >> PAGE_SHIFT;
int prot = IOMMU_READ | IOMMU_WRITE; /* TODO: extract from attrs */
pgprot_t remap_prot = pgprot_writecombine(PAGE_KERNEL);
bool is_coherent = is_device_dma_coherent(dev);
pgprot_t remap_prot = __get_dma_pgprot(attrs, PAGE_KERNEL, is_coherent);
struct page **pages;
prot = __get_iommu_pgprot(attrs, prot, is_coherent);
*handle = DMA_ERROR_CODE;
pages = __fast_smmu_alloc_pages(count, gfp);
@ -459,7 +486,7 @@ static void *fast_smmu_alloc(struct device *dev, size_t size,
goto out_free_pages;
}
if (!(prot & IOMMU_CACHE)) {
if (!is_coherent) {
/*
* The CPU-centric flushing implied by SG_MITER_TO_SG isn't
* sufficient here, so skip it by using the "wrong" direction.
@ -562,9 +589,10 @@ static int fast_smmu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
unsigned long uaddr = vma->vm_start;
struct page **pages;
int i, nr_pages, ret = 0;
bool coherent = is_device_dma_coherent(dev);
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
coherent);
area = find_vm_area(cpu_addr);
if (!area)
return -EINVAL;