Commit d563bccf authored by Robin Murphy's avatar Robin Murphy Committed by Christoph Hellwig

ARM/dma-mapping: consolidate IOMMU ops callbacks

Merge the coherent and non-coherent callbacks down to a single
implementation each, relying on the generic dev->dma_coherent
flag at the points where the difference matters.
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Tested-by: default avatarMarc Zyngier <maz@kernel.org>
parent 42998ef0
...@@ -1079,13 +1079,13 @@ static void __iommu_free_atomic(struct device *dev, void *cpu_addr, ...@@ -1079,13 +1079,13 @@ static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
__free_from_pool(cpu_addr, size); __free_from_pool(cpu_addr, size);
} }
static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp, unsigned long attrs, dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
int coherent_flag)
{ {
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
struct page **pages; struct page **pages;
void *addr = NULL; void *addr = NULL;
int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL;
*handle = DMA_MAPPING_ERROR; *handle = DMA_MAPPING_ERROR;
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
...@@ -1128,19 +1128,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, ...@@ -1128,19 +1128,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
return NULL; return NULL;
} }
static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
{
return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, NORMAL);
}
static void *arm_coherent_iommu_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
{
return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, COHERENT);
}
static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size, void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs) unsigned long attrs)
{ {
...@@ -1154,35 +1142,24 @@ static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma ...@@ -1154,35 +1142,24 @@ static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma
if (vma->vm_pgoff >= nr_pages) if (vma->vm_pgoff >= nr_pages)
return -ENXIO; return -ENXIO;
if (!dev->dma_coherent)
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
err = vm_map_pages(vma, pages, nr_pages); err = vm_map_pages(vma, pages, nr_pages);
if (err) if (err)
pr_err("Remapping memory failed: %d\n", err); pr_err("Remapping memory failed: %d\n", err);
return err; return err;
} }
static int arm_iommu_mmap_attrs(struct device *dev,
struct vm_area_struct *vma, void *cpu_addr,
dma_addr_t dma_addr, size_t size, unsigned long attrs)
{
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
}
static int arm_coherent_iommu_mmap_attrs(struct device *dev,
struct vm_area_struct *vma, void *cpu_addr,
dma_addr_t dma_addr, size_t size, unsigned long attrs)
{
return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
}
/* /*
* free a page as defined by the above mapping. * free a page as defined by the above mapping.
* Must not be called with IRQs disabled. * Must not be called with IRQs disabled.
*/ */
static void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, static void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, unsigned long attrs, int coherent_flag) dma_addr_t handle, unsigned long attrs)
{ {
int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL;
struct page **pages; struct page **pages;
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
...@@ -1204,19 +1181,6 @@ static void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_ad ...@@ -1204,19 +1181,6 @@ static void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_ad
__iommu_free_buffer(dev, pages, size, attrs); __iommu_free_buffer(dev, pages, size, attrs);
} }
static void arm_iommu_free_attrs(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t handle,
unsigned long attrs)
{
__arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, NORMAL);
}
static void arm_coherent_iommu_free_attrs(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t handle, unsigned long attrs)
{
__arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, COHERENT);
}
static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t dma_addr, void *cpu_addr, dma_addr_t dma_addr,
size_t size, unsigned long attrs) size_t size, unsigned long attrs)
...@@ -1236,8 +1200,7 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, ...@@ -1236,8 +1200,7 @@ static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
*/ */
static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
size_t size, dma_addr_t *handle, size_t size, dma_addr_t *handle,
enum dma_data_direction dir, unsigned long attrs, enum dma_data_direction dir, unsigned long attrs)
bool is_coherent)
{ {
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
dma_addr_t iova, iova_base; dma_addr_t iova, iova_base;
...@@ -1257,7 +1220,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, ...@@ -1257,7 +1220,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
phys_addr_t phys = page_to_phys(sg_page(s)); phys_addr_t phys = page_to_phys(sg_page(s));
unsigned int len = PAGE_ALIGN(s->offset + s->length); unsigned int len = PAGE_ALIGN(s->offset + s->length);
if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
prot = __dma_info_to_prot(dir, attrs); prot = __dma_info_to_prot(dir, attrs);
...@@ -1277,9 +1240,20 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, ...@@ -1277,9 +1240,20 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
return ret; return ret;
} }
static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, /**
enum dma_data_direction dir, unsigned long attrs, * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
bool is_coherent) * @dev: valid struct device pointer
* @sg: list of buffers
* @nents: number of buffers to map
* @dir: DMA transfer direction
*
* Map a set of buffers described by scatterlist in streaming mode for DMA.
* The scatter gather list elements are merged together (if possible) and
* tagged with the appropriate dma address and length. They are obtained via
* sg_dma_{address,length}.
*/
static int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, unsigned long attrs)
{ {
struct scatterlist *s = sg, *dma = sg, *start = sg; struct scatterlist *s = sg, *dma = sg, *start = sg;
int i, count = 0, ret; int i, count = 0, ret;
...@@ -1294,8 +1268,7 @@ static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -1294,8 +1268,7 @@ static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) { if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
ret = __map_sg_chunk(dev, start, size, ret = __map_sg_chunk(dev, start, size,
&dma->dma_address, dir, attrs, &dma->dma_address, dir, attrs);
is_coherent);
if (ret < 0) if (ret < 0)
goto bad_mapping; goto bad_mapping;
...@@ -1309,8 +1282,7 @@ static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -1309,8 +1282,7 @@ static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
} }
size += s->length; size += s->length;
} }
ret = __map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs, ret = __map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs);
is_coherent);
if (ret < 0) if (ret < 0)
goto bad_mapping; goto bad_mapping;
...@@ -1328,44 +1300,19 @@ static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -1328,44 +1300,19 @@ static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
} }
/** /**
* arm_coherent_iommu_map_sg - map a set of SG buffers for streaming mode DMA * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
* @dev: valid struct device pointer
* @sg: list of buffers
* @nents: number of buffers to map
* @dir: DMA transfer direction
*
* Map a set of i/o coherent buffers described by scatterlist in streaming
* mode for DMA. The scatter gather list elements are merged together (if
* possible) and tagged with the appropriate dma address and length. They are
* obtained via sg_dma_{address,length}.
*/
static int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, unsigned long attrs)
{
return __iommu_map_sg(dev, sg, nents, dir, attrs, true);
}
/**
* arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
* @dev: valid struct device pointer * @dev: valid struct device pointer
* @sg: list of buffers * @sg: list of buffers
* @nents: number of buffers to map * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
* @dir: DMA transfer direction * @dir: DMA transfer direction (same as was passed to dma_map_sg)
* *
* Map a set of buffers described by scatterlist in streaming mode for DMA. * Unmap a set of streaming mode DMA translations. Again, CPU access
* The scatter gather list elements are merged together (if possible) and * rules concerning calls here are the same as for dma_unmap_single().
* tagged with the appropriate dma address and length. They are obtained via
* sg_dma_{address,length}.
*/ */
static int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, static void arm_iommu_unmap_sg(struct device *dev,
int nents, enum dma_data_direction dir, unsigned long attrs) struct scatterlist *sg, int nents,
{ enum dma_data_direction dir,
return __iommu_map_sg(dev, sg, nents, dir, attrs, false); unsigned long attrs)
}
static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir,
unsigned long attrs, bool is_coherent)
{ {
struct scatterlist *s; struct scatterlist *s;
int i; int i;
...@@ -1374,47 +1321,12 @@ static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg, ...@@ -1374,47 +1321,12 @@ static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
if (sg_dma_len(s)) if (sg_dma_len(s))
__iommu_remove_mapping(dev, sg_dma_address(s), __iommu_remove_mapping(dev, sg_dma_address(s),
sg_dma_len(s)); sg_dma_len(s));
if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
__dma_page_dev_to_cpu(sg_page(s), s->offset, __dma_page_dev_to_cpu(sg_page(s), s->offset,
s->length, dir); s->length, dir);
} }
} }
/**
* arm_coherent_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
* @dev: valid struct device pointer
* @sg: list of buffers
* @nents: number of buffers to unmap (same as was passed to dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*
* Unmap a set of streaming mode DMA translations. Again, CPU access
* rules concerning calls here are the same as for dma_unmap_single().
*/
static void arm_coherent_iommu_unmap_sg(struct device *dev,
struct scatterlist *sg, int nents, enum dma_data_direction dir,
unsigned long attrs)
{
__iommu_unmap_sg(dev, sg, nents, dir, attrs, true);
}
/**
* arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
* @dev: valid struct device pointer
* @sg: list of buffers
* @nents: number of buffers to unmap (same as was passed to dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*
* Unmap a set of streaming mode DMA translations. Again, CPU access
* rules concerning calls here are the same as for dma_unmap_single().
*/
static void arm_iommu_unmap_sg(struct device *dev,
struct scatterlist *sg, int nents,
enum dma_data_direction dir,
unsigned long attrs)
{
__iommu_unmap_sg(dev, sg, nents, dir, attrs, false);
}
/** /**
* arm_iommu_sync_sg_for_cpu * arm_iommu_sync_sg_for_cpu
* @dev: valid struct device pointer * @dev: valid struct device pointer
...@@ -1452,18 +1364,17 @@ static void arm_iommu_sync_sg_for_device(struct device *dev, ...@@ -1452,18 +1364,17 @@ static void arm_iommu_sync_sg_for_device(struct device *dev,
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
} }
/** /**
* arm_coherent_iommu_map_page * arm_iommu_map_page
* @dev: valid struct device pointer * @dev: valid struct device pointer
* @page: page that buffer resides in * @page: page that buffer resides in
* @offset: offset into page for start of buffer * @offset: offset into page for start of buffer
* @size: size of buffer to map * @size: size of buffer to map
* @dir: DMA transfer direction * @dir: DMA transfer direction
* *
* Coherent IOMMU aware version of arm_dma_map_page() * IOMMU aware version of arm_dma_map_page()
*/ */
static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *page, static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction dir, unsigned long offset, size_t size, enum dma_data_direction dir,
unsigned long attrs) unsigned long attrs)
{ {
...@@ -1471,6 +1382,9 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p ...@@ -1471,6 +1382,9 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
dma_addr_t dma_addr; dma_addr_t dma_addr;
int ret, prot, len = PAGE_ALIGN(size + offset); int ret, prot, len = PAGE_ALIGN(size + offset);
if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
__dma_page_cpu_to_dev(page, offset, size, dir);
dma_addr = __alloc_iova(mapping, len); dma_addr = __alloc_iova(mapping, len);
if (dma_addr == DMA_MAPPING_ERROR) if (dma_addr == DMA_MAPPING_ERROR)
return dma_addr; return dma_addr;
...@@ -1487,50 +1401,6 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p ...@@ -1487,50 +1401,6 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
return DMA_MAPPING_ERROR; return DMA_MAPPING_ERROR;
} }
/**
* arm_iommu_map_page
* @dev: valid struct device pointer
* @page: page that buffer resides in
* @offset: offset into page for start of buffer
* @size: size of buffer to map
* @dir: DMA transfer direction
*
* IOMMU aware version of arm_dma_map_page()
*/
static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__dma_page_cpu_to_dev(page, offset, size, dir);
return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
}
/**
* arm_coherent_iommu_unmap_page
* @dev: valid struct device pointer
* @handle: DMA address of buffer
* @size: size of buffer (same as passed to dma_map_page)
* @dir: DMA transfer direction (same as passed to dma_map_page)
*
* Coherent IOMMU aware version of arm_dma_unmap_page()
*/
static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
dma_addr_t iova = handle & PAGE_MASK;
int offset = handle & ~PAGE_MASK;
int len = PAGE_ALIGN(size + offset);
if (!iova)
return;
iommu_unmap(mapping->domain, iova, len);
__free_iova(mapping, iova, len);
}
/** /**
* arm_iommu_unmap_page * arm_iommu_unmap_page
* @dev: valid struct device pointer * @dev: valid struct device pointer
...@@ -1545,15 +1415,17 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, ...@@ -1545,15 +1415,17 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
{ {
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
dma_addr_t iova = handle & PAGE_MASK; dma_addr_t iova = handle & PAGE_MASK;
struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); struct page *page;
int offset = handle & ~PAGE_MASK; int offset = handle & ~PAGE_MASK;
int len = PAGE_ALIGN(size + offset); int len = PAGE_ALIGN(size + offset);
if (!iova) if (!iova)
return; return;
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
__dma_page_dev_to_cpu(page, offset, size, dir); __dma_page_dev_to_cpu(page, offset, size, dir);
}
iommu_unmap(mapping->domain, iova, len); iommu_unmap(mapping->domain, iova, len);
__free_iova(mapping, iova, len); __free_iova(mapping, iova, len);
...@@ -1665,16 +1537,16 @@ static const struct dma_map_ops iommu_ops = { ...@@ -1665,16 +1537,16 @@ static const struct dma_map_ops iommu_ops = {
}; };
static const struct dma_map_ops iommu_coherent_ops = { static const struct dma_map_ops iommu_coherent_ops = {
.alloc = arm_coherent_iommu_alloc_attrs, .alloc = arm_iommu_alloc_attrs,
.free = arm_coherent_iommu_free_attrs, .free = arm_iommu_free_attrs,
.mmap = arm_coherent_iommu_mmap_attrs, .mmap = arm_iommu_mmap_attrs,
.get_sgtable = arm_iommu_get_sgtable, .get_sgtable = arm_iommu_get_sgtable,
.map_page = arm_coherent_iommu_map_page, .map_page = arm_iommu_map_page,
.unmap_page = arm_coherent_iommu_unmap_page, .unmap_page = arm_iommu_unmap_page,
.map_sg = arm_coherent_iommu_map_sg, .map_sg = arm_iommu_map_sg,
.unmap_sg = arm_coherent_iommu_unmap_sg, .unmap_sg = arm_iommu_unmap_sg,
.map_resource = arm_iommu_map_resource, .map_resource = arm_iommu_map_resource,
.unmap_resource = arm_iommu_unmap_resource, .unmap_resource = arm_iommu_unmap_resource,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment