18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Framework for buffer objects that can be shared across devices/subsystems.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright(C) 2011 Linaro Limited. All rights reserved.
68c2ecf20Sopenharmony_ci * Author: Sumit Semwal <sumit.semwal@ti.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Many thanks to linaro-mm-sig list, and specially
98c2ecf20Sopenharmony_ci * Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and
108c2ecf20Sopenharmony_ci * Daniel Vetter <daniel@ffwll.ch> for their support in creation and
118c2ecf20Sopenharmony_ci * refining of this idea.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/fs.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/dma-buf.h>
178c2ecf20Sopenharmony_ci#include <linux/dma-fence.h>
188c2ecf20Sopenharmony_ci#include <linux/anon_inodes.h>
198c2ecf20Sopenharmony_ci#include <linux/export.h>
208c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
238c2ecf20Sopenharmony_ci#include <linux/poll.h>
248c2ecf20Sopenharmony_ci#include <linux/dma-resv.h>
258c2ecf20Sopenharmony_ci#include <linux/mm.h>
268c2ecf20Sopenharmony_ci#include <linux/mount.h>
278c2ecf20Sopenharmony_ci#include <linux/pseudo_fs.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <uapi/linux/dma-buf.h>
308c2ecf20Sopenharmony_ci#include <uapi/linux/magic.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "dma-buf-sysfs-stats.h"
338c2ecf20Sopenharmony_ci#include "dma-buf-process-info.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic inline int is_dma_buf_file(struct file *);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct dma_buf_list {
388c2ecf20Sopenharmony_ci	struct list_head head;
398c2ecf20Sopenharmony_ci	struct mutex lock;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic struct dma_buf_list db_list;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
478c2ecf20Sopenharmony_ci	char name[DMA_BUF_NAME_LEN];
488c2ecf20Sopenharmony_ci	size_t ret = 0;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	dmabuf = dentry->d_fsdata;
518c2ecf20Sopenharmony_ci	spin_lock(&dmabuf->name_lock);
528c2ecf20Sopenharmony_ci	if (dmabuf->name)
538c2ecf20Sopenharmony_ci		ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
548c2ecf20Sopenharmony_ci	spin_unlock(&dmabuf->name_lock);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
578c2ecf20Sopenharmony_ci			     dentry->d_name.name, ret > 0 ? name : "");
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void dma_buf_release(struct dentry *dentry)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	dmabuf = dentry->d_fsdata;
658c2ecf20Sopenharmony_ci	if (unlikely(!dmabuf))
668c2ecf20Sopenharmony_ci		return;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	BUG_ON(dmabuf->vmapping_counter);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/*
718c2ecf20Sopenharmony_ci	 * Any fences that a dma-buf poll can wait on should be signaled
728c2ecf20Sopenharmony_ci	 * before releasing dma-buf. This is the responsibility of each
738c2ecf20Sopenharmony_ci	 * driver that uses the reservation objects.
748c2ecf20Sopenharmony_ci	 *
758c2ecf20Sopenharmony_ci	 * If you hit this BUG() it means someone dropped their ref to the
768c2ecf20Sopenharmony_ci	 * dma-buf while still having pending operation to the buffer.
778c2ecf20Sopenharmony_ci	 */
788c2ecf20Sopenharmony_ci	BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	dmabuf->ops->release(dmabuf);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
838c2ecf20Sopenharmony_ci		dma_resv_fini(dmabuf->resv);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&dmabuf->attachments));
868c2ecf20Sopenharmony_ci	dma_buf_stats_teardown(dmabuf);
878c2ecf20Sopenharmony_ci	module_put(dmabuf->owner);
888c2ecf20Sopenharmony_ci	kfree(dmabuf->name);
898c2ecf20Sopenharmony_ci	kfree(dmabuf);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int dma_buf_file_release(struct inode *inode, struct file *file)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (!is_dma_buf_file(file))
978c2ecf20Sopenharmony_ci		return -EINVAL;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	dmabuf = file->private_data;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	mutex_lock(&db_list.lock);
1028c2ecf20Sopenharmony_ci	list_del(&dmabuf->list_node);
1038c2ecf20Sopenharmony_ci	mutex_unlock(&db_list.lock);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic const struct dentry_operations dma_buf_dentry_ops = {
1098c2ecf20Sopenharmony_ci	.d_dname = dmabuffs_dname,
1108c2ecf20Sopenharmony_ci	.d_release = dma_buf_release,
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct vfsmount *dma_buf_mnt;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int dma_buf_fs_init_context(struct fs_context *fc)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct pseudo_fs_context *ctx;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	ctx = init_pseudo(fc, DMA_BUF_MAGIC);
1208c2ecf20Sopenharmony_ci	if (!ctx)
1218c2ecf20Sopenharmony_ci		return -ENOMEM;
1228c2ecf20Sopenharmony_ci	ctx->dops = &dma_buf_dentry_ops;
1238c2ecf20Sopenharmony_ci	return 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic struct file_system_type dma_buf_fs_type = {
1278c2ecf20Sopenharmony_ci	.name = "dmabuf",
1288c2ecf20Sopenharmony_ci	.init_fs_context = dma_buf_fs_init_context,
1298c2ecf20Sopenharmony_ci	.kill_sb = kill_anon_super,
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (!is_dma_buf_file(file))
1378c2ecf20Sopenharmony_ci		return -EINVAL;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	dmabuf = file->private_data;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* check if buffer supports mmap */
1428c2ecf20Sopenharmony_ci	if (!dmabuf->ops->mmap)
1438c2ecf20Sopenharmony_ci		return -EINVAL;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* check for overflowing the buffer's size */
1468c2ecf20Sopenharmony_ci	if (vma->vm_pgoff + vma_pages(vma) >
1478c2ecf20Sopenharmony_ci	    dmabuf->size >> PAGE_SHIFT)
1488c2ecf20Sopenharmony_ci		return -EINVAL;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return dmabuf->ops->mmap(dmabuf, vma);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
1568c2ecf20Sopenharmony_ci	loff_t base;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (!is_dma_buf_file(file))
1598c2ecf20Sopenharmony_ci		return -EBADF;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	dmabuf = file->private_data;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* only support discovering the end of the buffer,
1648c2ecf20Sopenharmony_ci	   but also allow SEEK_SET to maintain the idiomatic
1658c2ecf20Sopenharmony_ci	   SEEK_END(0), SEEK_CUR(0) pattern */
1668c2ecf20Sopenharmony_ci	if (whence == SEEK_END)
1678c2ecf20Sopenharmony_ci		base = dmabuf->size;
1688c2ecf20Sopenharmony_ci	else if (whence == SEEK_SET)
1698c2ecf20Sopenharmony_ci		base = 0;
1708c2ecf20Sopenharmony_ci	else
1718c2ecf20Sopenharmony_ci		return -EINVAL;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (offset != 0)
1748c2ecf20Sopenharmony_ci		return -EINVAL;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return base + offset;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/**
1808c2ecf20Sopenharmony_ci * DOC: implicit fence polling
1818c2ecf20Sopenharmony_ci *
1828c2ecf20Sopenharmony_ci * To support cross-device and cross-driver synchronization of buffer access
1838c2ecf20Sopenharmony_ci * implicit fences (represented internally in the kernel with &struct dma_fence)
1848c2ecf20Sopenharmony_ci * can be attached to a &dma_buf. The glue for that and a few related things are
1858c2ecf20Sopenharmony_ci * provided in the &dma_resv structure.
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * Userspace can query the state of these implicitly tracked fences using poll()
1888c2ecf20Sopenharmony_ci * and related system calls:
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * - Checking for EPOLLIN, i.e. read access, can be use to query the state of the
1918c2ecf20Sopenharmony_ci *   most recent write or exclusive fence.
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * - Checking for EPOLLOUT, i.e. write access, can be used to query the state of
1948c2ecf20Sopenharmony_ci *   all attached fences, shared and exclusive ones.
1958c2ecf20Sopenharmony_ci *
1968c2ecf20Sopenharmony_ci * Note that this only signals the completion of the respective fences, i.e. the
1978c2ecf20Sopenharmony_ci * DMA transfers are complete. Cache flushing and any other necessary
1988c2ecf20Sopenharmony_ci * preparations before CPU access can begin still need to happen.
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb;
2048c2ecf20Sopenharmony_ci	unsigned long flags;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dcb->poll->lock, flags);
2078c2ecf20Sopenharmony_ci	wake_up_locked_poll(dcb->poll, dcb->active);
2088c2ecf20Sopenharmony_ci	dcb->active = 0;
2098c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dcb->poll->lock, flags);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic __poll_t dma_buf_poll(struct file *file, poll_table *poll)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
2158c2ecf20Sopenharmony_ci	struct dma_resv *resv;
2168c2ecf20Sopenharmony_ci	struct dma_resv_list *fobj;
2178c2ecf20Sopenharmony_ci	struct dma_fence *fence_excl;
2188c2ecf20Sopenharmony_ci	__poll_t events;
2198c2ecf20Sopenharmony_ci	unsigned shared_count, seq;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	dmabuf = file->private_data;
2228c2ecf20Sopenharmony_ci	if (!dmabuf || !dmabuf->resv)
2238c2ecf20Sopenharmony_ci		return EPOLLERR;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	resv = dmabuf->resv;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	poll_wait(file, &dmabuf->poll, poll);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	events = poll_requested_events(poll) & (EPOLLIN | EPOLLOUT);
2308c2ecf20Sopenharmony_ci	if (!events)
2318c2ecf20Sopenharmony_ci		return 0;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciretry:
2348c2ecf20Sopenharmony_ci	seq = read_seqcount_begin(&resv->seq);
2358c2ecf20Sopenharmony_ci	rcu_read_lock();
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	fobj = rcu_dereference(resv->fence);
2388c2ecf20Sopenharmony_ci	if (fobj)
2398c2ecf20Sopenharmony_ci		shared_count = fobj->shared_count;
2408c2ecf20Sopenharmony_ci	else
2418c2ecf20Sopenharmony_ci		shared_count = 0;
2428c2ecf20Sopenharmony_ci	fence_excl = rcu_dereference(resv->fence_excl);
2438c2ecf20Sopenharmony_ci	if (read_seqcount_retry(&resv->seq, seq)) {
2448c2ecf20Sopenharmony_ci		rcu_read_unlock();
2458c2ecf20Sopenharmony_ci		goto retry;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) {
2498c2ecf20Sopenharmony_ci		struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl;
2508c2ecf20Sopenharmony_ci		__poll_t pevents = EPOLLIN;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		if (shared_count == 0)
2538c2ecf20Sopenharmony_ci			pevents |= EPOLLOUT;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		spin_lock_irq(&dmabuf->poll.lock);
2568c2ecf20Sopenharmony_ci		if (dcb->active) {
2578c2ecf20Sopenharmony_ci			dcb->active |= pevents;
2588c2ecf20Sopenharmony_ci			events &= ~pevents;
2598c2ecf20Sopenharmony_ci		} else
2608c2ecf20Sopenharmony_ci			dcb->active = pevents;
2618c2ecf20Sopenharmony_ci		spin_unlock_irq(&dmabuf->poll.lock);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		if (events & pevents) {
2648c2ecf20Sopenharmony_ci			if (!dma_fence_get_rcu(fence_excl)) {
2658c2ecf20Sopenharmony_ci				/* force a recheck */
2668c2ecf20Sopenharmony_ci				events &= ~pevents;
2678c2ecf20Sopenharmony_ci				dma_buf_poll_cb(NULL, &dcb->cb);
2688c2ecf20Sopenharmony_ci			} else if (!dma_fence_add_callback(fence_excl, &dcb->cb,
2698c2ecf20Sopenharmony_ci							   dma_buf_poll_cb)) {
2708c2ecf20Sopenharmony_ci				events &= ~pevents;
2718c2ecf20Sopenharmony_ci				dma_fence_put(fence_excl);
2728c2ecf20Sopenharmony_ci			} else {
2738c2ecf20Sopenharmony_ci				/*
2748c2ecf20Sopenharmony_ci				 * No callback queued, wake up any additional
2758c2ecf20Sopenharmony_ci				 * waiters.
2768c2ecf20Sopenharmony_ci				 */
2778c2ecf20Sopenharmony_ci				dma_fence_put(fence_excl);
2788c2ecf20Sopenharmony_ci				dma_buf_poll_cb(NULL, &dcb->cb);
2798c2ecf20Sopenharmony_ci			}
2808c2ecf20Sopenharmony_ci		}
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if ((events & EPOLLOUT) && shared_count > 0) {
2848c2ecf20Sopenharmony_ci		struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared;
2858c2ecf20Sopenharmony_ci		int i;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		/* Only queue a new callback if no event has fired yet */
2888c2ecf20Sopenharmony_ci		spin_lock_irq(&dmabuf->poll.lock);
2898c2ecf20Sopenharmony_ci		if (dcb->active)
2908c2ecf20Sopenharmony_ci			events &= ~EPOLLOUT;
2918c2ecf20Sopenharmony_ci		else
2928c2ecf20Sopenharmony_ci			dcb->active = EPOLLOUT;
2938c2ecf20Sopenharmony_ci		spin_unlock_irq(&dmabuf->poll.lock);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		if (!(events & EPOLLOUT))
2968c2ecf20Sopenharmony_ci			goto out;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci		for (i = 0; i < shared_count; ++i) {
2998c2ecf20Sopenharmony_ci			struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci			if (!dma_fence_get_rcu(fence)) {
3028c2ecf20Sopenharmony_ci				/*
3038c2ecf20Sopenharmony_ci				 * fence refcount dropped to zero, this means
3048c2ecf20Sopenharmony_ci				 * that fobj has been freed
3058c2ecf20Sopenharmony_ci				 *
3068c2ecf20Sopenharmony_ci				 * call dma_buf_poll_cb and force a recheck!
3078c2ecf20Sopenharmony_ci				 */
3088c2ecf20Sopenharmony_ci				events &= ~EPOLLOUT;
3098c2ecf20Sopenharmony_ci				dma_buf_poll_cb(NULL, &dcb->cb);
3108c2ecf20Sopenharmony_ci				break;
3118c2ecf20Sopenharmony_ci			}
3128c2ecf20Sopenharmony_ci			if (!dma_fence_add_callback(fence, &dcb->cb,
3138c2ecf20Sopenharmony_ci						    dma_buf_poll_cb)) {
3148c2ecf20Sopenharmony_ci				dma_fence_put(fence);
3158c2ecf20Sopenharmony_ci				events &= ~EPOLLOUT;
3168c2ecf20Sopenharmony_ci				break;
3178c2ecf20Sopenharmony_ci			}
3188c2ecf20Sopenharmony_ci			dma_fence_put(fence);
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		/* No callback queued, wake up any additional waiters. */
3228c2ecf20Sopenharmony_ci		if (i == shared_count)
3238c2ecf20Sopenharmony_ci			dma_buf_poll_cb(NULL, &dcb->cb);
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciout:
3278c2ecf20Sopenharmony_ci	rcu_read_unlock();
3288c2ecf20Sopenharmony_ci	return events;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/**
3328c2ecf20Sopenharmony_ci * dma_buf_set_name - Set a name to a specific dma_buf to track the usage.
3338c2ecf20Sopenharmony_ci * The name of the dma-buf buffer can only be set when the dma-buf is not
3348c2ecf20Sopenharmony_ci * attached to any devices. It could theoritically support changing the
3358c2ecf20Sopenharmony_ci * name of the dma-buf if the same piece of memory is used for multiple
3368c2ecf20Sopenharmony_ci * purpose between different devices.
3378c2ecf20Sopenharmony_ci *
3388c2ecf20Sopenharmony_ci * @dmabuf: [in]     dmabuf buffer that will be renamed.
3398c2ecf20Sopenharmony_ci * @buf:    [in]     A piece of userspace memory that contains the name of
3408c2ecf20Sopenharmony_ci *                   the dma-buf.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * Returns 0 on success. If the dma-buf buffer is already attached to
3438c2ecf20Sopenharmony_ci * devices, return -EBUSY.
3448c2ecf20Sopenharmony_ci *
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_cistatic long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
3498c2ecf20Sopenharmony_ci	long ret = 0;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (IS_ERR(name))
3528c2ecf20Sopenharmony_ci		return PTR_ERR(name);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	dma_resv_lock(dmabuf->resv, NULL);
3558c2ecf20Sopenharmony_ci	if (!list_empty(&dmabuf->attachments)) {
3568c2ecf20Sopenharmony_ci		ret = -EBUSY;
3578c2ecf20Sopenharmony_ci		kfree(name);
3588c2ecf20Sopenharmony_ci		goto out_unlock;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	spin_lock(&dmabuf->name_lock);
3618c2ecf20Sopenharmony_ci	kfree(dmabuf->name);
3628c2ecf20Sopenharmony_ci	dmabuf->name = name;
3638c2ecf20Sopenharmony_ci	spin_unlock(&dmabuf->name_lock);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ciout_unlock:
3668c2ecf20Sopenharmony_ci	dma_resv_unlock(dmabuf->resv);
3678c2ecf20Sopenharmony_ci	return ret;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic long dma_buf_ioctl(struct file *file,
3718c2ecf20Sopenharmony_ci			  unsigned int cmd, unsigned long arg)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
3748c2ecf20Sopenharmony_ci	struct dma_buf_sync sync;
3758c2ecf20Sopenharmony_ci	enum dma_data_direction direction;
3768c2ecf20Sopenharmony_ci	int ret;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	dmabuf = file->private_data;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	switch (cmd) {
3818c2ecf20Sopenharmony_ci	case DMA_BUF_IOCTL_SYNC:
3828c2ecf20Sopenharmony_ci		if (copy_from_user(&sync, (void __user *) arg, sizeof(sync)))
3838c2ecf20Sopenharmony_ci			return -EFAULT;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		if (sync.flags & ~DMA_BUF_SYNC_VALID_FLAGS_MASK)
3868c2ecf20Sopenharmony_ci			return -EINVAL;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		switch (sync.flags & DMA_BUF_SYNC_RW) {
3898c2ecf20Sopenharmony_ci		case DMA_BUF_SYNC_READ:
3908c2ecf20Sopenharmony_ci			direction = DMA_FROM_DEVICE;
3918c2ecf20Sopenharmony_ci			break;
3928c2ecf20Sopenharmony_ci		case DMA_BUF_SYNC_WRITE:
3938c2ecf20Sopenharmony_ci			direction = DMA_TO_DEVICE;
3948c2ecf20Sopenharmony_ci			break;
3958c2ecf20Sopenharmony_ci		case DMA_BUF_SYNC_RW:
3968c2ecf20Sopenharmony_ci			direction = DMA_BIDIRECTIONAL;
3978c2ecf20Sopenharmony_ci			break;
3988c2ecf20Sopenharmony_ci		default:
3998c2ecf20Sopenharmony_ci			return -EINVAL;
4008c2ecf20Sopenharmony_ci		}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		if (sync.flags & DMA_BUF_SYNC_END)
4038c2ecf20Sopenharmony_ci			ret = dma_buf_end_cpu_access(dmabuf, direction);
4048c2ecf20Sopenharmony_ci		else
4058c2ecf20Sopenharmony_ci			ret = dma_buf_begin_cpu_access(dmabuf, direction);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		return ret;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	case DMA_BUF_SET_NAME_A:
4108c2ecf20Sopenharmony_ci	case DMA_BUF_SET_NAME_B:
4118c2ecf20Sopenharmony_ci		return dma_buf_set_name(dmabuf, (const char __user *)arg);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	default:
4148c2ecf20Sopenharmony_ci		return -ENOTTY;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void dma_buf_show_fdinfo(struct seq_file *m, struct file *file)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf = file->private_data;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	seq_printf(m, "size:\t%zu\n", dmabuf->size);
4238c2ecf20Sopenharmony_ci	/* Don't count the temporary reference taken inside procfs seq_show */
4248c2ecf20Sopenharmony_ci	seq_printf(m, "count:\t%ld\n", file_count(dmabuf->file) - 1);
4258c2ecf20Sopenharmony_ci	seq_printf(m, "exp_name:\t%s\n", dmabuf->exp_name);
4268c2ecf20Sopenharmony_ci	spin_lock(&dmabuf->name_lock);
4278c2ecf20Sopenharmony_ci	if (dmabuf->name)
4288c2ecf20Sopenharmony_ci		seq_printf(m, "name:\t%s\n", dmabuf->name);
4298c2ecf20Sopenharmony_ci	spin_unlock(&dmabuf->name_lock);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic const struct file_operations dma_buf_fops = {
4338c2ecf20Sopenharmony_ci	.release	= dma_buf_file_release,
4348c2ecf20Sopenharmony_ci	.mmap		= dma_buf_mmap_internal,
4358c2ecf20Sopenharmony_ci	.llseek		= dma_buf_llseek,
4368c2ecf20Sopenharmony_ci	.poll		= dma_buf_poll,
4378c2ecf20Sopenharmony_ci	.unlocked_ioctl	= dma_buf_ioctl,
4388c2ecf20Sopenharmony_ci	.compat_ioctl	= compat_ptr_ioctl,
4398c2ecf20Sopenharmony_ci	.show_fdinfo	= dma_buf_show_fdinfo,
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/*
4438c2ecf20Sopenharmony_ci * is_dma_buf_file - Check if struct file* is associated with dma_buf
4448c2ecf20Sopenharmony_ci */
4458c2ecf20Sopenharmony_cistatic inline int is_dma_buf_file(struct file *file)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	return file->f_op == &dma_buf_fops;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct file *file;
4538c2ecf20Sopenharmony_ci	struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
4568c2ecf20Sopenharmony_ci		return ERR_CAST(inode);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	inode->i_size = dmabuf->size;
4598c2ecf20Sopenharmony_ci	inode_set_bytes(inode, dmabuf->size);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	file = alloc_file_pseudo(inode, dma_buf_mnt, "dmabuf",
4628c2ecf20Sopenharmony_ci				 flags, &dma_buf_fops);
4638c2ecf20Sopenharmony_ci	if (IS_ERR(file))
4648c2ecf20Sopenharmony_ci		goto err_alloc_file;
4658c2ecf20Sopenharmony_ci	file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
4668c2ecf20Sopenharmony_ci	file->private_data = dmabuf;
4678c2ecf20Sopenharmony_ci	file->f_path.dentry->d_fsdata = dmabuf;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return file;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cierr_alloc_file:
4728c2ecf20Sopenharmony_ci	iput(inode);
4738c2ecf20Sopenharmony_ci	return file;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci/**
4778c2ecf20Sopenharmony_ci * DOC: dma buf device access
4788c2ecf20Sopenharmony_ci *
4798c2ecf20Sopenharmony_ci * For device DMA access to a shared DMA buffer the usual sequence of operations
4808c2ecf20Sopenharmony_ci * is fairly simple:
4818c2ecf20Sopenharmony_ci *
4828c2ecf20Sopenharmony_ci * 1. The exporter defines his exporter instance using
4838c2ecf20Sopenharmony_ci *    DEFINE_DMA_BUF_EXPORT_INFO() and calls dma_buf_export() to wrap a private
4848c2ecf20Sopenharmony_ci *    buffer object into a &dma_buf. It then exports that &dma_buf to userspace
4858c2ecf20Sopenharmony_ci *    as a file descriptor by calling dma_buf_fd().
4868c2ecf20Sopenharmony_ci *
4878c2ecf20Sopenharmony_ci * 2. Userspace passes this file-descriptors to all drivers it wants this buffer
4888c2ecf20Sopenharmony_ci *    to share with: First the filedescriptor is converted to a &dma_buf using
4898c2ecf20Sopenharmony_ci *    dma_buf_get(). Then the buffer is attached to the device using
4908c2ecf20Sopenharmony_ci *    dma_buf_attach().
4918c2ecf20Sopenharmony_ci *
4928c2ecf20Sopenharmony_ci *    Up to this stage the exporter is still free to migrate or reallocate the
4938c2ecf20Sopenharmony_ci *    backing storage.
4948c2ecf20Sopenharmony_ci *
4958c2ecf20Sopenharmony_ci * 3. Once the buffer is attached to all devices userspace can initiate DMA
4968c2ecf20Sopenharmony_ci *    access to the shared buffer. In the kernel this is done by calling
4978c2ecf20Sopenharmony_ci *    dma_buf_map_attachment() and dma_buf_unmap_attachment().
4988c2ecf20Sopenharmony_ci *
4998c2ecf20Sopenharmony_ci * 4. Once a driver is done with a shared buffer it needs to call
5008c2ecf20Sopenharmony_ci *    dma_buf_detach() (after cleaning up any mappings) and then release the
5018c2ecf20Sopenharmony_ci *    reference acquired with dma_buf_get by calling dma_buf_put().
5028c2ecf20Sopenharmony_ci *
5038c2ecf20Sopenharmony_ci * For the detailed semantics exporters are expected to implement see
5048c2ecf20Sopenharmony_ci * &dma_buf_ops.
5058c2ecf20Sopenharmony_ci */
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/**
5088c2ecf20Sopenharmony_ci * dma_buf_export - Creates a new dma_buf, and associates an anon file
5098c2ecf20Sopenharmony_ci * with this buffer, so it can be exported.
5108c2ecf20Sopenharmony_ci * Also connect the allocator specific data and ops to the buffer.
5118c2ecf20Sopenharmony_ci * Additionally, provide a name string for exporter; useful in debugging.
5128c2ecf20Sopenharmony_ci *
5138c2ecf20Sopenharmony_ci * @exp_info:	[in]	holds all the export related information provided
5148c2ecf20Sopenharmony_ci *			by the exporter. see &struct dma_buf_export_info
5158c2ecf20Sopenharmony_ci *			for further details.
5168c2ecf20Sopenharmony_ci *
5178c2ecf20Sopenharmony_ci * Returns, on success, a newly created dma_buf object, which wraps the
5188c2ecf20Sopenharmony_ci * supplied private data and operations for dma_buf_ops. On either missing
5198c2ecf20Sopenharmony_ci * ops, or error in allocating struct dma_buf, will return negative error.
5208c2ecf20Sopenharmony_ci *
5218c2ecf20Sopenharmony_ci * For most cases the easiest way to create @exp_info is through the
5228c2ecf20Sopenharmony_ci * %DEFINE_DMA_BUF_EXPORT_INFO macro.
5238c2ecf20Sopenharmony_ci */
5248c2ecf20Sopenharmony_cistruct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf;
5278c2ecf20Sopenharmony_ci	struct dma_resv *resv = exp_info->resv;
5288c2ecf20Sopenharmony_ci	struct file *file;
5298c2ecf20Sopenharmony_ci	size_t alloc_size = sizeof(struct dma_buf);
5308c2ecf20Sopenharmony_ci	int ret;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (!exp_info->resv)
5338c2ecf20Sopenharmony_ci		alloc_size += sizeof(struct dma_resv);
5348c2ecf20Sopenharmony_ci	else
5358c2ecf20Sopenharmony_ci		/* prevent &dma_buf[1] == dma_buf->resv */
5368c2ecf20Sopenharmony_ci		alloc_size += 1;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (WARN_ON(!exp_info->priv
5398c2ecf20Sopenharmony_ci			  || !exp_info->ops
5408c2ecf20Sopenharmony_ci			  || !exp_info->ops->map_dma_buf
5418c2ecf20Sopenharmony_ci			  || !exp_info->ops->unmap_dma_buf
5428c2ecf20Sopenharmony_ci			  || !exp_info->ops->release)) {
5438c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (WARN_ON(exp_info->ops->cache_sgt_mapping &&
5478c2ecf20Sopenharmony_ci		    (exp_info->ops->pin || exp_info->ops->unpin)))
5488c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (WARN_ON(!exp_info->ops->pin != !exp_info->ops->unpin))
5518c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (!try_module_get(exp_info->owner))
5548c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOENT);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	dmabuf = kzalloc(alloc_size, GFP_KERNEL);
5578c2ecf20Sopenharmony_ci	if (!dmabuf) {
5588c2ecf20Sopenharmony_ci		ret = -ENOMEM;
5598c2ecf20Sopenharmony_ci		goto err_module;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	dmabuf->priv = exp_info->priv;
5638c2ecf20Sopenharmony_ci	dmabuf->ops = exp_info->ops;
5648c2ecf20Sopenharmony_ci	dmabuf->size = exp_info->size;
5658c2ecf20Sopenharmony_ci	dmabuf->exp_name = exp_info->exp_name;
5668c2ecf20Sopenharmony_ci	dmabuf->owner = exp_info->owner;
5678c2ecf20Sopenharmony_ci	spin_lock_init(&dmabuf->name_lock);
5688c2ecf20Sopenharmony_ci	init_waitqueue_head(&dmabuf->poll);
5698c2ecf20Sopenharmony_ci	dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll;
5708c2ecf20Sopenharmony_ci	dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (!resv) {
5738c2ecf20Sopenharmony_ci		resv = (struct dma_resv *)&dmabuf[1];
5748c2ecf20Sopenharmony_ci		dma_resv_init(resv);
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci	dmabuf->resv = resv;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	file = dma_buf_getfile(dmabuf, exp_info->flags);
5798c2ecf20Sopenharmony_ci	if (IS_ERR(file)) {
5808c2ecf20Sopenharmony_ci		ret = PTR_ERR(file);
5818c2ecf20Sopenharmony_ci		goto err_dmabuf;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	file->f_mode |= FMODE_LSEEK;
5858c2ecf20Sopenharmony_ci	dmabuf->file = file;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	ret = dma_buf_stats_setup(dmabuf);
5888c2ecf20Sopenharmony_ci	if (ret)
5898c2ecf20Sopenharmony_ci		goto err_sysfs;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	mutex_init(&dmabuf->lock);
5928c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dmabuf->attachments);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	mutex_lock(&db_list.lock);
5958c2ecf20Sopenharmony_ci	list_add(&dmabuf->list_node, &db_list.head);
5968c2ecf20Sopenharmony_ci	mutex_unlock(&db_list.lock);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	init_dma_buf_task_info(dmabuf);
5998c2ecf20Sopenharmony_ci	return dmabuf;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cierr_sysfs:
6028c2ecf20Sopenharmony_ci	/*
6038c2ecf20Sopenharmony_ci	 * Set file->f_path.dentry->d_fsdata to NULL so that when
6048c2ecf20Sopenharmony_ci	 * dma_buf_release() gets invoked by dentry_ops, it exits
6058c2ecf20Sopenharmony_ci	 * early before calling the release() dma_buf op.
6068c2ecf20Sopenharmony_ci	 */
6078c2ecf20Sopenharmony_ci	file->f_path.dentry->d_fsdata = NULL;
6088c2ecf20Sopenharmony_ci	fput(file);
6098c2ecf20Sopenharmony_cierr_dmabuf:
6108c2ecf20Sopenharmony_ci	kfree(dmabuf);
6118c2ecf20Sopenharmony_cierr_module:
6128c2ecf20Sopenharmony_ci	module_put(exp_info->owner);
6138c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_export);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci/**
6188c2ecf20Sopenharmony_ci * dma_buf_fd - returns a file descriptor for the given dma_buf
6198c2ecf20Sopenharmony_ci * @dmabuf:	[in]	pointer to dma_buf for which fd is required.
6208c2ecf20Sopenharmony_ci * @flags:      [in]    flags to give to fd
6218c2ecf20Sopenharmony_ci *
6228c2ecf20Sopenharmony_ci * On success, returns an associated 'fd'. Else, returns error.
6238c2ecf20Sopenharmony_ci */
6248c2ecf20Sopenharmony_ciint dma_buf_fd(struct dma_buf *dmabuf, int flags)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	int fd;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (!dmabuf || !dmabuf->file)
6298c2ecf20Sopenharmony_ci		return -EINVAL;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	fd = get_unused_fd_flags(flags);
6328c2ecf20Sopenharmony_ci	if (fd < 0)
6338c2ecf20Sopenharmony_ci		return fd;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	fd_install(fd, dmabuf->file);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	return fd;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_fd);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci/**
6428c2ecf20Sopenharmony_ci * dma_buf_get - returns the dma_buf structure related to an fd
6438c2ecf20Sopenharmony_ci * @fd:	[in]	fd associated with the dma_buf to be returned
6448c2ecf20Sopenharmony_ci *
6458c2ecf20Sopenharmony_ci * On success, returns the dma_buf structure associated with an fd; uses
6468c2ecf20Sopenharmony_ci * file's refcounting done by fget to increase refcount. returns ERR_PTR
6478c2ecf20Sopenharmony_ci * otherwise.
6488c2ecf20Sopenharmony_ci */
6498c2ecf20Sopenharmony_cistruct dma_buf *dma_buf_get(int fd)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	struct file *file;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	file = fget(fd);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (!file)
6568c2ecf20Sopenharmony_ci		return ERR_PTR(-EBADF);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	if (!is_dma_buf_file(file)) {
6598c2ecf20Sopenharmony_ci		fput(file);
6608c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	return file->private_data;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_get);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci/**
6688c2ecf20Sopenharmony_ci * dma_buf_put - decreases refcount of the buffer
6698c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to reduce refcount of
6708c2ecf20Sopenharmony_ci *
6718c2ecf20Sopenharmony_ci * Uses file's refcounting done implicitly by fput().
6728c2ecf20Sopenharmony_ci *
6738c2ecf20Sopenharmony_ci * If, as a result of this call, the refcount becomes 0, the 'release' file
6748c2ecf20Sopenharmony_ci * operation related to this fd is called. It calls &dma_buf_ops.release vfunc
6758c2ecf20Sopenharmony_ci * in turn, and frees the memory allocated for dmabuf when exported.
6768c2ecf20Sopenharmony_ci */
6778c2ecf20Sopenharmony_civoid dma_buf_put(struct dma_buf *dmabuf)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf || !dmabuf->file))
6808c2ecf20Sopenharmony_ci		return;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	fput(dmabuf->file);
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_put);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci/**
6878c2ecf20Sopenharmony_ci * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list; optionally,
6888c2ecf20Sopenharmony_ci * calls attach() of dma_buf_ops to allow device-specific attach functionality
6898c2ecf20Sopenharmony_ci * @dmabuf:		[in]	buffer to attach device to.
6908c2ecf20Sopenharmony_ci * @dev:		[in]	device to be attached.
6918c2ecf20Sopenharmony_ci * @importer_ops:	[in]	importer operations for the attachment
6928c2ecf20Sopenharmony_ci * @importer_priv:	[in]	importer private pointer for the attachment
6938c2ecf20Sopenharmony_ci *
6948c2ecf20Sopenharmony_ci * Returns struct dma_buf_attachment pointer for this attachment. Attachments
6958c2ecf20Sopenharmony_ci * must be cleaned up by calling dma_buf_detach().
6968c2ecf20Sopenharmony_ci *
6978c2ecf20Sopenharmony_ci * Returns:
6988c2ecf20Sopenharmony_ci *
6998c2ecf20Sopenharmony_ci * A pointer to newly created &dma_buf_attachment on success, or a negative
7008c2ecf20Sopenharmony_ci * error code wrapped into a pointer on failure.
7018c2ecf20Sopenharmony_ci *
7028c2ecf20Sopenharmony_ci * Note that this can fail if the backing storage of @dmabuf is in a place not
7038c2ecf20Sopenharmony_ci * accessible to @dev, and cannot be moved to a more suitable place. This is
7048c2ecf20Sopenharmony_ci * indicated with the error code -EBUSY.
7058c2ecf20Sopenharmony_ci */
7068c2ecf20Sopenharmony_cistruct dma_buf_attachment *
7078c2ecf20Sopenharmony_cidma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
7088c2ecf20Sopenharmony_ci		       const struct dma_buf_attach_ops *importer_ops,
7098c2ecf20Sopenharmony_ci		       void *importer_priv)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct dma_buf_attachment *attach;
7128c2ecf20Sopenharmony_ci	int ret;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf || !dev))
7158c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (WARN_ON(importer_ops && !importer_ops->move_notify))
7188c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	attach = kzalloc(sizeof(*attach), GFP_KERNEL);
7218c2ecf20Sopenharmony_ci	if (!attach)
7228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	attach->dev = dev;
7258c2ecf20Sopenharmony_ci	attach->dmabuf = dmabuf;
7268c2ecf20Sopenharmony_ci	if (importer_ops)
7278c2ecf20Sopenharmony_ci		attach->peer2peer = importer_ops->allow_peer2peer;
7288c2ecf20Sopenharmony_ci	attach->importer_ops = importer_ops;
7298c2ecf20Sopenharmony_ci	attach->importer_priv = importer_priv;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (dmabuf->ops->attach) {
7328c2ecf20Sopenharmony_ci		ret = dmabuf->ops->attach(dmabuf, attach);
7338c2ecf20Sopenharmony_ci		if (ret)
7348c2ecf20Sopenharmony_ci			goto err_attach;
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci	dma_resv_lock(dmabuf->resv, NULL);
7378c2ecf20Sopenharmony_ci	list_add(&attach->node, &dmabuf->attachments);
7388c2ecf20Sopenharmony_ci	dma_resv_unlock(dmabuf->resv);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	/* When either the importer or the exporter can't handle dynamic
7418c2ecf20Sopenharmony_ci	 * mappings we cache the mapping here to avoid issues with the
7428c2ecf20Sopenharmony_ci	 * reservation object lock.
7438c2ecf20Sopenharmony_ci	 */
7448c2ecf20Sopenharmony_ci	if (dma_buf_attachment_is_dynamic(attach) !=
7458c2ecf20Sopenharmony_ci	    dma_buf_is_dynamic(dmabuf)) {
7468c2ecf20Sopenharmony_ci		struct sg_table *sgt;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci		if (dma_buf_is_dynamic(attach->dmabuf)) {
7498c2ecf20Sopenharmony_ci			dma_resv_lock(attach->dmabuf->resv, NULL);
7508c2ecf20Sopenharmony_ci			ret = dma_buf_pin(attach);
7518c2ecf20Sopenharmony_ci			if (ret)
7528c2ecf20Sopenharmony_ci				goto err_unlock;
7538c2ecf20Sopenharmony_ci		}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		sgt = dmabuf->ops->map_dma_buf(attach, DMA_BIDIRECTIONAL);
7568c2ecf20Sopenharmony_ci		if (!sgt)
7578c2ecf20Sopenharmony_ci			sgt = ERR_PTR(-ENOMEM);
7588c2ecf20Sopenharmony_ci		if (IS_ERR(sgt)) {
7598c2ecf20Sopenharmony_ci			ret = PTR_ERR(sgt);
7608c2ecf20Sopenharmony_ci			goto err_unpin;
7618c2ecf20Sopenharmony_ci		}
7628c2ecf20Sopenharmony_ci		if (dma_buf_is_dynamic(attach->dmabuf))
7638c2ecf20Sopenharmony_ci			dma_resv_unlock(attach->dmabuf->resv);
7648c2ecf20Sopenharmony_ci		attach->sgt = sgt;
7658c2ecf20Sopenharmony_ci		attach->dir = DMA_BIDIRECTIONAL;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	return attach;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cierr_attach:
7718c2ecf20Sopenharmony_ci	kfree(attach);
7728c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cierr_unpin:
7758c2ecf20Sopenharmony_ci	if (dma_buf_is_dynamic(attach->dmabuf))
7768c2ecf20Sopenharmony_ci		dma_buf_unpin(attach);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_cierr_unlock:
7798c2ecf20Sopenharmony_ci	if (dma_buf_is_dynamic(attach->dmabuf))
7808c2ecf20Sopenharmony_ci		dma_resv_unlock(attach->dmabuf->resv);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	dma_buf_detach(dmabuf, attach);
7838c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_dynamic_attach);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci/**
7888c2ecf20Sopenharmony_ci * dma_buf_attach - Wrapper for dma_buf_dynamic_attach
7898c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to attach device to.
7908c2ecf20Sopenharmony_ci * @dev:	[in]	device to be attached.
7918c2ecf20Sopenharmony_ci *
7928c2ecf20Sopenharmony_ci * Wrapper to call dma_buf_dynamic_attach() for drivers which still use a static
7938c2ecf20Sopenharmony_ci * mapping.
7948c2ecf20Sopenharmony_ci */
7958c2ecf20Sopenharmony_cistruct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
7968c2ecf20Sopenharmony_ci					  struct device *dev)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	return dma_buf_dynamic_attach(dmabuf, dev, NULL, NULL);
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_attach);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci/**
8038c2ecf20Sopenharmony_ci * dma_buf_detach - Remove the given attachment from dmabuf's attachments list;
8048c2ecf20Sopenharmony_ci * optionally calls detach() of dma_buf_ops for device-specific detach
8058c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to detach from.
8068c2ecf20Sopenharmony_ci * @attach:	[in]	attachment to be detached; is free'd after this call.
8078c2ecf20Sopenharmony_ci *
8088c2ecf20Sopenharmony_ci * Clean up a device attachment obtained by calling dma_buf_attach().
8098c2ecf20Sopenharmony_ci */
8108c2ecf20Sopenharmony_civoid dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf || !attach))
8138c2ecf20Sopenharmony_ci		return;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (attach->sgt) {
8168c2ecf20Sopenharmony_ci		if (dma_buf_is_dynamic(attach->dmabuf))
8178c2ecf20Sopenharmony_ci			dma_resv_lock(attach->dmabuf->resv, NULL);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		dmabuf->ops->unmap_dma_buf(attach, attach->sgt, attach->dir);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		if (dma_buf_is_dynamic(attach->dmabuf)) {
8228c2ecf20Sopenharmony_ci			dma_buf_unpin(attach);
8238c2ecf20Sopenharmony_ci			dma_resv_unlock(attach->dmabuf->resv);
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	dma_resv_lock(dmabuf->resv, NULL);
8288c2ecf20Sopenharmony_ci	list_del(&attach->node);
8298c2ecf20Sopenharmony_ci	dma_resv_unlock(dmabuf->resv);
8308c2ecf20Sopenharmony_ci	if (dmabuf->ops->detach)
8318c2ecf20Sopenharmony_ci		dmabuf->ops->detach(dmabuf, attach);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	kfree(attach);
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_detach);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci/**
8388c2ecf20Sopenharmony_ci * dma_buf_pin - Lock down the DMA-buf
8398c2ecf20Sopenharmony_ci *
8408c2ecf20Sopenharmony_ci * @attach:	[in]	attachment which should be pinned
8418c2ecf20Sopenharmony_ci *
8428c2ecf20Sopenharmony_ci * Returns:
8438c2ecf20Sopenharmony_ci * 0 on success, negative error code on failure.
8448c2ecf20Sopenharmony_ci */
8458c2ecf20Sopenharmony_ciint dma_buf_pin(struct dma_buf_attachment *attach)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf = attach->dmabuf;
8488c2ecf20Sopenharmony_ci	int ret = 0;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	dma_resv_assert_held(dmabuf->resv);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (dmabuf->ops->pin)
8538c2ecf20Sopenharmony_ci		ret = dmabuf->ops->pin(attach);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return ret;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_pin);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci/**
8608c2ecf20Sopenharmony_ci * dma_buf_unpin - Remove lock from DMA-buf
8618c2ecf20Sopenharmony_ci *
8628c2ecf20Sopenharmony_ci * @attach:	[in]	attachment which should be unpinned
8638c2ecf20Sopenharmony_ci */
8648c2ecf20Sopenharmony_civoid dma_buf_unpin(struct dma_buf_attachment *attach)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	struct dma_buf *dmabuf = attach->dmabuf;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	dma_resv_assert_held(dmabuf->resv);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	if (dmabuf->ops->unpin)
8718c2ecf20Sopenharmony_ci		dmabuf->ops->unpin(attach);
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_unpin);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci/**
8768c2ecf20Sopenharmony_ci * dma_buf_map_attachment - Returns the scatterlist table of the attachment;
8778c2ecf20Sopenharmony_ci * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the
8788c2ecf20Sopenharmony_ci * dma_buf_ops.
8798c2ecf20Sopenharmony_ci * @attach:	[in]	attachment whose scatterlist is to be returned
8808c2ecf20Sopenharmony_ci * @direction:	[in]	direction of DMA transfer
8818c2ecf20Sopenharmony_ci *
8828c2ecf20Sopenharmony_ci * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR
8838c2ecf20Sopenharmony_ci * on error. May return -EINTR if it is interrupted by a signal.
8848c2ecf20Sopenharmony_ci *
8858c2ecf20Sopenharmony_ci * A mapping must be unmapped by using dma_buf_unmap_attachment(). Note that
8868c2ecf20Sopenharmony_ci * the underlying backing storage is pinned for as long as a mapping exists,
8878c2ecf20Sopenharmony_ci * therefore users/importers should not hold onto a mapping for undue amounts of
8888c2ecf20Sopenharmony_ci * time.
8898c2ecf20Sopenharmony_ci */
8908c2ecf20Sopenharmony_cistruct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
8918c2ecf20Sopenharmony_ci					enum dma_data_direction direction)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	struct sg_table *sg_table;
8948c2ecf20Sopenharmony_ci	int r;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	might_sleep();
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (WARN_ON(!attach || !attach->dmabuf))
8998c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (dma_buf_attachment_is_dynamic(attach))
9028c2ecf20Sopenharmony_ci		dma_resv_assert_held(attach->dmabuf->resv);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	if (attach->sgt) {
9058c2ecf20Sopenharmony_ci		/*
9068c2ecf20Sopenharmony_ci		 * Two mappings with different directions for the same
9078c2ecf20Sopenharmony_ci		 * attachment are not allowed.
9088c2ecf20Sopenharmony_ci		 */
9098c2ecf20Sopenharmony_ci		if (attach->dir != direction &&
9108c2ecf20Sopenharmony_ci		    attach->dir != DMA_BIDIRECTIONAL)
9118c2ecf20Sopenharmony_ci			return ERR_PTR(-EBUSY);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci		return attach->sgt;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (dma_buf_is_dynamic(attach->dmabuf)) {
9178c2ecf20Sopenharmony_ci		dma_resv_assert_held(attach->dmabuf->resv);
9188c2ecf20Sopenharmony_ci		if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) {
9198c2ecf20Sopenharmony_ci			r = dma_buf_pin(attach);
9208c2ecf20Sopenharmony_ci			if (r)
9218c2ecf20Sopenharmony_ci				return ERR_PTR(r);
9228c2ecf20Sopenharmony_ci		}
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
9268c2ecf20Sopenharmony_ci	if (!sg_table)
9278c2ecf20Sopenharmony_ci		sg_table = ERR_PTR(-ENOMEM);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	if (IS_ERR(sg_table) && dma_buf_is_dynamic(attach->dmabuf) &&
9308c2ecf20Sopenharmony_ci	     !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY))
9318c2ecf20Sopenharmony_ci		dma_buf_unpin(attach);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	if (!IS_ERR(sg_table) && attach->dmabuf->ops->cache_sgt_mapping) {
9348c2ecf20Sopenharmony_ci		attach->sgt = sg_table;
9358c2ecf20Sopenharmony_ci		attach->dir = direction;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	return sg_table;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_map_attachment);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci/**
9438c2ecf20Sopenharmony_ci * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might
9448c2ecf20Sopenharmony_ci * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of
9458c2ecf20Sopenharmony_ci * dma_buf_ops.
9468c2ecf20Sopenharmony_ci * @attach:	[in]	attachment to unmap buffer from
9478c2ecf20Sopenharmony_ci * @sg_table:	[in]	scatterlist info of the buffer to unmap
9488c2ecf20Sopenharmony_ci * @direction:  [in]    direction of DMA transfer
9498c2ecf20Sopenharmony_ci *
9508c2ecf20Sopenharmony_ci * This unmaps a DMA mapping for @attached obtained by dma_buf_map_attachment().
9518c2ecf20Sopenharmony_ci */
9528c2ecf20Sopenharmony_civoid dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
9538c2ecf20Sopenharmony_ci				struct sg_table *sg_table,
9548c2ecf20Sopenharmony_ci				enum dma_data_direction direction)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	might_sleep();
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
9598c2ecf20Sopenharmony_ci		return;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (dma_buf_attachment_is_dynamic(attach))
9628c2ecf20Sopenharmony_ci		dma_resv_assert_held(attach->dmabuf->resv);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (attach->sgt == sg_table)
9658c2ecf20Sopenharmony_ci		return;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (dma_buf_is_dynamic(attach->dmabuf))
9688c2ecf20Sopenharmony_ci		dma_resv_assert_held(attach->dmabuf->resv);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	if (dma_buf_is_dynamic(attach->dmabuf) &&
9738c2ecf20Sopenharmony_ci	    !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY))
9748c2ecf20Sopenharmony_ci		dma_buf_unpin(attach);
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci/**
9798c2ecf20Sopenharmony_ci * dma_buf_move_notify - notify attachments that DMA-buf is moving
9808c2ecf20Sopenharmony_ci *
9818c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer which is moving
9828c2ecf20Sopenharmony_ci *
9838c2ecf20Sopenharmony_ci * Informs all attachmenst that they need to destroy and recreated all their
9848c2ecf20Sopenharmony_ci * mappings.
9858c2ecf20Sopenharmony_ci */
9868c2ecf20Sopenharmony_civoid dma_buf_move_notify(struct dma_buf *dmabuf)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	struct dma_buf_attachment *attach;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	dma_resv_assert_held(dmabuf->resv);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	list_for_each_entry(attach, &dmabuf->attachments, node)
9938c2ecf20Sopenharmony_ci		if (attach->importer_ops)
9948c2ecf20Sopenharmony_ci			attach->importer_ops->move_notify(attach);
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_move_notify);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci/**
9998c2ecf20Sopenharmony_ci * DOC: cpu access
10008c2ecf20Sopenharmony_ci *
10018c2ecf20Sopenharmony_ci * There are mutliple reasons for supporting CPU access to a dma buffer object:
10028c2ecf20Sopenharmony_ci *
10038c2ecf20Sopenharmony_ci * - Fallback operations in the kernel, for example when a device is connected
10048c2ecf20Sopenharmony_ci *   over USB and the kernel needs to shuffle the data around first before
10058c2ecf20Sopenharmony_ci *   sending it away. Cache coherency is handled by braketing any transactions
10068c2ecf20Sopenharmony_ci *   with calls to dma_buf_begin_cpu_access() and dma_buf_end_cpu_access()
10078c2ecf20Sopenharmony_ci *   access.
10088c2ecf20Sopenharmony_ci *
10098c2ecf20Sopenharmony_ci *   Since for most kernel internal dma-buf accesses need the entire buffer, a
10108c2ecf20Sopenharmony_ci *   vmap interface is introduced. Note that on very old 32-bit architectures
10118c2ecf20Sopenharmony_ci *   vmalloc space might be limited and result in vmap calls failing.
10128c2ecf20Sopenharmony_ci *
10138c2ecf20Sopenharmony_ci *   Interfaces::
10148c2ecf20Sopenharmony_ci *      void \*dma_buf_vmap(struct dma_buf \*dmabuf)
10158c2ecf20Sopenharmony_ci *      void dma_buf_vunmap(struct dma_buf \*dmabuf, void \*vaddr)
10168c2ecf20Sopenharmony_ci *
10178c2ecf20Sopenharmony_ci *   The vmap call can fail if there is no vmap support in the exporter, or if
10188c2ecf20Sopenharmony_ci *   it runs out of vmalloc space. Fallback to kmap should be implemented. Note
10198c2ecf20Sopenharmony_ci *   that the dma-buf layer keeps a reference count for all vmap access and
10208c2ecf20Sopenharmony_ci *   calls down into the exporter's vmap function only when no vmapping exists,
10218c2ecf20Sopenharmony_ci *   and only unmaps it once. Protection against concurrent vmap/vunmap calls is
10228c2ecf20Sopenharmony_ci *   provided by taking the dma_buf->lock mutex.
10238c2ecf20Sopenharmony_ci *
10248c2ecf20Sopenharmony_ci * - For full compatibility on the importer side with existing userspace
10258c2ecf20Sopenharmony_ci *   interfaces, which might already support mmap'ing buffers. This is needed in
10268c2ecf20Sopenharmony_ci *   many processing pipelines (e.g. feeding a software rendered image into a
10278c2ecf20Sopenharmony_ci *   hardware pipeline, thumbnail creation, snapshots, ...). Also, Android's ION
10288c2ecf20Sopenharmony_ci *   framework already supported this and for DMA buffer file descriptors to
10298c2ecf20Sopenharmony_ci *   replace ION buffers mmap support was needed.
10308c2ecf20Sopenharmony_ci *
10318c2ecf20Sopenharmony_ci *   There is no special interfaces, userspace simply calls mmap on the dma-buf
10328c2ecf20Sopenharmony_ci *   fd. But like for CPU access there's a need to braket the actual access,
10338c2ecf20Sopenharmony_ci *   which is handled by the ioctl (DMA_BUF_IOCTL_SYNC). Note that
10348c2ecf20Sopenharmony_ci *   DMA_BUF_IOCTL_SYNC can fail with -EAGAIN or -EINTR, in which case it must
10358c2ecf20Sopenharmony_ci *   be restarted.
10368c2ecf20Sopenharmony_ci *
10378c2ecf20Sopenharmony_ci *   Some systems might need some sort of cache coherency management e.g. when
10388c2ecf20Sopenharmony_ci *   CPU and GPU domains are being accessed through dma-buf at the same time.
10398c2ecf20Sopenharmony_ci *   To circumvent this problem there are begin/end coherency markers, that
10408c2ecf20Sopenharmony_ci *   forward directly to existing dma-buf device drivers vfunc hooks. Userspace
10418c2ecf20Sopenharmony_ci *   can make use of those markers through the DMA_BUF_IOCTL_SYNC ioctl. The
10428c2ecf20Sopenharmony_ci *   sequence would be used like following:
10438c2ecf20Sopenharmony_ci *
10448c2ecf20Sopenharmony_ci *     - mmap dma-buf fd
10458c2ecf20Sopenharmony_ci *     - for each drawing/upload cycle in CPU 1. SYNC_START ioctl, 2. read/write
10468c2ecf20Sopenharmony_ci *       to mmap area 3. SYNC_END ioctl. This can be repeated as often as you
10478c2ecf20Sopenharmony_ci *       want (with the new data being consumed by say the GPU or the scanout
10488c2ecf20Sopenharmony_ci *       device)
10498c2ecf20Sopenharmony_ci *     - munmap once you don't need the buffer any more
10508c2ecf20Sopenharmony_ci *
10518c2ecf20Sopenharmony_ci *    For correctness and optimal performance, it is always required to use
10528c2ecf20Sopenharmony_ci *    SYNC_START and SYNC_END before and after, respectively, when accessing the
10538c2ecf20Sopenharmony_ci *    mapped address. Userspace cannot rely on coherent access, even when there
10548c2ecf20Sopenharmony_ci *    are systems where it just works without calling these ioctls.
10558c2ecf20Sopenharmony_ci *
10568c2ecf20Sopenharmony_ci * - And as a CPU fallback in userspace processing pipelines.
10578c2ecf20Sopenharmony_ci *
10588c2ecf20Sopenharmony_ci *   Similar to the motivation for kernel cpu access it is again important that
10598c2ecf20Sopenharmony_ci *   the userspace code of a given importing subsystem can use the same
10608c2ecf20Sopenharmony_ci *   interfaces with a imported dma-buf buffer object as with a native buffer
10618c2ecf20Sopenharmony_ci *   object. This is especially important for drm where the userspace part of
10628c2ecf20Sopenharmony_ci *   contemporary OpenGL, X, and other drivers is huge, and reworking them to
10638c2ecf20Sopenharmony_ci *   use a different way to mmap a buffer rather invasive.
10648c2ecf20Sopenharmony_ci *
10658c2ecf20Sopenharmony_ci *   The assumption in the current dma-buf interfaces is that redirecting the
10668c2ecf20Sopenharmony_ci *   initial mmap is all that's needed. A survey of some of the existing
10678c2ecf20Sopenharmony_ci *   subsystems shows that no driver seems to do any nefarious thing like
10688c2ecf20Sopenharmony_ci *   syncing up with outstanding asynchronous processing on the device or
10698c2ecf20Sopenharmony_ci *   allocating special resources at fault time. So hopefully this is good
10708c2ecf20Sopenharmony_ci *   enough, since adding interfaces to intercept pagefaults and allow pte
10718c2ecf20Sopenharmony_ci *   shootdowns would increase the complexity quite a bit.
10728c2ecf20Sopenharmony_ci *
10738c2ecf20Sopenharmony_ci *   Interface::
10748c2ecf20Sopenharmony_ci *      int dma_buf_mmap(struct dma_buf \*, struct vm_area_struct \*,
10758c2ecf20Sopenharmony_ci *		       unsigned long);
10768c2ecf20Sopenharmony_ci *
10778c2ecf20Sopenharmony_ci *   If the importing subsystem simply provides a special-purpose mmap call to
10788c2ecf20Sopenharmony_ci *   set up a mapping in userspace, calling do_mmap with dma_buf->file will
10798c2ecf20Sopenharmony_ci *   equally achieve that for a dma-buf object.
10808c2ecf20Sopenharmony_ci */
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
10838c2ecf20Sopenharmony_ci				      enum dma_data_direction direction)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	bool write = (direction == DMA_BIDIRECTIONAL ||
10868c2ecf20Sopenharmony_ci		      direction == DMA_TO_DEVICE);
10878c2ecf20Sopenharmony_ci	struct dma_resv *resv = dmabuf->resv;
10888c2ecf20Sopenharmony_ci	long ret;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	/* Wait on any implicit rendering fences */
10918c2ecf20Sopenharmony_ci	ret = dma_resv_wait_timeout_rcu(resv, write, true,
10928c2ecf20Sopenharmony_ci						  MAX_SCHEDULE_TIMEOUT);
10938c2ecf20Sopenharmony_ci	if (ret < 0)
10948c2ecf20Sopenharmony_ci		return ret;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	return 0;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci/**
11008c2ecf20Sopenharmony_ci * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
11018c2ecf20Sopenharmony_ci * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
11028c2ecf20Sopenharmony_ci * preparations. Coherency is only guaranteed in the specified range for the
11038c2ecf20Sopenharmony_ci * specified access direction.
11048c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to prepare cpu access for.
11058c2ecf20Sopenharmony_ci * @direction:	[in]	length of range for cpu access.
11068c2ecf20Sopenharmony_ci *
11078c2ecf20Sopenharmony_ci * After the cpu access is complete the caller should call
11088c2ecf20Sopenharmony_ci * dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is
11098c2ecf20Sopenharmony_ci * it guaranteed to be coherent with other DMA access.
11108c2ecf20Sopenharmony_ci *
11118c2ecf20Sopenharmony_ci * Can return negative error values, returns 0 on success.
11128c2ecf20Sopenharmony_ci */
11138c2ecf20Sopenharmony_ciint dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
11148c2ecf20Sopenharmony_ci			     enum dma_data_direction direction)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	int ret = 0;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf))
11198c2ecf20Sopenharmony_ci		return -EINVAL;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	if (dmabuf->ops->begin_cpu_access)
11228c2ecf20Sopenharmony_ci		ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	/* Ensure that all fences are waited upon - but we first allow
11258c2ecf20Sopenharmony_ci	 * the native handler the chance to do so more efficiently if it
11268c2ecf20Sopenharmony_ci	 * chooses. A double invocation here will be reasonably cheap no-op.
11278c2ecf20Sopenharmony_ci	 */
11288c2ecf20Sopenharmony_ci	if (ret == 0)
11298c2ecf20Sopenharmony_ci		ret = __dma_buf_begin_cpu_access(dmabuf, direction);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	return ret;
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci/**
11368c2ecf20Sopenharmony_ci * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the
11378c2ecf20Sopenharmony_ci * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
11388c2ecf20Sopenharmony_ci * actions. Coherency is only guaranteed in the specified range for the
11398c2ecf20Sopenharmony_ci * specified access direction.
11408c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to complete cpu access for.
11418c2ecf20Sopenharmony_ci * @direction:	[in]	length of range for cpu access.
11428c2ecf20Sopenharmony_ci *
11438c2ecf20Sopenharmony_ci * This terminates CPU access started with dma_buf_begin_cpu_access().
11448c2ecf20Sopenharmony_ci *
11458c2ecf20Sopenharmony_ci * Can return negative error values, returns 0 on success.
11468c2ecf20Sopenharmony_ci */
11478c2ecf20Sopenharmony_ciint dma_buf_end_cpu_access(struct dma_buf *dmabuf,
11488c2ecf20Sopenharmony_ci			   enum dma_data_direction direction)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	int ret = 0;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	WARN_ON(!dmabuf);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (dmabuf->ops->end_cpu_access)
11558c2ecf20Sopenharmony_ci		ret = dmabuf->ops->end_cpu_access(dmabuf, direction);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	return ret;
11588c2ecf20Sopenharmony_ci}
11598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci/**
11638c2ecf20Sopenharmony_ci * dma_buf_mmap - Setup up a userspace mmap with the given vma
11648c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer that should back the vma
11658c2ecf20Sopenharmony_ci * @vma:	[in]	vma for the mmap
11668c2ecf20Sopenharmony_ci * @pgoff:	[in]	offset in pages where this mmap should start within the
11678c2ecf20Sopenharmony_ci *			dma-buf buffer.
11688c2ecf20Sopenharmony_ci *
11698c2ecf20Sopenharmony_ci * This function adjusts the passed in vma so that it points at the file of the
11708c2ecf20Sopenharmony_ci * dma_buf operation. It also adjusts the starting pgoff and does bounds
11718c2ecf20Sopenharmony_ci * checking on the size of the vma. Then it calls the exporters mmap function to
11728c2ecf20Sopenharmony_ci * set up the mapping.
11738c2ecf20Sopenharmony_ci *
11748c2ecf20Sopenharmony_ci * Can return negative error values, returns 0 on success.
11758c2ecf20Sopenharmony_ci */
11768c2ecf20Sopenharmony_ciint dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
11778c2ecf20Sopenharmony_ci		 unsigned long pgoff)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	struct file *oldfile;
11808c2ecf20Sopenharmony_ci	int ret;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf || !vma))
11838c2ecf20Sopenharmony_ci		return -EINVAL;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	/* check if buffer supports mmap */
11868c2ecf20Sopenharmony_ci	if (!dmabuf->ops->mmap)
11878c2ecf20Sopenharmony_ci		return -EINVAL;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	/* check for offset overflow */
11908c2ecf20Sopenharmony_ci	if (pgoff + vma_pages(vma) < pgoff)
11918c2ecf20Sopenharmony_ci		return -EOVERFLOW;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	/* check for overflowing the buffer's size */
11948c2ecf20Sopenharmony_ci	if (pgoff + vma_pages(vma) >
11958c2ecf20Sopenharmony_ci	    dmabuf->size >> PAGE_SHIFT)
11968c2ecf20Sopenharmony_ci		return -EINVAL;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	/* readjust the vma */
11998c2ecf20Sopenharmony_ci	get_file(dmabuf->file);
12008c2ecf20Sopenharmony_ci	oldfile = vma->vm_file;
12018c2ecf20Sopenharmony_ci	vma->vm_file = dmabuf->file;
12028c2ecf20Sopenharmony_ci	vma->vm_pgoff = pgoff;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	ret = dmabuf->ops->mmap(dmabuf, vma);
12058c2ecf20Sopenharmony_ci	if (ret) {
12068c2ecf20Sopenharmony_ci		/* restore old parameters on failure */
12078c2ecf20Sopenharmony_ci		vma->vm_file = oldfile;
12088c2ecf20Sopenharmony_ci		fput(dmabuf->file);
12098c2ecf20Sopenharmony_ci	} else {
12108c2ecf20Sopenharmony_ci		if (oldfile)
12118c2ecf20Sopenharmony_ci			fput(oldfile);
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci	return ret;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci}
12168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_mmap);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci/**
12198c2ecf20Sopenharmony_ci * dma_buf_vmap - Create virtual mapping for the buffer object into kernel
12208c2ecf20Sopenharmony_ci * address space. Same restrictions as for vmap and friends apply.
12218c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to vmap
12228c2ecf20Sopenharmony_ci *
12238c2ecf20Sopenharmony_ci * This call may fail due to lack of virtual mapping address space.
12248c2ecf20Sopenharmony_ci * These calls are optional in drivers. The intended use for them
12258c2ecf20Sopenharmony_ci * is for mapping objects linear in kernel space for high use objects.
12268c2ecf20Sopenharmony_ci * Please attempt to use kmap/kunmap before thinking about these interfaces.
12278c2ecf20Sopenharmony_ci *
12288c2ecf20Sopenharmony_ci * Returns NULL on error.
12298c2ecf20Sopenharmony_ci */
12308c2ecf20Sopenharmony_civoid *dma_buf_vmap(struct dma_buf *dmabuf)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	void *ptr;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf))
12358c2ecf20Sopenharmony_ci		return NULL;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (!dmabuf->ops->vmap)
12388c2ecf20Sopenharmony_ci		return NULL;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	mutex_lock(&dmabuf->lock);
12418c2ecf20Sopenharmony_ci	if (dmabuf->vmapping_counter) {
12428c2ecf20Sopenharmony_ci		dmabuf->vmapping_counter++;
12438c2ecf20Sopenharmony_ci		BUG_ON(!dmabuf->vmap_ptr);
12448c2ecf20Sopenharmony_ci		ptr = dmabuf->vmap_ptr;
12458c2ecf20Sopenharmony_ci		goto out_unlock;
12468c2ecf20Sopenharmony_ci	}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	BUG_ON(dmabuf->vmap_ptr);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	ptr = dmabuf->ops->vmap(dmabuf);
12518c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(IS_ERR(ptr)))
12528c2ecf20Sopenharmony_ci		ptr = NULL;
12538c2ecf20Sopenharmony_ci	if (!ptr)
12548c2ecf20Sopenharmony_ci		goto out_unlock;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	dmabuf->vmap_ptr = ptr;
12578c2ecf20Sopenharmony_ci	dmabuf->vmapping_counter = 1;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ciout_unlock:
12608c2ecf20Sopenharmony_ci	mutex_unlock(&dmabuf->lock);
12618c2ecf20Sopenharmony_ci	return ptr;
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_vmap);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci/**
12668c2ecf20Sopenharmony_ci * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap.
12678c2ecf20Sopenharmony_ci * @dmabuf:	[in]	buffer to vunmap
12688c2ecf20Sopenharmony_ci * @vaddr:	[in]	vmap to vunmap
12698c2ecf20Sopenharmony_ci */
12708c2ecf20Sopenharmony_civoid dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	if (WARN_ON(!dmabuf))
12738c2ecf20Sopenharmony_ci		return;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	BUG_ON(!dmabuf->vmap_ptr);
12768c2ecf20Sopenharmony_ci	BUG_ON(dmabuf->vmapping_counter == 0);
12778c2ecf20Sopenharmony_ci	BUG_ON(dmabuf->vmap_ptr != vaddr);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	mutex_lock(&dmabuf->lock);
12808c2ecf20Sopenharmony_ci	if (--dmabuf->vmapping_counter == 0) {
12818c2ecf20Sopenharmony_ci		if (dmabuf->ops->vunmap)
12828c2ecf20Sopenharmony_ci			dmabuf->ops->vunmap(dmabuf, vaddr);
12838c2ecf20Sopenharmony_ci		dmabuf->vmap_ptr = NULL;
12848c2ecf20Sopenharmony_ci	}
12858c2ecf20Sopenharmony_ci	mutex_unlock(&dmabuf->lock);
12868c2ecf20Sopenharmony_ci}
12878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_vunmap);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
12908c2ecf20Sopenharmony_cistatic int dma_buf_debug_show(struct seq_file *s, void *unused)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	int ret;
12938c2ecf20Sopenharmony_ci	struct dma_buf *buf_obj;
12948c2ecf20Sopenharmony_ci	struct dma_buf_attachment *attach_obj;
12958c2ecf20Sopenharmony_ci	struct dma_resv *robj;
12968c2ecf20Sopenharmony_ci	struct dma_resv_list *fobj;
12978c2ecf20Sopenharmony_ci	struct dma_fence *fence;
12988c2ecf20Sopenharmony_ci	unsigned seq;
12998c2ecf20Sopenharmony_ci	int count = 0, attach_count, shared_count, i;
13008c2ecf20Sopenharmony_ci	size_t size = 0;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&db_list.lock);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	if (ret)
13058c2ecf20Sopenharmony_ci		return ret;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	seq_puts(s, "\nDma-buf Objects:\n");
13088c2ecf20Sopenharmony_ci	seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\t"
13098c2ecf20Sopenharmony_ci		   "%-16s\t%-16s\t%-16s\n",
13108c2ecf20Sopenharmony_ci		   "size", "flags", "mode", "count", "ino",
13118c2ecf20Sopenharmony_ci		   "buf_name", "exp_pid",  "exp_task_comm");
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	list_for_each_entry(buf_obj, &db_list.head, list_node) {
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		ret = dma_resv_lock_interruptible(buf_obj->resv, NULL);
13168c2ecf20Sopenharmony_ci		if (ret)
13178c2ecf20Sopenharmony_ci			goto error_unlock;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci		seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\t"
13208c2ecf20Sopenharmony_ci			   "%-16d\t%-16s\n",
13218c2ecf20Sopenharmony_ci				buf_obj->size,
13228c2ecf20Sopenharmony_ci				buf_obj->file->f_flags, buf_obj->file->f_mode,
13238c2ecf20Sopenharmony_ci				file_count(buf_obj->file),
13248c2ecf20Sopenharmony_ci				buf_obj->exp_name,
13258c2ecf20Sopenharmony_ci				file_inode(buf_obj->file)->i_ino,
13268c2ecf20Sopenharmony_ci				buf_obj->name ?: "NULL",
13278c2ecf20Sopenharmony_ci				dma_buf_exp_pid(buf_obj),
13288c2ecf20Sopenharmony_ci				dma_buf_exp_task_comm(buf_obj) ?: "NULL");
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci		robj = buf_obj->resv;
13318c2ecf20Sopenharmony_ci		while (true) {
13328c2ecf20Sopenharmony_ci			seq = read_seqcount_begin(&robj->seq);
13338c2ecf20Sopenharmony_ci			rcu_read_lock();
13348c2ecf20Sopenharmony_ci			fobj = rcu_dereference(robj->fence);
13358c2ecf20Sopenharmony_ci			shared_count = fobj ? fobj->shared_count : 0;
13368c2ecf20Sopenharmony_ci			fence = rcu_dereference(robj->fence_excl);
13378c2ecf20Sopenharmony_ci			if (!read_seqcount_retry(&robj->seq, seq))
13388c2ecf20Sopenharmony_ci				break;
13398c2ecf20Sopenharmony_ci			rcu_read_unlock();
13408c2ecf20Sopenharmony_ci		}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		if (fence)
13438c2ecf20Sopenharmony_ci			seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n",
13448c2ecf20Sopenharmony_ci				   fence->ops->get_driver_name(fence),
13458c2ecf20Sopenharmony_ci				   fence->ops->get_timeline_name(fence),
13468c2ecf20Sopenharmony_ci				   dma_fence_is_signaled(fence) ? "" : "un");
13478c2ecf20Sopenharmony_ci		for (i = 0; i < shared_count; i++) {
13488c2ecf20Sopenharmony_ci			fence = rcu_dereference(fobj->shared[i]);
13498c2ecf20Sopenharmony_ci			if (!dma_fence_get_rcu(fence))
13508c2ecf20Sopenharmony_ci				continue;
13518c2ecf20Sopenharmony_ci			seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
13528c2ecf20Sopenharmony_ci				   fence->ops->get_driver_name(fence),
13538c2ecf20Sopenharmony_ci				   fence->ops->get_timeline_name(fence),
13548c2ecf20Sopenharmony_ci				   dma_fence_is_signaled(fence) ? "" : "un");
13558c2ecf20Sopenharmony_ci			dma_fence_put(fence);
13568c2ecf20Sopenharmony_ci		}
13578c2ecf20Sopenharmony_ci		rcu_read_unlock();
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci		seq_puts(s, "\tAttached Devices:\n");
13608c2ecf20Sopenharmony_ci		attach_count = 0;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci		list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
13638c2ecf20Sopenharmony_ci			seq_printf(s, "\t%s\n", dev_name(attach_obj->dev));
13648c2ecf20Sopenharmony_ci			attach_count++;
13658c2ecf20Sopenharmony_ci		}
13668c2ecf20Sopenharmony_ci		dma_resv_unlock(buf_obj->resv);
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci		seq_printf(s, "Total %d devices attached\n\n",
13698c2ecf20Sopenharmony_ci				attach_count);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci		count++;
13728c2ecf20Sopenharmony_ci		size += buf_obj->size;
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	mutex_unlock(&db_list.lock);
13788c2ecf20Sopenharmony_ci	return 0;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_cierror_unlock:
13818c2ecf20Sopenharmony_ci	mutex_unlock(&db_list.lock);
13828c2ecf20Sopenharmony_ci	return ret;
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dma_buf_debug);
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cistatic struct dentry *dma_buf_debugfs_dir;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistatic int dma_buf_init_debugfs(void)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	struct dentry *d;
13928c2ecf20Sopenharmony_ci	int err = 0;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	d = debugfs_create_dir("dma_buf", NULL);
13958c2ecf20Sopenharmony_ci	if (IS_ERR(d))
13968c2ecf20Sopenharmony_ci		return PTR_ERR(d);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	dma_buf_debugfs_dir = d;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	d = debugfs_create_file("bufinfo", S_IRUGO, dma_buf_debugfs_dir,
14018c2ecf20Sopenharmony_ci				NULL, &dma_buf_debug_fops);
14028c2ecf20Sopenharmony_ci	if (IS_ERR(d)) {
14038c2ecf20Sopenharmony_ci		pr_debug("dma_buf: debugfs: failed to create node bufinfo\n");
14048c2ecf20Sopenharmony_ci		debugfs_remove_recursive(dma_buf_debugfs_dir);
14058c2ecf20Sopenharmony_ci		dma_buf_debugfs_dir = NULL;
14068c2ecf20Sopenharmony_ci		err = PTR_ERR(d);
14078c2ecf20Sopenharmony_ci	}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	dma_buf_process_info_init_debugfs(dma_buf_debugfs_dir);
14108c2ecf20Sopenharmony_ci	return err;
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_cistatic void dma_buf_uninit_debugfs(void)
14148c2ecf20Sopenharmony_ci{
14158c2ecf20Sopenharmony_ci	debugfs_remove_recursive(dma_buf_debugfs_dir);
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci#else
14188c2ecf20Sopenharmony_cistatic inline int dma_buf_init_debugfs(void)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	return 0;
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_cistatic inline void dma_buf_uninit_debugfs(void)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci}
14258c2ecf20Sopenharmony_ci#endif
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci#ifdef CONFIG_DMABUF_PROCESS_INFO
14288c2ecf20Sopenharmony_cistruct dma_buf *get_dma_buf_from_file(struct file *f)
14298c2ecf20Sopenharmony_ci{
14308c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(f))
14318c2ecf20Sopenharmony_ci		return NULL;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	if (!is_dma_buf_file(f))
14348c2ecf20Sopenharmony_ci		return NULL;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	return f->private_data;
14378c2ecf20Sopenharmony_ci}
14388c2ecf20Sopenharmony_ci#endif /* CONFIG_DMABUF_PROCESS_INFO */
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_cistatic int __init dma_buf_init(void)
14418c2ecf20Sopenharmony_ci{
14428c2ecf20Sopenharmony_ci	int ret;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	ret = dma_buf_init_sysfs_statistics();
14458c2ecf20Sopenharmony_ci	if (ret)
14468c2ecf20Sopenharmony_ci		return ret;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	dma_buf_mnt = kern_mount(&dma_buf_fs_type);
14498c2ecf20Sopenharmony_ci	if (IS_ERR(dma_buf_mnt))
14508c2ecf20Sopenharmony_ci		return PTR_ERR(dma_buf_mnt);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	mutex_init(&db_list.lock);
14538c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&db_list.head);
14548c2ecf20Sopenharmony_ci	dma_buf_init_debugfs();
14558c2ecf20Sopenharmony_ci	dma_buf_process_info_init_procfs();
14568c2ecf20Sopenharmony_ci	return 0;
14578c2ecf20Sopenharmony_ci}
14588c2ecf20Sopenharmony_cisubsys_initcall(dma_buf_init);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cistatic void __exit dma_buf_deinit(void)
14618c2ecf20Sopenharmony_ci{
14628c2ecf20Sopenharmony_ci	dma_buf_uninit_debugfs();
14638c2ecf20Sopenharmony_ci	kern_unmount(dma_buf_mnt);
14648c2ecf20Sopenharmony_ci	dma_buf_uninit_sysfs_statistics();
14658c2ecf20Sopenharmony_ci	dma_buf_process_info_uninit_procfs();
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci__exitcall(dma_buf_deinit);
1468