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