Skip to content

Commit

Permalink
WIP: ARM/dma-mapping: implement ->alloc_noncontiguous
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paullo612 authored and chewitt committed Jun 26, 2022
1 parent 4d9cc9d commit fbd0c34
Showing 1 changed file with 59 additions and 0 deletions.
59 changes: 59 additions & 0 deletions arch/arm/mm/dma-mapping.c
Expand Up @@ -1759,6 +1759,63 @@ static void arm_iommu_unmap_sg(struct device *dev,
__iommu_unmap_sg(dev, sg, nents, dir, attrs, false);
}

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
Expand Down Expand Up @@ -1996,6 +2053,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,

Expand Down

0 comments on commit fbd0c34

Please sign in to comment.