@@ -30,6 +30,7 @@ struct vb2_dc_buf {
dma_addr_t dma_addr;
unsigned long attrs;
enum dma_data_direction dma_dir;
+ struct sg_table __dma_sgt;
struct sg_table *dma_sgt;
/* MMAP related */
@@ -127,10 +128,9 @@ static void vb2_dc_put(void *buf_priv)
if (!refcount_dec_and_test(&buf->refcount))
return;
- if (buf->dma_sgt) {
+ if (buf->dma_sgt)
sg_free_table(buf->dma_sgt);
- kfree(buf->dma_sgt);
- }
+
dma_free_attrs(buf->dev, buf->size, buf->cookie, buf->dma_addr,
buf->attrs);
put_device(buf->dev);
@@ -364,26 +364,6 @@ static struct dma_buf_ops vb2_dc_dmabuf_ops = {
.release = vb2_dc_dmabuf_ops_release,
};
-static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf)
-{
- int ret;
- struct sg_table *sgt;
-
- sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
- if (!sgt)
- return NULL;
-
- ret = dma_get_sgtable_attrs(buf->dev, sgt, buf->cookie, buf->dma_addr,
- buf->size, buf->attrs);
- if (ret < 0) {
- dev_err(buf->dev, "failed to get scatterlist from DMA API\n");
- kfree(sgt);
- return NULL;
- }
-
- return sgt;
-}
-
static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags)
{
struct vb2_dc_buf *buf = buf_priv;
@@ -395,11 +375,19 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags)
exp_info.flags = flags;
exp_info.priv = buf;
- if (!buf->dma_sgt)
- buf->dma_sgt = vb2_dc_get_base_sgt(buf);
+ if (!buf->dma_sgt) {
+ int ret;
- if (!buf->dma_sgt)
- return NULL;
+ ret = dma_get_sgtable_attrs(buf->dev, &buf->__dma_sgt,
+ buf->cookie, buf->dma_addr,
+ buf->size, buf->attrs);
+ if (ret < 0) {
+ dev_err(buf->dev, "failed to get scatterlist from DMA API\n");
+ return NULL;
+ }
+
+ buf->dma_sgt = &buf->__dma_sgt;
+ }
dbuf = dma_buf_export(&exp_info);
if (IS_ERR(dbuf))
@@ -435,7 +423,6 @@ static void vb2_dc_put_userptr(void *buf_priv)
for (i = 0; i < frame_vector_count(buf->vec); i++)
set_page_dirty_lock(pages[i]);
sg_free_table(sgt);
- kfree(sgt);
}
vb2_destroy_framevec(buf->vec);
kfree(buf);
@@ -481,7 +468,6 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
unsigned long offset;
int n_pages, i;
int ret = 0;
- struct sg_table *sgt;
unsigned long contig_size;
unsigned long dma_align = dma_get_cache_alignment();
@@ -529,33 +515,31 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
goto out;
}
- sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
- if (!sgt) {
- pr_err("failed to allocate sg table\n");
- ret = -ENOMEM;
- goto fail_pfnvec;
- }
-
- ret = sg_alloc_table_from_pages(sgt, frame_vector_pages(vec), n_pages,
- offset, size, GFP_KERNEL);
+ ret = sg_alloc_table_from_pages(&buf->__dma_sgt,
+ frame_vector_pages(vec), n_pages,
+ offset, size, GFP_KERNEL);
if (ret) {
pr_err("failed to initialize sg table\n");
- goto fail_sgt;
+ goto fail_pfnvec;
}
+ buf->dma_sgt = &buf->__dma_sgt;
+
/*
* No need to sync to the device, this will happen later when the
* prepare() memop is called.
*/
- sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
- if (sgt->nents <= 0) {
+ buf->dma_sgt->nents = dma_map_sg_attrs(buf->dev, buf->dma_sgt->sgl,
+ buf->dma_sgt->orig_nents,
+ buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ if (buf->dma_sgt->nents <= 0) {
pr_err("failed to map scatterlist\n");
ret = -EIO;
goto fail_sgt_init;
}
- contig_size = vb2_dc_get_contiguous_size(sgt);
+ contig_size = vb2_dc_get_contiguous_size(buf->dma_sgt);
if (contig_size < size) {
pr_err("contiguous mapping is too small %lu/%lu\n",
contig_size, size);
@@ -563,22 +547,19 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
goto fail_map_sg;
}
- buf->dma_addr = sg_dma_address(sgt->sgl);
- buf->dma_sgt = sgt;
+ buf->dma_addr = sg_dma_address(buf->dma_sgt->sgl);
out:
buf->size = size;
return buf;
fail_map_sg:
- dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sg_attrs(buf->dev, buf->dma_sgt->sgl,
+ buf->dma_sgt->orig_nents, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
fail_sgt_init:
- sg_free_table(sgt);
-
-fail_sgt:
- kfree(sgt);
+ sg_free_table(buf->dma_sgt);
fail_pfnvec:
vb2_destroy_framevec(vec);
The scatterlist table is needed in the vast majority of the cases. Allocate struct sg_table as part of the struct. This has the benefit of making managing the buffer data structure allocation, setup and release more simple. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 83 ++++++++++---------------- 1 file changed, 32 insertions(+), 51 deletions(-)