mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
WIP: ARM/dma-mapping: implement ->alloc_noncontiguous
Implement support for allocating a non-contiguous DMA region. The implementation is based on the ma-iommu driver. Signed-off-by: Pavel Golikov <Paullo612@ya.ru>
This commit is contained in:
committed by
Mauro (mdrjr) Ribeiro
parent
76977620c7
commit
9cd5a4c47d
@@ -1315,6 +1315,63 @@ static void arm_iommu_unmap_sg(struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static struct sg_table *arm_iommu_alloc_noncontiguous(struct device *dev,
|
||||
size_t size, enum dma_data_direction dir, gfp_t gfp,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct dma_sgt_handle *sh;
|
||||
int count;
|
||||
|
||||
sh = kmalloc(sizeof(*sh), gfp);
|
||||
if (!sh)
|
||||
return NULL;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
count = size >> PAGE_SHIFT;
|
||||
|
||||
/*
|
||||
* Following is a work-around (a.k.a. hack) to prevent pages
|
||||
* with __GFP_COMP being passed to split_page() which cannot
|
||||
* handle them. The real problem is that this flag probably
|
||||
* should be 0 on ARM as it is not supported on this
|
||||
* platform; see CONFIG_HUGETLBFS.
|
||||
*/
|
||||
gfp &= ~(__GFP_COMP);
|
||||
|
||||
sh->pages = __iommu_alloc_buffer(dev, size, gfp, attrs, false);
|
||||
if (!sh->pages)
|
||||
goto err_sh;
|
||||
|
||||
if (sg_alloc_table_from_pages(&sh->sgt, sh->pages, count, 0, size,
|
||||
GFP_KERNEL))
|
||||
goto err_buffer;
|
||||
|
||||
if (__iommu_map_sg(dev, sh->sgt.sgl, sh->sgt.orig_nents, dir, attrs,
|
||||
false) < 1)
|
||||
goto err_free_sg;
|
||||
|
||||
return &sh->sgt;
|
||||
|
||||
err_free_sg:
|
||||
sg_free_table(&sh->sgt);
|
||||
err_buffer:
|
||||
__iommu_free_buffer(dev, sh->pages, size, attrs);
|
||||
err_sh:
|
||||
kfree(sh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void arm_iommu_free_noncontiguous(struct device *dev, size_t size,
|
||||
struct sg_table *sgt, enum dma_data_direction dir)
|
||||
{
|
||||
struct dma_sgt_handle *sh = sgt_handle(sgt);
|
||||
|
||||
__iommu_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir, 0, false);
|
||||
__iommu_free_buffer(dev, sh->pages, PAGE_ALIGN(size), 0);
|
||||
sg_free_table(&sh->sgt);
|
||||
kfree(sh);
|
||||
}
|
||||
|
||||
/**
|
||||
* arm_iommu_sync_sg_for_cpu
|
||||
* @dev: valid struct device pointer
|
||||
@@ -1521,6 +1578,8 @@ static const struct dma_map_ops iommu_ops = {
|
||||
|
||||
.map_page = arm_iommu_map_page,
|
||||
.unmap_page = arm_iommu_unmap_page,
|
||||
.alloc_noncontiguous = arm_iommu_alloc_noncontiguous,
|
||||
.free_noncontiguous = arm_iommu_free_noncontiguous,
|
||||
.sync_single_for_cpu = arm_iommu_sync_single_for_cpu,
|
||||
.sync_single_for_device = arm_iommu_sync_single_for_device,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user