162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2010 Samsung Electronics
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Pawel Osciak <pawel@osciak.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
962306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
1062306a36Sopenharmony_ci * the Free Software Foundation.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/mm.h>
1662306a36Sopenharmony_ci#include <linux/refcount.h>
1762306a36Sopenharmony_ci#include <linux/sched.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/vmalloc.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h>
2262306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
2362306a36Sopenharmony_ci#include <media/videobuf2-memops.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct vb2_vmalloc_buf {
2662306a36Sopenharmony_ci	void				*vaddr;
2762306a36Sopenharmony_ci	struct frame_vector		*vec;
2862306a36Sopenharmony_ci	enum dma_data_direction		dma_dir;
2962306a36Sopenharmony_ci	unsigned long			size;
3062306a36Sopenharmony_ci	refcount_t			refcount;
3162306a36Sopenharmony_ci	struct vb2_vmarea_handler	handler;
3262306a36Sopenharmony_ci	struct dma_buf			*dbuf;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic void vb2_vmalloc_put(void *buf_priv);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void *vb2_vmalloc_alloc(struct vb2_buffer *vb, struct device *dev,
3862306a36Sopenharmony_ci			       unsigned long size)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags);
4362306a36Sopenharmony_ci	if (!buf)
4462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	buf->size = size;
4762306a36Sopenharmony_ci	buf->vaddr = vmalloc_user(buf->size);
4862306a36Sopenharmony_ci	if (!buf->vaddr) {
4962306a36Sopenharmony_ci		pr_debug("vmalloc of size %ld failed\n", buf->size);
5062306a36Sopenharmony_ci		kfree(buf);
5162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	buf->dma_dir = vb->vb2_queue->dma_dir;
5562306a36Sopenharmony_ci	buf->handler.refcount = &buf->refcount;
5662306a36Sopenharmony_ci	buf->handler.put = vb2_vmalloc_put;
5762306a36Sopenharmony_ci	buf->handler.arg = buf;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	refcount_set(&buf->refcount, 1);
6062306a36Sopenharmony_ci	return buf;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic void vb2_vmalloc_put(void *buf_priv)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = buf_priv;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (refcount_dec_and_test(&buf->refcount)) {
6862306a36Sopenharmony_ci		vfree(buf->vaddr);
6962306a36Sopenharmony_ci		kfree(buf);
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev,
7462306a36Sopenharmony_ci				     unsigned long vaddr, unsigned long size)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf;
7762306a36Sopenharmony_ci	struct frame_vector *vec;
7862306a36Sopenharmony_ci	int n_pages, offset, i;
7962306a36Sopenharmony_ci	int ret = -ENOMEM;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
8262306a36Sopenharmony_ci	if (!buf)
8362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	buf->dma_dir = vb->vb2_queue->dma_dir;
8662306a36Sopenharmony_ci	offset = vaddr & ~PAGE_MASK;
8762306a36Sopenharmony_ci	buf->size = size;
8862306a36Sopenharmony_ci	vec = vb2_create_framevec(vaddr, size,
8962306a36Sopenharmony_ci				  buf->dma_dir == DMA_FROM_DEVICE ||
9062306a36Sopenharmony_ci				  buf->dma_dir == DMA_BIDIRECTIONAL);
9162306a36Sopenharmony_ci	if (IS_ERR(vec)) {
9262306a36Sopenharmony_ci		ret = PTR_ERR(vec);
9362306a36Sopenharmony_ci		goto fail_pfnvec_create;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci	buf->vec = vec;
9662306a36Sopenharmony_ci	n_pages = frame_vector_count(vec);
9762306a36Sopenharmony_ci	if (frame_vector_to_pages(vec) < 0) {
9862306a36Sopenharmony_ci		unsigned long *nums = frame_vector_pfns(vec);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		/*
10162306a36Sopenharmony_ci		 * We cannot get page pointers for these pfns. Check memory is
10262306a36Sopenharmony_ci		 * physically contiguous and use direct mapping.
10362306a36Sopenharmony_ci		 */
10462306a36Sopenharmony_ci		for (i = 1; i < n_pages; i++)
10562306a36Sopenharmony_ci			if (nums[i-1] + 1 != nums[i])
10662306a36Sopenharmony_ci				goto fail_map;
10762306a36Sopenharmony_ci		buf->vaddr = (__force void *)
10862306a36Sopenharmony_ci			ioremap(__pfn_to_phys(nums[0]), size + offset);
10962306a36Sopenharmony_ci	} else {
11062306a36Sopenharmony_ci		buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1);
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (!buf->vaddr)
11462306a36Sopenharmony_ci		goto fail_map;
11562306a36Sopenharmony_ci	buf->vaddr += offset;
11662306a36Sopenharmony_ci	return buf;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cifail_map:
11962306a36Sopenharmony_ci	vb2_destroy_framevec(vec);
12062306a36Sopenharmony_cifail_pfnvec_create:
12162306a36Sopenharmony_ci	kfree(buf);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return ERR_PTR(ret);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic void vb2_vmalloc_put_userptr(void *buf_priv)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = buf_priv;
12962306a36Sopenharmony_ci	unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
13062306a36Sopenharmony_ci	unsigned int i;
13162306a36Sopenharmony_ci	struct page **pages;
13262306a36Sopenharmony_ci	unsigned int n_pages;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (!buf->vec->is_pfns) {
13562306a36Sopenharmony_ci		n_pages = frame_vector_count(buf->vec);
13662306a36Sopenharmony_ci		pages = frame_vector_pages(buf->vec);
13762306a36Sopenharmony_ci		if (vaddr)
13862306a36Sopenharmony_ci			vm_unmap_ram((void *)vaddr, n_pages);
13962306a36Sopenharmony_ci		if (buf->dma_dir == DMA_FROM_DEVICE ||
14062306a36Sopenharmony_ci		    buf->dma_dir == DMA_BIDIRECTIONAL)
14162306a36Sopenharmony_ci			for (i = 0; i < n_pages; i++)
14262306a36Sopenharmony_ci				set_page_dirty_lock(pages[i]);
14362306a36Sopenharmony_ci	} else {
14462306a36Sopenharmony_ci		iounmap((__force void __iomem *)buf->vaddr);
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	vb2_destroy_framevec(buf->vec);
14762306a36Sopenharmony_ci	kfree(buf);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void *vb2_vmalloc_vaddr(struct vb2_buffer *vb, void *buf_priv)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = buf_priv;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (!buf->vaddr) {
15562306a36Sopenharmony_ci		pr_err("Address of an unallocated plane requested or cannot map user pointer\n");
15662306a36Sopenharmony_ci		return NULL;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return buf->vaddr;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic unsigned int vb2_vmalloc_num_users(void *buf_priv)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = buf_priv;
16562306a36Sopenharmony_ci	return refcount_read(&buf->refcount);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = buf_priv;
17162306a36Sopenharmony_ci	int ret;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (!buf) {
17462306a36Sopenharmony_ci		pr_err("No memory to map\n");
17562306a36Sopenharmony_ci		return -EINVAL;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
17962306a36Sopenharmony_ci	if (ret) {
18062306a36Sopenharmony_ci		pr_err("Remapping vmalloc memory, error: %d\n", ret);
18162306a36Sopenharmony_ci		return ret;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * Make sure that vm_areas for 2 buffers won't be merged together
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	vm_flags_set(vma, VM_DONTEXPAND);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/*
19062306a36Sopenharmony_ci	 * Use common vm_area operations to track buffer refcount.
19162306a36Sopenharmony_ci	 */
19262306a36Sopenharmony_ci	vma->vm_private_data	= &buf->handler;
19362306a36Sopenharmony_ci	vma->vm_ops		= &vb2_common_vm_ops;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	vma->vm_ops->open(vma);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#ifdef CONFIG_HAS_DMA
20162306a36Sopenharmony_ci/*********************************************/
20262306a36Sopenharmony_ci/*         DMABUF ops for exporters          */
20362306a36Sopenharmony_ci/*********************************************/
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistruct vb2_vmalloc_attachment {
20662306a36Sopenharmony_ci	struct sg_table sgt;
20762306a36Sopenharmony_ci	enum dma_data_direction dma_dir;
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf,
21162306a36Sopenharmony_ci	struct dma_buf_attachment *dbuf_attach)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct vb2_vmalloc_attachment *attach;
21462306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = dbuf->priv;
21562306a36Sopenharmony_ci	int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE;
21662306a36Sopenharmony_ci	struct sg_table *sgt;
21762306a36Sopenharmony_ci	struct scatterlist *sg;
21862306a36Sopenharmony_ci	void *vaddr = buf->vaddr;
21962306a36Sopenharmony_ci	int ret;
22062306a36Sopenharmony_ci	int i;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	attach = kzalloc(sizeof(*attach), GFP_KERNEL);
22362306a36Sopenharmony_ci	if (!attach)
22462306a36Sopenharmony_ci		return -ENOMEM;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	sgt = &attach->sgt;
22762306a36Sopenharmony_ci	ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL);
22862306a36Sopenharmony_ci	if (ret) {
22962306a36Sopenharmony_ci		kfree(attach);
23062306a36Sopenharmony_ci		return ret;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci	for_each_sgtable_sg(sgt, sg, i) {
23362306a36Sopenharmony_ci		struct page *page = vmalloc_to_page(vaddr);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		if (!page) {
23662306a36Sopenharmony_ci			sg_free_table(sgt);
23762306a36Sopenharmony_ci			kfree(attach);
23862306a36Sopenharmony_ci			return -ENOMEM;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci		sg_set_page(sg, page, PAGE_SIZE, 0);
24162306a36Sopenharmony_ci		vaddr += PAGE_SIZE;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	attach->dma_dir = DMA_NONE;
24562306a36Sopenharmony_ci	dbuf_attach->priv = attach;
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void vb2_vmalloc_dmabuf_ops_detach(struct dma_buf *dbuf,
25062306a36Sopenharmony_ci	struct dma_buf_attachment *db_attach)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct vb2_vmalloc_attachment *attach = db_attach->priv;
25362306a36Sopenharmony_ci	struct sg_table *sgt;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (!attach)
25662306a36Sopenharmony_ci		return;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	sgt = &attach->sgt;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* release the scatterlist cache */
26162306a36Sopenharmony_ci	if (attach->dma_dir != DMA_NONE)
26262306a36Sopenharmony_ci		dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
26362306a36Sopenharmony_ci	sg_free_table(sgt);
26462306a36Sopenharmony_ci	kfree(attach);
26562306a36Sopenharmony_ci	db_attach->priv = NULL;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic struct sg_table *vb2_vmalloc_dmabuf_ops_map(
26962306a36Sopenharmony_ci	struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct vb2_vmalloc_attachment *attach = db_attach->priv;
27262306a36Sopenharmony_ci	struct sg_table *sgt;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	sgt = &attach->sgt;
27562306a36Sopenharmony_ci	/* return previously mapped sg table */
27662306a36Sopenharmony_ci	if (attach->dma_dir == dma_dir)
27762306a36Sopenharmony_ci		return sgt;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* release any previous cache */
28062306a36Sopenharmony_ci	if (attach->dma_dir != DMA_NONE) {
28162306a36Sopenharmony_ci		dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
28262306a36Sopenharmony_ci		attach->dma_dir = DMA_NONE;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* mapping to the client with new direction */
28662306a36Sopenharmony_ci	if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) {
28762306a36Sopenharmony_ci		pr_err("failed to map scatterlist\n");
28862306a36Sopenharmony_ci		return ERR_PTR(-EIO);
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	attach->dma_dir = dma_dir;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return sgt;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void vb2_vmalloc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
29762306a36Sopenharmony_ci	struct sg_table *sgt, enum dma_data_direction dma_dir)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	/* nothing to be done here */
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic void vb2_vmalloc_dmabuf_ops_release(struct dma_buf *dbuf)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	/* drop reference obtained in vb2_vmalloc_get_dmabuf */
30562306a36Sopenharmony_ci	vb2_vmalloc_put(dbuf->priv);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf,
30962306a36Sopenharmony_ci				       struct iosys_map *map)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = dbuf->priv;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	iosys_map_set_vaddr(map, buf->vaddr);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf,
31962306a36Sopenharmony_ci	struct vm_area_struct *vma)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	return vb2_vmalloc_mmap(dbuf->priv, vma);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = {
32562306a36Sopenharmony_ci	.attach = vb2_vmalloc_dmabuf_ops_attach,
32662306a36Sopenharmony_ci	.detach = vb2_vmalloc_dmabuf_ops_detach,
32762306a36Sopenharmony_ci	.map_dma_buf = vb2_vmalloc_dmabuf_ops_map,
32862306a36Sopenharmony_ci	.unmap_dma_buf = vb2_vmalloc_dmabuf_ops_unmap,
32962306a36Sopenharmony_ci	.vmap = vb2_vmalloc_dmabuf_ops_vmap,
33062306a36Sopenharmony_ci	.mmap = vb2_vmalloc_dmabuf_ops_mmap,
33162306a36Sopenharmony_ci	.release = vb2_vmalloc_dmabuf_ops_release,
33262306a36Sopenharmony_ci};
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic struct dma_buf *vb2_vmalloc_get_dmabuf(struct vb2_buffer *vb,
33562306a36Sopenharmony_ci					      void *buf_priv,
33662306a36Sopenharmony_ci					      unsigned long flags)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = buf_priv;
33962306a36Sopenharmony_ci	struct dma_buf *dbuf;
34062306a36Sopenharmony_ci	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	exp_info.ops = &vb2_vmalloc_dmabuf_ops;
34362306a36Sopenharmony_ci	exp_info.size = buf->size;
34462306a36Sopenharmony_ci	exp_info.flags = flags;
34562306a36Sopenharmony_ci	exp_info.priv = buf;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (WARN_ON(!buf->vaddr))
34862306a36Sopenharmony_ci		return NULL;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	dbuf = dma_buf_export(&exp_info);
35162306a36Sopenharmony_ci	if (IS_ERR(dbuf))
35262306a36Sopenharmony_ci		return NULL;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* dmabuf keeps reference to vb2 buffer */
35562306a36Sopenharmony_ci	refcount_inc(&buf->refcount);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return dbuf;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci#endif /* CONFIG_HAS_DMA */
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/*********************************************/
36362306a36Sopenharmony_ci/*       callbacks for DMABUF buffers        */
36462306a36Sopenharmony_ci/*********************************************/
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int vb2_vmalloc_map_dmabuf(void *mem_priv)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = mem_priv;
36962306a36Sopenharmony_ci	struct iosys_map map;
37062306a36Sopenharmony_ci	int ret;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	ret = dma_buf_vmap_unlocked(buf->dbuf, &map);
37362306a36Sopenharmony_ci	if (ret)
37462306a36Sopenharmony_ci		return -EFAULT;
37562306a36Sopenharmony_ci	buf->vaddr = map.vaddr;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void vb2_vmalloc_unmap_dmabuf(void *mem_priv)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = mem_priv;
38362306a36Sopenharmony_ci	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	dma_buf_vunmap_unlocked(buf->dbuf, &map);
38662306a36Sopenharmony_ci	buf->vaddr = NULL;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void vb2_vmalloc_detach_dmabuf(void *mem_priv)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf = mem_priv;
39262306a36Sopenharmony_ci	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (buf->vaddr)
39562306a36Sopenharmony_ci		dma_buf_vunmap_unlocked(buf->dbuf, &map);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	kfree(buf);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void *vb2_vmalloc_attach_dmabuf(struct vb2_buffer *vb,
40162306a36Sopenharmony_ci				       struct device *dev,
40262306a36Sopenharmony_ci				       struct dma_buf *dbuf,
40362306a36Sopenharmony_ci				       unsigned long size)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct vb2_vmalloc_buf *buf;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (dbuf->size < size)
40862306a36Sopenharmony_ci		return ERR_PTR(-EFAULT);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
41162306a36Sopenharmony_ci	if (!buf)
41262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	buf->dbuf = dbuf;
41562306a36Sopenharmony_ci	buf->dma_dir = vb->vb2_queue->dma_dir;
41662306a36Sopenharmony_ci	buf->size = size;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return buf;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ciconst struct vb2_mem_ops vb2_vmalloc_memops = {
42362306a36Sopenharmony_ci	.alloc		= vb2_vmalloc_alloc,
42462306a36Sopenharmony_ci	.put		= vb2_vmalloc_put,
42562306a36Sopenharmony_ci	.get_userptr	= vb2_vmalloc_get_userptr,
42662306a36Sopenharmony_ci	.put_userptr	= vb2_vmalloc_put_userptr,
42762306a36Sopenharmony_ci#ifdef CONFIG_HAS_DMA
42862306a36Sopenharmony_ci	.get_dmabuf	= vb2_vmalloc_get_dmabuf,
42962306a36Sopenharmony_ci#endif
43062306a36Sopenharmony_ci	.map_dmabuf	= vb2_vmalloc_map_dmabuf,
43162306a36Sopenharmony_ci	.unmap_dmabuf	= vb2_vmalloc_unmap_dmabuf,
43262306a36Sopenharmony_ci	.attach_dmabuf	= vb2_vmalloc_attach_dmabuf,
43362306a36Sopenharmony_ci	.detach_dmabuf	= vb2_vmalloc_detach_dmabuf,
43462306a36Sopenharmony_ci	.vaddr		= vb2_vmalloc_vaddr,
43562306a36Sopenharmony_ci	.mmap		= vb2_vmalloc_mmap,
43662306a36Sopenharmony_ci	.num_users	= vb2_vmalloc_num_users,
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciMODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
44162306a36Sopenharmony_ciMODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
44262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
44362306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF);
444