参照元†
- void *alloc_ctx
- unsigned long size
- enum dma_data_direction dma_dir
- gfp_t gfp_flags
返り値†
static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size,
enum dma_data_direction dma_dir, gfp_t gfp_flags)
{
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
struct sg_table *sgt;
int ret;
int num_pages;
DEFINE_DMA_ATTRS(attrs);
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
if (WARN_ON(alloc_ctx == NULL))
return NULL;
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
buf->vaddr = NULL;
buf->dma_dir = dma_dir;
buf->offset = 0;
buf->size = size;
/* size is already page aligned */
buf->num_pages = size >> PAGE_SHIFT;
buf->dma_sgt = &buf->sg_table;
buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
GFP_KERNEL);
if (!buf->pages)
goto fail_pages_array_alloc;
ret = vb2_dma_sg_alloc_compacted(buf, gfp_flags);
if (ret)
goto fail_pages_alloc;
ret = sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
buf->num_pages, 0, size, GFP_KERNEL);
if (ret)
goto fail_table_alloc;
/* Prevent the device from being released while the buffer is used */
buf->dev = get_device(conf->dev);
sgt = &buf->sg_table;
/*
* 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, &attrs);
if (!sgt->nents)
goto fail_map;
buf->handler.refcount = &buf->refcount;
buf->handler.put = vb2_dma_sg_put;
buf->handler.arg = buf;
atomic_inc(&buf->refcount);
dprintk(1, "%s: Allocated buffer of %d pages\n",
__func__, buf->num_pages);
return buf;
fail_map:
put_device(buf->dev);
sg_free_table(buf->dma_sgt);
fail_table_alloc:
num_pages = buf->num_pages;
while (num_pages--)
__free_page(buf->pages[num_pages]);
fail_pages_alloc:
kfree(buf->pages);
fail_pages_array_alloc:
kfree(buf);
return NULL;
}
コメント†