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:
Pavel Golikov
2022-06-24 15:52:58 +00:00
committed by Mauro (mdrjr) Ribeiro
parent 76977620c7
commit 9cd5a4c47d

View File

@@ -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,