13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * Framework for buffer objects that can be shared across devices/subsystems.
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright(C) 2011 Linaro Limited. All rights reserved.
63d0407baSopenharmony_ci * Author: Sumit Semwal <sumit.semwal@ti.com>
73d0407baSopenharmony_ci *
83d0407baSopenharmony_ci * Many thanks to linaro-mm-sig list, and specially
93d0407baSopenharmony_ci * Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and
103d0407baSopenharmony_ci * Daniel Vetter <daniel@ffwll.ch> for their support in creation and
113d0407baSopenharmony_ci * refining of this idea.
123d0407baSopenharmony_ci */
133d0407baSopenharmony_ci
143d0407baSopenharmony_ci#include <linux/fs.h>
153d0407baSopenharmony_ci#include <linux/slab.h>
163d0407baSopenharmony_ci#include <linux/dma-buf.h>
173d0407baSopenharmony_ci#include <linux/dma-fence.h>
183d0407baSopenharmony_ci#include <linux/anon_inodes.h>
193d0407baSopenharmony_ci#include <linux/export.h>
203d0407baSopenharmony_ci#include <linux/debugfs.h>
213d0407baSopenharmony_ci#include <linux/module.h>
223d0407baSopenharmony_ci#include <linux/seq_file.h>
233d0407baSopenharmony_ci#include <linux/poll.h>
243d0407baSopenharmony_ci#include <linux/dma-resv.h>
253d0407baSopenharmony_ci#include <linux/mm.h>
263d0407baSopenharmony_ci#include <linux/mount.h>
273d0407baSopenharmony_ci#include <linux/pseudo_fs.h>
283d0407baSopenharmony_ci
293d0407baSopenharmony_ci#include <uapi/linux/dma-buf.h>
303d0407baSopenharmony_ci#include <uapi/linux/magic.h>
313d0407baSopenharmony_ci
323d0407baSopenharmony_ci#include "dma-buf-sysfs-stats.h"
333d0407baSopenharmony_ci#include "dma-buf-process-info.h"
343d0407baSopenharmony_ci
353d0407baSopenharmony_cistruct dma_buf_list {
363d0407baSopenharmony_ci    struct list_head head;
373d0407baSopenharmony_ci    struct mutex lock;
383d0407baSopenharmony_ci};
393d0407baSopenharmony_ci
403d0407baSopenharmony_cistatic struct dma_buf_list db_list;
413d0407baSopenharmony_ci
423d0407baSopenharmony_ci/*
433d0407baSopenharmony_ci * This function helps in traversing the db_list and calls the
443d0407baSopenharmony_ci * callback function which can extract required info out of each
453d0407baSopenharmony_ci * dmabuf.
463d0407baSopenharmony_ci */
473d0407baSopenharmony_ciint get_each_dmabuf(int (*callback)(const struct dma_buf *dmabuf, void *private), void *private)
483d0407baSopenharmony_ci{
493d0407baSopenharmony_ci    struct dma_buf *buf;
503d0407baSopenharmony_ci    int ret = mutex_lock_interruptible(&db_list.lock);
513d0407baSopenharmony_ci    if (ret) {
523d0407baSopenharmony_ci        return ret;
533d0407baSopenharmony_ci    }
543d0407baSopenharmony_ci
553d0407baSopenharmony_ci    list_for_each_entry(buf, &db_list.head, list_node)
563d0407baSopenharmony_ci    {
573d0407baSopenharmony_ci        ret = callback(buf, private);
583d0407baSopenharmony_ci        if (ret) {
593d0407baSopenharmony_ci            break;
603d0407baSopenharmony_ci        }
613d0407baSopenharmony_ci    }
623d0407baSopenharmony_ci    mutex_unlock(&db_list.lock);
633d0407baSopenharmony_ci    return ret;
643d0407baSopenharmony_ci}
653d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(get_each_dmabuf);
663d0407baSopenharmony_ci
673d0407baSopenharmony_cistatic char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
683d0407baSopenharmony_ci{
693d0407baSopenharmony_ci    struct dma_buf *dmabuf;
703d0407baSopenharmony_ci    char name[DMA_BUF_NAME_LEN];
713d0407baSopenharmony_ci    size_t ret = 0;
723d0407baSopenharmony_ci
733d0407baSopenharmony_ci    dmabuf = dentry->d_fsdata;
743d0407baSopenharmony_ci    spin_lock(&dmabuf->name_lock);
753d0407baSopenharmony_ci    if (dmabuf->name) {
763d0407baSopenharmony_ci        ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
773d0407baSopenharmony_ci    }
783d0407baSopenharmony_ci    spin_unlock(&dmabuf->name_lock);
793d0407baSopenharmony_ci
803d0407baSopenharmony_ci    return dynamic_dname(dentry, buffer, buflen, "/%s:%s", dentry->d_name.name, ret > 0 ? name : "");
813d0407baSopenharmony_ci}
823d0407baSopenharmony_ci
833d0407baSopenharmony_cistatic void dma_buf_release(struct dentry *dentry)
843d0407baSopenharmony_ci{
853d0407baSopenharmony_ci    struct dma_buf *dmabuf;
863d0407baSopenharmony_ci
873d0407baSopenharmony_ci    dmabuf = dentry->d_fsdata;
883d0407baSopenharmony_ci    if (unlikely(!dmabuf)) {
893d0407baSopenharmony_ci        return;
903d0407baSopenharmony_ci    }
913d0407baSopenharmony_ci
923d0407baSopenharmony_ci    BUG_ON(dmabuf->vmapping_counter);
933d0407baSopenharmony_ci
943d0407baSopenharmony_ci    /*
953d0407baSopenharmony_ci     * Any fences that a dma-buf poll can wait on should be signaled
963d0407baSopenharmony_ci     * before releasing dma-buf. This is the responsibility of each
973d0407baSopenharmony_ci     * driver that uses the reservation objects.
983d0407baSopenharmony_ci     *
993d0407baSopenharmony_ci     * If you hit this BUG() it means someone dropped their ref to the
1003d0407baSopenharmony_ci     * dma-buf while still having pending operation to the buffer.
1013d0407baSopenharmony_ci     */
1023d0407baSopenharmony_ci    BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active);
1033d0407baSopenharmony_ci
1043d0407baSopenharmony_ci    dmabuf->ops->release(dmabuf);
1053d0407baSopenharmony_ci
1063d0407baSopenharmony_ci    if (dmabuf->resv == (struct dma_resv *)&dmabuf[1]) {
1073d0407baSopenharmony_ci        dma_resv_fini(dmabuf->resv);
1083d0407baSopenharmony_ci    }
1093d0407baSopenharmony_ci
1103d0407baSopenharmony_ci    WARN_ON(!list_empty(&dmabuf->attachments));
1113d0407baSopenharmony_ci    dma_buf_stats_teardown(dmabuf);
1123d0407baSopenharmony_ci    module_put(dmabuf->owner);
1133d0407baSopenharmony_ci    kfree(dmabuf->name);
1143d0407baSopenharmony_ci    kfree(dmabuf);
1153d0407baSopenharmony_ci}
1163d0407baSopenharmony_ci
1173d0407baSopenharmony_cistatic int dma_buf_file_release(struct inode *inode, struct file *file)
1183d0407baSopenharmony_ci{
1193d0407baSopenharmony_ci    struct dma_buf *dmabuf;
1203d0407baSopenharmony_ci
1213d0407baSopenharmony_ci    if (!is_dma_buf_file(file)) {
1223d0407baSopenharmony_ci        return -EINVAL;
1233d0407baSopenharmony_ci    }
1243d0407baSopenharmony_ci
1253d0407baSopenharmony_ci    dmabuf = file->private_data;
1263d0407baSopenharmony_ci
1273d0407baSopenharmony_ci    mutex_lock(&db_list.lock);
1283d0407baSopenharmony_ci    list_del(&dmabuf->list_node);
1293d0407baSopenharmony_ci    mutex_unlock(&db_list.lock);
1303d0407baSopenharmony_ci
1313d0407baSopenharmony_ci    return 0;
1323d0407baSopenharmony_ci}
1333d0407baSopenharmony_ci
1343d0407baSopenharmony_cistatic const struct dentry_operations dma_buf_dentry_ops = {
1353d0407baSopenharmony_ci    .d_dname = dmabuffs_dname,
1363d0407baSopenharmony_ci    .d_release = dma_buf_release,
1373d0407baSopenharmony_ci};
1383d0407baSopenharmony_ci
1393d0407baSopenharmony_cistatic struct vfsmount *dma_buf_mnt;
1403d0407baSopenharmony_ci
1413d0407baSopenharmony_cistatic int dma_buf_fs_init_context(struct fs_context *fc)
1423d0407baSopenharmony_ci{
1433d0407baSopenharmony_ci    struct pseudo_fs_context *ctx;
1443d0407baSopenharmony_ci
1453d0407baSopenharmony_ci    ctx = init_pseudo(fc, DMA_BUF_MAGIC);
1463d0407baSopenharmony_ci    if (!ctx) {
1473d0407baSopenharmony_ci        return -ENOMEM;
1483d0407baSopenharmony_ci    }
1493d0407baSopenharmony_ci    ctx->dops = &dma_buf_dentry_ops;
1503d0407baSopenharmony_ci    return 0;
1513d0407baSopenharmony_ci}
1523d0407baSopenharmony_ci
1533d0407baSopenharmony_cistatic struct file_system_type dma_buf_fs_type = {
1543d0407baSopenharmony_ci    .name = "dmabuf",
1553d0407baSopenharmony_ci    .init_fs_context = dma_buf_fs_init_context,
1563d0407baSopenharmony_ci    .kill_sb = kill_anon_super,
1573d0407baSopenharmony_ci};
1583d0407baSopenharmony_ci
1593d0407baSopenharmony_ci#ifdef CONFIG_DMABUF_SYSFS_STATS
1603d0407baSopenharmony_cistatic void dma_buf_vma_open(struct vm_area_struct *vma)
1613d0407baSopenharmony_ci{
1623d0407baSopenharmony_ci    struct dma_buf *dmabuf = vma->vm_file->private_data;
1633d0407baSopenharmony_ci
1643d0407baSopenharmony_ci    dmabuf->mmap_count++;
1653d0407baSopenharmony_ci    /* call the heap provided vma open() op */
1663d0407baSopenharmony_ci    if (dmabuf->exp_vm_ops->open) {
1673d0407baSopenharmony_ci        dmabuf->exp_vm_ops->open(vma);
1683d0407baSopenharmony_ci    }
1693d0407baSopenharmony_ci}
1703d0407baSopenharmony_ci
1713d0407baSopenharmony_cistatic void dma_buf_vma_close(struct vm_area_struct *vma)
1723d0407baSopenharmony_ci{
1733d0407baSopenharmony_ci    struct dma_buf *dmabuf = vma->vm_file->private_data;
1743d0407baSopenharmony_ci
1753d0407baSopenharmony_ci    if (dmabuf->mmap_count) {
1763d0407baSopenharmony_ci        dmabuf->mmap_count--;
1773d0407baSopenharmony_ci    }
1783d0407baSopenharmony_ci    /* call the heap provided vma close() op */
1793d0407baSopenharmony_ci    if (dmabuf->exp_vm_ops->close) {
1803d0407baSopenharmony_ci        dmabuf->exp_vm_ops->close(vma);
1813d0407baSopenharmony_ci    }
1823d0407baSopenharmony_ci}
1833d0407baSopenharmony_ci
1843d0407baSopenharmony_cistatic int dma_buf_do_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
1853d0407baSopenharmony_ci{
1863d0407baSopenharmony_ci    /* call this first because the exporter might override vma->vm_ops */
1873d0407baSopenharmony_ci    int ret = dmabuf->ops->mmap(dmabuf, vma);
1883d0407baSopenharmony_ci    if (ret) {
1893d0407baSopenharmony_ci        return ret;
1903d0407baSopenharmony_ci    }
1913d0407baSopenharmony_ci
1923d0407baSopenharmony_ci    /* save the exporter provided vm_ops */
1933d0407baSopenharmony_ci    dmabuf->exp_vm_ops = vma->vm_ops;
1943d0407baSopenharmony_ci    dmabuf->vm_ops = *(dmabuf->exp_vm_ops);
1953d0407baSopenharmony_ci    /* override open() and close() to provide buffer mmap count */
1963d0407baSopenharmony_ci    dmabuf->vm_ops.open = dma_buf_vma_open;
1973d0407baSopenharmony_ci    dmabuf->vm_ops.close = dma_buf_vma_close;
1983d0407baSopenharmony_ci    vma->vm_ops = &dmabuf->vm_ops;
1993d0407baSopenharmony_ci    dmabuf->mmap_count++;
2003d0407baSopenharmony_ci
2013d0407baSopenharmony_ci    return ret;
2023d0407baSopenharmony_ci}
2033d0407baSopenharmony_ci#else  /* CONFIG_DMABUF_SYSFS_STATS */
2043d0407baSopenharmony_cistatic int dma_buf_do_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
2053d0407baSopenharmony_ci{
2063d0407baSopenharmony_ci    return dmabuf->ops->mmap(dmabuf, vma);
2073d0407baSopenharmony_ci}
2083d0407baSopenharmony_ci#endif /* CONFIG_DMABUF_SYSFS_STATS */
2093d0407baSopenharmony_ci
2103d0407baSopenharmony_cistatic int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
2113d0407baSopenharmony_ci{
2123d0407baSopenharmony_ci    struct dma_buf *dmabuf;
2133d0407baSopenharmony_ci
2143d0407baSopenharmony_ci    if (!is_dma_buf_file(file)) {
2153d0407baSopenharmony_ci        return -EINVAL;
2163d0407baSopenharmony_ci    }
2173d0407baSopenharmony_ci
2183d0407baSopenharmony_ci    dmabuf = file->private_data;
2193d0407baSopenharmony_ci
2203d0407baSopenharmony_ci    /* check if buffer supports mmap */
2213d0407baSopenharmony_ci    if (!dmabuf->ops->mmap) {
2223d0407baSopenharmony_ci        return -EINVAL;
2233d0407baSopenharmony_ci    }
2243d0407baSopenharmony_ci
2253d0407baSopenharmony_ci    /* check for overflowing the buffer's size */
2263d0407baSopenharmony_ci    if ((vma->vm_pgoff + vma_pages(vma)) > (dmabuf->size >> PAGE_SHIFT)) {
2273d0407baSopenharmony_ci        return -EINVAL;
2283d0407baSopenharmony_ci    }
2293d0407baSopenharmony_ci
2303d0407baSopenharmony_ci    return dma_buf_do_mmap(dmabuf, vma);
2313d0407baSopenharmony_ci}
2323d0407baSopenharmony_ci
2333d0407baSopenharmony_cistatic loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
2343d0407baSopenharmony_ci{
2353d0407baSopenharmony_ci    struct dma_buf *dmabuf;
2363d0407baSopenharmony_ci    loff_t base;
2373d0407baSopenharmony_ci
2383d0407baSopenharmony_ci    if (!is_dma_buf_file(file)) {
2393d0407baSopenharmony_ci        return -EBADF;
2403d0407baSopenharmony_ci    }
2413d0407baSopenharmony_ci
2423d0407baSopenharmony_ci    dmabuf = file->private_data;
2433d0407baSopenharmony_ci
2443d0407baSopenharmony_ci    /* only support discovering the end of the buffer,
2453d0407baSopenharmony_ci       but also allow SEEK_SET to maintain the idiomatic
2463d0407baSopenharmony_ci       SEEK_END(0), SEEK_CUR(0) pattern */
2473d0407baSopenharmony_ci    if (whence == SEEK_END) {
2483d0407baSopenharmony_ci        base = dmabuf->size;
2493d0407baSopenharmony_ci    } else if (whence == SEEK_SET) {
2503d0407baSopenharmony_ci        base = 0;
2513d0407baSopenharmony_ci    } else {
2523d0407baSopenharmony_ci        return -EINVAL;
2533d0407baSopenharmony_ci    }
2543d0407baSopenharmony_ci
2553d0407baSopenharmony_ci    if (offset != 0) {
2563d0407baSopenharmony_ci        return -EINVAL;
2573d0407baSopenharmony_ci    }
2583d0407baSopenharmony_ci
2593d0407baSopenharmony_ci    return base + offset;
2603d0407baSopenharmony_ci}
2613d0407baSopenharmony_ci
2623d0407baSopenharmony_ci/**
2633d0407baSopenharmony_ci * DOC: implicit fence polling
2643d0407baSopenharmony_ci *
2653d0407baSopenharmony_ci * To support cross-device and cross-driver synchronization of buffer access
2663d0407baSopenharmony_ci * implicit fences (represented internally in the kernel with &struct dma_fence)
2673d0407baSopenharmony_ci * can be attached to a &dma_buf. The glue for that and a few related things are
2683d0407baSopenharmony_ci * provided in the &dma_resv structure.
2693d0407baSopenharmony_ci *
2703d0407baSopenharmony_ci * Userspace can query the state of these implicitly tracked fences using poll()
2713d0407baSopenharmony_ci * and related system calls
2723d0407baSopenharmony_ci *
2733d0407baSopenharmony_ci * - Checking for EPOLLIN, i.e. read access, can be use to query the state of the
2743d0407baSopenharmony_ci *   most recent write or exclusive fence.
2753d0407baSopenharmony_ci *
2763d0407baSopenharmony_ci * - Checking for EPOLLOUT, i.e. write access, can be used to query the state of
2773d0407baSopenharmony_ci *   all attached fences, shared and exclusive ones.
2783d0407baSopenharmony_ci *
2793d0407baSopenharmony_ci * Note that this only signals the completion of the respective fences, i.e. the
2803d0407baSopenharmony_ci * DMA transfers are complete. Cache flushing and any other necessary
2813d0407baSopenharmony_ci * preparations before CPU access can begin still need to happen.
2823d0407baSopenharmony_ci */
2833d0407baSopenharmony_ci
2843d0407baSopenharmony_cistatic void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
2853d0407baSopenharmony_ci{
2863d0407baSopenharmony_ci    struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb;
2873d0407baSopenharmony_ci    unsigned long flags;
2883d0407baSopenharmony_ci
2893d0407baSopenharmony_ci    spin_lock_irqsave(&dcb->poll->lock, flags);
2903d0407baSopenharmony_ci    wake_up_locked_poll(dcb->poll, dcb->active);
2913d0407baSopenharmony_ci    dcb->active = 0;
2923d0407baSopenharmony_ci    spin_unlock_irqrestore(&dcb->poll->lock, flags);
2933d0407baSopenharmony_ci}
2943d0407baSopenharmony_ci
2953d0407baSopenharmony_cistatic __poll_t dma_buf_poll(struct file *file, poll_table *poll)
2963d0407baSopenharmony_ci{
2973d0407baSopenharmony_ci    struct dma_buf *dmabuf;
2983d0407baSopenharmony_ci    struct dma_resv *resv;
2993d0407baSopenharmony_ci    struct dma_resv_list *fobj;
3003d0407baSopenharmony_ci    struct dma_fence *fence_excl;
3013d0407baSopenharmony_ci    __poll_t events;
3023d0407baSopenharmony_ci    unsigned shared_count, seq;
3033d0407baSopenharmony_ci
3043d0407baSopenharmony_ci    dmabuf = file->private_data;
3053d0407baSopenharmony_ci    if (!dmabuf || !dmabuf->resv) {
3063d0407baSopenharmony_ci        return EPOLLERR;
3073d0407baSopenharmony_ci    }
3083d0407baSopenharmony_ci
3093d0407baSopenharmony_ci    resv = dmabuf->resv;
3103d0407baSopenharmony_ci
3113d0407baSopenharmony_ci    poll_wait(file, &dmabuf->poll, poll);
3123d0407baSopenharmony_ci
3133d0407baSopenharmony_ci    events = poll_requested_events(poll) & (EPOLLIN | EPOLLOUT);
3143d0407baSopenharmony_ci    if (!events) {
3153d0407baSopenharmony_ci        return 0;
3163d0407baSopenharmony_ci    }
3173d0407baSopenharmony_ci
3183d0407baSopenharmony_ci    while (1) {
3193d0407baSopenharmony_ci        seq = read_seqcount_begin(&resv->seq);
3203d0407baSopenharmony_ci        rcu_read_lock();
3213d0407baSopenharmony_ci
3223d0407baSopenharmony_ci        fobj = rcu_dereference(resv->fence);
3233d0407baSopenharmony_ci        if (fobj) {
3243d0407baSopenharmony_ci            shared_count = fobj->shared_count;
3253d0407baSopenharmony_ci        } else {
3263d0407baSopenharmony_ci            shared_count = 0;
3273d0407baSopenharmony_ci        }
3283d0407baSopenharmony_ci        fence_excl = rcu_dereference(resv->fence_excl);
3293d0407baSopenharmony_ci        if (read_seqcount_retry(&resv->seq, seq)) {
3303d0407baSopenharmony_ci            rcu_read_unlock();
3313d0407baSopenharmony_ci            continue;
3323d0407baSopenharmony_ci        }
3333d0407baSopenharmony_ci        break;
3343d0407baSopenharmony_ci    }
3353d0407baSopenharmony_ci    if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) {
3363d0407baSopenharmony_ci        struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl;
3373d0407baSopenharmony_ci        __poll_t pevents = EPOLLIN;
3383d0407baSopenharmony_ci
3393d0407baSopenharmony_ci        if (shared_count == 0) {
3403d0407baSopenharmony_ci            pevents |= EPOLLOUT;
3413d0407baSopenharmony_ci        }
3423d0407baSopenharmony_ci
3433d0407baSopenharmony_ci        spin_lock_irq(&dmabuf->poll.lock);
3443d0407baSopenharmony_ci        if (dcb->active) {
3453d0407baSopenharmony_ci            dcb->active |= pevents;
3463d0407baSopenharmony_ci            events &= ~pevents;
3473d0407baSopenharmony_ci        } else {
3483d0407baSopenharmony_ci            dcb->active = pevents;
3493d0407baSopenharmony_ci        }
3503d0407baSopenharmony_ci        spin_unlock_irq(&dmabuf->poll.lock);
3513d0407baSopenharmony_ci
3523d0407baSopenharmony_ci        if (events & pevents) {
3533d0407baSopenharmony_ci            if (!dma_fence_get_rcu(fence_excl)) {
3543d0407baSopenharmony_ci                /* force a recheck */
3553d0407baSopenharmony_ci                events &= ~pevents;
3563d0407baSopenharmony_ci                dma_buf_poll_cb(NULL, &dcb->cb);
3573d0407baSopenharmony_ci            } else if (!dma_fence_add_callback(fence_excl, &dcb->cb, dma_buf_poll_cb)) {
3583d0407baSopenharmony_ci                events &= ~pevents;
3593d0407baSopenharmony_ci                dma_fence_put(fence_excl);
3603d0407baSopenharmony_ci            } else {
3613d0407baSopenharmony_ci                /*
3623d0407baSopenharmony_ci                 * No callback queued, wake up any additional
3633d0407baSopenharmony_ci                 * waiters.
3643d0407baSopenharmony_ci                 */
3653d0407baSopenharmony_ci                dma_fence_put(fence_excl);
3663d0407baSopenharmony_ci                dma_buf_poll_cb(NULL, &dcb->cb);
3673d0407baSopenharmony_ci            }
3683d0407baSopenharmony_ci        }
3693d0407baSopenharmony_ci    }
3703d0407baSopenharmony_ci
3713d0407baSopenharmony_ci    if ((events & EPOLLOUT) && shared_count > 0) {
3723d0407baSopenharmony_ci        struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared;
3733d0407baSopenharmony_ci        int i;
3743d0407baSopenharmony_ci
3753d0407baSopenharmony_ci        /* Only queue a new callback if no event has fired yet */
3763d0407baSopenharmony_ci        spin_lock_irq(&dmabuf->poll.lock);
3773d0407baSopenharmony_ci        if (dcb->active) {
3783d0407baSopenharmony_ci            events &= ~EPOLLOUT;
3793d0407baSopenharmony_ci        } else {
3803d0407baSopenharmony_ci            dcb->active = EPOLLOUT;
3813d0407baSopenharmony_ci        }
3823d0407baSopenharmony_ci        spin_unlock_irq(&dmabuf->poll.lock);
3833d0407baSopenharmony_ci
3843d0407baSopenharmony_ci        if (!(events & EPOLLOUT)) {
3853d0407baSopenharmony_ci            goto out;
3863d0407baSopenharmony_ci        }
3873d0407baSopenharmony_ci
3883d0407baSopenharmony_ci        for (i = 0; i < shared_count; ++i) {
3893d0407baSopenharmony_ci            struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
3903d0407baSopenharmony_ci
3913d0407baSopenharmony_ci            if (!dma_fence_get_rcu(fence)) {
3923d0407baSopenharmony_ci                /*
3933d0407baSopenharmony_ci                 * fence refcount dropped to zero, this means
3943d0407baSopenharmony_ci                 * that fobj has been freed
3953d0407baSopenharmony_ci                 *
3963d0407baSopenharmony_ci                 * call dma_buf_poll_cb and force a recheck!
3973d0407baSopenharmony_ci                 */
3983d0407baSopenharmony_ci                events &= ~EPOLLOUT;
3993d0407baSopenharmony_ci                dma_buf_poll_cb(NULL, &dcb->cb);
4003d0407baSopenharmony_ci                break;
4013d0407baSopenharmony_ci            }
4023d0407baSopenharmony_ci            if (!dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb)) {
4033d0407baSopenharmony_ci                dma_fence_put(fence);
4043d0407baSopenharmony_ci                events &= ~EPOLLOUT;
4053d0407baSopenharmony_ci                break;
4063d0407baSopenharmony_ci            }
4073d0407baSopenharmony_ci            dma_fence_put(fence);
4083d0407baSopenharmony_ci        }
4093d0407baSopenharmony_ci
4103d0407baSopenharmony_ci        /* No callback queued, wake up any additional waiters. */
4113d0407baSopenharmony_ci        if (i == shared_count) {
4123d0407baSopenharmony_ci            dma_buf_poll_cb(NULL, &dcb->cb);
4133d0407baSopenharmony_ci        }
4143d0407baSopenharmony_ci    }
4153d0407baSopenharmony_ci
4163d0407baSopenharmony_ciout:
4173d0407baSopenharmony_ci    rcu_read_unlock();
4183d0407baSopenharmony_ci    return events;
4193d0407baSopenharmony_ci}
4203d0407baSopenharmony_ci
4213d0407baSopenharmony_ci/**
4223d0407baSopenharmony_ci * dma_buf_set_name - Set a name to a specific dma_buf to track the usage.
4233d0407baSopenharmony_ci * The name of the dma-buf buffer can only be set when the dma-buf is not
4243d0407baSopenharmony_ci * attached to any devices. It could theoritically support changing the
4253d0407baSopenharmony_ci * name of the dma-buf if the same piece of memory is used for multiple
4263d0407baSopenharmony_ci * purpose between different devices.
4273d0407baSopenharmony_ci *
4283d0407baSopenharmony_ci * @dmabuf: [in]     dmabuf buffer that will be renamed.
4293d0407baSopenharmony_ci * @buf:    [in]     A piece of userspace memory that contains the name of
4303d0407baSopenharmony_ci *                   the dma-buf.
4313d0407baSopenharmony_ci *
4323d0407baSopenharmony_ci * Returns 0 on success. If the dma-buf buffer is already attached to
4333d0407baSopenharmony_ci * devices, return -EBUSY.
4343d0407baSopenharmony_ci *
4353d0407baSopenharmony_ci */
4363d0407baSopenharmony_cistatic long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
4373d0407baSopenharmony_ci{
4383d0407baSopenharmony_ci    char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
4393d0407baSopenharmony_ci    long ret = 0;
4403d0407baSopenharmony_ci
4413d0407baSopenharmony_ci    if (IS_ERR(name)) {
4423d0407baSopenharmony_ci        return PTR_ERR(name);
4433d0407baSopenharmony_ci    }
4443d0407baSopenharmony_ci
4453d0407baSopenharmony_ci    dma_resv_lock(dmabuf->resv, NULL);
4463d0407baSopenharmony_ci    if (!list_empty(&dmabuf->attachments)) {
4473d0407baSopenharmony_ci        ret = -EBUSY;
4483d0407baSopenharmony_ci        kfree(name);
4493d0407baSopenharmony_ci        goto out_unlock;
4503d0407baSopenharmony_ci    }
4513d0407baSopenharmony_ci    spin_lock(&dmabuf->name_lock);
4523d0407baSopenharmony_ci    kfree(dmabuf->name);
4533d0407baSopenharmony_ci    dmabuf->name = name;
4543d0407baSopenharmony_ci    spin_unlock(&dmabuf->name_lock);
4553d0407baSopenharmony_ci
4563d0407baSopenharmony_ciout_unlock:
4573d0407baSopenharmony_ci    dma_resv_unlock(dmabuf->resv);
4583d0407baSopenharmony_ci    return ret;
4593d0407baSopenharmony_ci}
4603d0407baSopenharmony_ci
4613d0407baSopenharmony_cistatic long dma_buf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4623d0407baSopenharmony_ci{
4633d0407baSopenharmony_ci    struct dma_buf *dmabuf;
4643d0407baSopenharmony_ci    struct dma_buf_sync sync;
4653d0407baSopenharmony_ci    enum dma_data_direction direction;
4663d0407baSopenharmony_ci    int ret;
4673d0407baSopenharmony_ci
4683d0407baSopenharmony_ci    dmabuf = file->private_data;
4693d0407baSopenharmony_ci
4703d0407baSopenharmony_ci    switch (cmd) {
4713d0407baSopenharmony_ci        case DMA_BUF_IOCTL_SYNC:
4723d0407baSopenharmony_ci            if (copy_from_user(&sync, (void __user *)arg, sizeof(sync))) {
4733d0407baSopenharmony_ci                return -EFAULT;
4743d0407baSopenharmony_ci            }
4753d0407baSopenharmony_ci
4763d0407baSopenharmony_ci            if (sync.flags & ~DMA_BUF_SYNC_VALID_FLAGS_MASK) {
4773d0407baSopenharmony_ci                return -EINVAL;
4783d0407baSopenharmony_ci            }
4793d0407baSopenharmony_ci
4803d0407baSopenharmony_ci            switch (sync.flags & DMA_BUF_SYNC_RW) {
4813d0407baSopenharmony_ci                case DMA_BUF_SYNC_READ:
4823d0407baSopenharmony_ci                    direction = DMA_FROM_DEVICE;
4833d0407baSopenharmony_ci                    break;
4843d0407baSopenharmony_ci                case DMA_BUF_SYNC_WRITE:
4853d0407baSopenharmony_ci                    direction = DMA_TO_DEVICE;
4863d0407baSopenharmony_ci                    break;
4873d0407baSopenharmony_ci                case DMA_BUF_SYNC_RW:
4883d0407baSopenharmony_ci                    direction = DMA_BIDIRECTIONAL;
4893d0407baSopenharmony_ci                    break;
4903d0407baSopenharmony_ci                default:
4913d0407baSopenharmony_ci                    return -EINVAL;
4923d0407baSopenharmony_ci            }
4933d0407baSopenharmony_ci
4943d0407baSopenharmony_ci            if (sync.flags & DMA_BUF_SYNC_END) {
4953d0407baSopenharmony_ci                ret = dma_buf_end_cpu_access(dmabuf, direction);
4963d0407baSopenharmony_ci            } else {
4973d0407baSopenharmony_ci                ret = dma_buf_begin_cpu_access(dmabuf, direction);
4983d0407baSopenharmony_ci            }
4993d0407baSopenharmony_ci
5003d0407baSopenharmony_ci            return ret;
5013d0407baSopenharmony_ci
5023d0407baSopenharmony_ci        case DMA_BUF_SET_NAME_A:
5033d0407baSopenharmony_ci        case DMA_BUF_SET_NAME_B:
5043d0407baSopenharmony_ci            return dma_buf_set_name(dmabuf, (const char __user *)arg);
5053d0407baSopenharmony_ci
5063d0407baSopenharmony_ci        default:
5073d0407baSopenharmony_ci            return -ENOTTY;
5083d0407baSopenharmony_ci    }
5093d0407baSopenharmony_ci}
5103d0407baSopenharmony_ci
5113d0407baSopenharmony_cistatic void dma_buf_show_fdinfo(struct seq_file *m, struct file *file)
5123d0407baSopenharmony_ci{
5133d0407baSopenharmony_ci    struct dma_buf *dmabuf = file->private_data;
5143d0407baSopenharmony_ci
5153d0407baSopenharmony_ci    seq_printf(m, "size:\t%zu\n", dmabuf->size);
5163d0407baSopenharmony_ci    /* Don't count the temporary reference taken inside procfs seq_show */
5173d0407baSopenharmony_ci    seq_printf(m, "count:\t%ld\n", file_count(dmabuf->file) - 1);
5183d0407baSopenharmony_ci    seq_printf(m, "exp_name:\t%s\n", dmabuf->exp_name);
5193d0407baSopenharmony_ci    spin_lock(&dmabuf->name_lock);
5203d0407baSopenharmony_ci    if (dmabuf->name) {
5213d0407baSopenharmony_ci        seq_printf(m, "name:\t%s\n", dmabuf->name);
5223d0407baSopenharmony_ci    }
5233d0407baSopenharmony_ci    spin_unlock(&dmabuf->name_lock);
5243d0407baSopenharmony_ci}
5253d0407baSopenharmony_ci
5263d0407baSopenharmony_cistatic const struct file_operations dma_buf_fops = {
5273d0407baSopenharmony_ci    .release = dma_buf_file_release,
5283d0407baSopenharmony_ci    .mmap = dma_buf_mmap_internal,
5293d0407baSopenharmony_ci    .llseek = dma_buf_llseek,
5303d0407baSopenharmony_ci    .poll = dma_buf_poll,
5313d0407baSopenharmony_ci    .unlocked_ioctl = dma_buf_ioctl,
5323d0407baSopenharmony_ci    .compat_ioctl = compat_ptr_ioctl,
5333d0407baSopenharmony_ci    .show_fdinfo = dma_buf_show_fdinfo,
5343d0407baSopenharmony_ci};
5353d0407baSopenharmony_ci
5363d0407baSopenharmony_ci/*
5373d0407baSopenharmony_ci * is_dma_buf_file - Check if struct file* is associated with dma_buf
5383d0407baSopenharmony_ci */
5393d0407baSopenharmony_ciint is_dma_buf_file(struct file *file)
5403d0407baSopenharmony_ci{
5413d0407baSopenharmony_ci    return file->f_op == &dma_buf_fops;
5423d0407baSopenharmony_ci}
5433d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(is_dma_buf_file);
5443d0407baSopenharmony_ci
5453d0407baSopenharmony_cistatic struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
5463d0407baSopenharmony_ci{
5473d0407baSopenharmony_ci    struct file *file;
5483d0407baSopenharmony_ci    struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb);
5493d0407baSopenharmony_ci
5503d0407baSopenharmony_ci    if (IS_ERR(inode)) {
5513d0407baSopenharmony_ci        return ERR_CAST(inode);
5523d0407baSopenharmony_ci    }
5533d0407baSopenharmony_ci
5543d0407baSopenharmony_ci    inode->i_size = dmabuf->size;
5553d0407baSopenharmony_ci    inode_set_bytes(inode, dmabuf->size);
5563d0407baSopenharmony_ci
5573d0407baSopenharmony_ci    file = alloc_file_pseudo(inode, dma_buf_mnt, "dmabuf", flags, &dma_buf_fops);
5583d0407baSopenharmony_ci    if (IS_ERR(file)) {
5593d0407baSopenharmony_ci        goto err_alloc_file;
5603d0407baSopenharmony_ci    }
5613d0407baSopenharmony_ci    file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
5623d0407baSopenharmony_ci    file->private_data = dmabuf;
5633d0407baSopenharmony_ci    file->f_path.dentry->d_fsdata = dmabuf;
5643d0407baSopenharmony_ci
5653d0407baSopenharmony_ci    return file;
5663d0407baSopenharmony_ci
5673d0407baSopenharmony_cierr_alloc_file:
5683d0407baSopenharmony_ci    iput(inode);
5693d0407baSopenharmony_ci    return file;
5703d0407baSopenharmony_ci}
5713d0407baSopenharmony_ci
5723d0407baSopenharmony_ci/**
5733d0407baSopenharmony_ci * DOC: dma buf device access
5743d0407baSopenharmony_ci *
5753d0407baSopenharmony_ci * For device DMA access to a shared DMA buffer the usual sequence of operations
5763d0407baSopenharmony_ci * is fairly simple
5773d0407baSopenharmony_ci *
5783d0407baSopenharmony_ci * 1. The exporter defines his exporter instance using
5793d0407baSopenharmony_ci *    DEFINE_DMA_BUF_EXPORT_INFO() and calls dma_buf_export() to wrap a private
5803d0407baSopenharmony_ci *    buffer object into a &dma_buf. It then exports that &dma_buf to userspace
5813d0407baSopenharmony_ci *    as a file descriptor by calling dma_buf_fd().
5823d0407baSopenharmony_ci *
5833d0407baSopenharmony_ci * 2. Userspace passes this file-descriptors to all drivers it wants this buffer
5843d0407baSopenharmony_ci *    to share with: First the filedescriptor is converted to a &dma_buf using
5853d0407baSopenharmony_ci *    dma_buf_get(). Then the buffer is attached to the device using
5863d0407baSopenharmony_ci *    dma_buf_attach().
5873d0407baSopenharmony_ci *
5883d0407baSopenharmony_ci *    Up to this stage the exporter is still free to migrate or reallocate the
5893d0407baSopenharmony_ci *    backing storage.
5903d0407baSopenharmony_ci *
5913d0407baSopenharmony_ci * 3. Once the buffer is attached to all devices userspace can initiate DMA
5923d0407baSopenharmony_ci *    access to the shared buffer. In the kernel this is done by calling
5933d0407baSopenharmony_ci *    dma_buf_map_attachment() and dma_buf_unmap_attachment().
5943d0407baSopenharmony_ci *
5953d0407baSopenharmony_ci * 4. Once a driver is done with a shared buffer it needs to call
5963d0407baSopenharmony_ci *    dma_buf_detach() (after cleaning up any mappings) and then release the
5973d0407baSopenharmony_ci *    reference acquired with dma_buf_get by calling dma_buf_put().
5983d0407baSopenharmony_ci *
5993d0407baSopenharmony_ci * For the detailed semantics exporters are expected to implement see
6003d0407baSopenharmony_ci * &dma_buf_ops.
6013d0407baSopenharmony_ci */
6023d0407baSopenharmony_ci
6033d0407baSopenharmony_ci/**
6043d0407baSopenharmony_ci * dma_buf_export - Creates a new dma_buf, and associates an anon file
6053d0407baSopenharmony_ci * with this buffer, so it can be exported.
6063d0407baSopenharmony_ci * Also connect the allocator specific data and ops to the buffer.
6073d0407baSopenharmony_ci * Additionally, provide a name string for exporter; useful in debugging.
6083d0407baSopenharmony_ci *
6093d0407baSopenharmony_ci * @exp_info:    [in]    holds all the export related information provided
6103d0407baSopenharmony_ci *            by the exporter. see &struct dma_buf_export_info
6113d0407baSopenharmony_ci *            for further details.
6123d0407baSopenharmony_ci *
6133d0407baSopenharmony_ci * Returns, on success, a newly created dma_buf object, which wraps the
6143d0407baSopenharmony_ci * supplied private data and operations for dma_buf_ops. On either missing
6153d0407baSopenharmony_ci * ops, or error in allocating struct dma_buf, will return negative error.
6163d0407baSopenharmony_ci *
6173d0407baSopenharmony_ci * For most cases the easiest way to create @exp_info is through the
6183d0407baSopenharmony_ci * %DEFINE_DMA_BUF_EXPORT_INFO macro.
6193d0407baSopenharmony_ci */
6203d0407baSopenharmony_cistruct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
6213d0407baSopenharmony_ci{
6223d0407baSopenharmony_ci    struct dma_buf *dmabuf;
6233d0407baSopenharmony_ci    struct dma_resv *resv = exp_info->resv;
6243d0407baSopenharmony_ci    struct file *file;
6253d0407baSopenharmony_ci    size_t alloc_size = sizeof(struct dma_buf);
6263d0407baSopenharmony_ci    int ret;
6273d0407baSopenharmony_ci
6283d0407baSopenharmony_ci    if (!exp_info->resv) {
6293d0407baSopenharmony_ci        alloc_size += sizeof(struct dma_resv);
6303d0407baSopenharmony_ci    } else {
6313d0407baSopenharmony_ci        /* prevent &dma_buf[1] == dma_buf->resv */
6323d0407baSopenharmony_ci        alloc_size += 1;
6333d0407baSopenharmony_ci    }
6343d0407baSopenharmony_ci
6353d0407baSopenharmony_ci    if (WARN_ON(!exp_info->priv || !exp_info->ops || !exp_info->ops->map_dma_buf || !exp_info->ops->unmap_dma_buf ||
6363d0407baSopenharmony_ci                !exp_info->ops->release)) {
6373d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
6383d0407baSopenharmony_ci    }
6393d0407baSopenharmony_ci
6403d0407baSopenharmony_ci    if (WARN_ON(exp_info->ops->cache_sgt_mapping && (exp_info->ops->pin || exp_info->ops->unpin))) {
6413d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
6423d0407baSopenharmony_ci    }
6433d0407baSopenharmony_ci
6443d0407baSopenharmony_ci    if (WARN_ON(!exp_info->ops->pin != !exp_info->ops->unpin)) {
6453d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
6463d0407baSopenharmony_ci    }
6473d0407baSopenharmony_ci
6483d0407baSopenharmony_ci    if (!try_module_get(exp_info->owner)) {
6493d0407baSopenharmony_ci        return ERR_PTR(-ENOENT);
6503d0407baSopenharmony_ci    }
6513d0407baSopenharmony_ci
6523d0407baSopenharmony_ci    dmabuf = kzalloc(alloc_size, GFP_KERNEL);
6533d0407baSopenharmony_ci    if (!dmabuf) {
6543d0407baSopenharmony_ci        ret = -ENOMEM;
6553d0407baSopenharmony_ci        goto err_module;
6563d0407baSopenharmony_ci    }
6573d0407baSopenharmony_ci
6583d0407baSopenharmony_ci    dmabuf->priv = exp_info->priv;
6593d0407baSopenharmony_ci    dmabuf->ops = exp_info->ops;
6603d0407baSopenharmony_ci    dmabuf->size = exp_info->size;
6613d0407baSopenharmony_ci    dmabuf->exp_name = exp_info->exp_name;
6623d0407baSopenharmony_ci    dmabuf->owner = exp_info->owner;
6633d0407baSopenharmony_ci    spin_lock_init(&dmabuf->name_lock);
6643d0407baSopenharmony_ci    init_waitqueue_head(&dmabuf->poll);
6653d0407baSopenharmony_ci    dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll;
6663d0407baSopenharmony_ci    dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
6673d0407baSopenharmony_ci
6683d0407baSopenharmony_ci    if (!resv) {
6693d0407baSopenharmony_ci        resv = (struct dma_resv *)&dmabuf[1];
6703d0407baSopenharmony_ci        dma_resv_init(resv);
6713d0407baSopenharmony_ci    }
6723d0407baSopenharmony_ci    dmabuf->resv = resv;
6733d0407baSopenharmony_ci
6743d0407baSopenharmony_ci    file = dma_buf_getfile(dmabuf, exp_info->flags);
6753d0407baSopenharmony_ci    if (IS_ERR(file)) {
6763d0407baSopenharmony_ci        ret = PTR_ERR(file);
6773d0407baSopenharmony_ci        goto err_dmabuf;
6783d0407baSopenharmony_ci    }
6793d0407baSopenharmony_ci
6803d0407baSopenharmony_ci    file->f_mode |= FMODE_LSEEK;
6813d0407baSopenharmony_ci    dmabuf->file = file;
6823d0407baSopenharmony_ci
6833d0407baSopenharmony_ci    ret = dma_buf_stats_setup(dmabuf);
6843d0407baSopenharmony_ci    if (ret) {
6853d0407baSopenharmony_ci        goto err_sysfs;
6863d0407baSopenharmony_ci    }
6873d0407baSopenharmony_ci
6883d0407baSopenharmony_ci    mutex_init(&dmabuf->lock);
6893d0407baSopenharmony_ci    INIT_LIST_HEAD(&dmabuf->attachments);
6903d0407baSopenharmony_ci
6913d0407baSopenharmony_ci    mutex_lock(&db_list.lock);
6923d0407baSopenharmony_ci    list_add(&dmabuf->list_node, &db_list.head);
6933d0407baSopenharmony_ci    mutex_unlock(&db_list.lock);
6943d0407baSopenharmony_ci
6953d0407baSopenharmony_ci    init_dma_buf_task_info(dmabuf);
6963d0407baSopenharmony_ci    return dmabuf;
6973d0407baSopenharmony_ci
6983d0407baSopenharmony_cierr_sysfs:
6993d0407baSopenharmony_ci    /*
7003d0407baSopenharmony_ci     * Set file->f_path.dentry->d_fsdata to NULL so that when
7013d0407baSopenharmony_ci     * dma_buf_release() gets invoked by dentry_ops, it exits
7023d0407baSopenharmony_ci     * early before calling the release() dma_buf op.
7033d0407baSopenharmony_ci     */
7043d0407baSopenharmony_ci    file->f_path.dentry->d_fsdata = NULL;
7053d0407baSopenharmony_ci    fput(file);
7063d0407baSopenharmony_cierr_dmabuf:
7073d0407baSopenharmony_ci    kfree(dmabuf);
7083d0407baSopenharmony_cierr_module:
7093d0407baSopenharmony_ci    module_put(exp_info->owner);
7103d0407baSopenharmony_ci    return ERR_PTR(ret);
7113d0407baSopenharmony_ci}
7123d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_export);
7133d0407baSopenharmony_ci
7143d0407baSopenharmony_ci/**
7153d0407baSopenharmony_ci * dma_buf_fd - returns a file descriptor for the given dma_buf
7163d0407baSopenharmony_ci * @dmabuf:    [in]    pointer to dma_buf for which fd is required.
7173d0407baSopenharmony_ci * @flags:      [in]    flags to give to fd
7183d0407baSopenharmony_ci *
7193d0407baSopenharmony_ci * On success, returns an associated 'fd'. Else, returns error.
7203d0407baSopenharmony_ci */
7213d0407baSopenharmony_ciint dma_buf_fd(struct dma_buf *dmabuf, int flags)
7223d0407baSopenharmony_ci{
7233d0407baSopenharmony_ci    int fd;
7243d0407baSopenharmony_ci
7253d0407baSopenharmony_ci    if (!dmabuf || !dmabuf->file) {
7263d0407baSopenharmony_ci        return -EINVAL;
7273d0407baSopenharmony_ci    }
7283d0407baSopenharmony_ci
7293d0407baSopenharmony_ci    fd = get_unused_fd_flags(flags);
7303d0407baSopenharmony_ci    if (fd < 0) {
7313d0407baSopenharmony_ci        return fd;
7323d0407baSopenharmony_ci    }
7333d0407baSopenharmony_ci
7343d0407baSopenharmony_ci    fd_install(fd, dmabuf->file);
7353d0407baSopenharmony_ci
7363d0407baSopenharmony_ci    return fd;
7373d0407baSopenharmony_ci}
7383d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_fd);
7393d0407baSopenharmony_ci
7403d0407baSopenharmony_ci/**
7413d0407baSopenharmony_ci * dma_buf_get - returns the dma_buf structure related to an fd
7423d0407baSopenharmony_ci * @fd:    [in]    fd associated with the dma_buf to be returned
7433d0407baSopenharmony_ci *
7443d0407baSopenharmony_ci * On success, returns the dma_buf structure associated with an fd; uses
7453d0407baSopenharmony_ci * file's refcounting done by fget to increase refcount. returns ERR_PTR
7463d0407baSopenharmony_ci * otherwise.
7473d0407baSopenharmony_ci */
7483d0407baSopenharmony_cistruct dma_buf *dma_buf_get(int fd)
7493d0407baSopenharmony_ci{
7503d0407baSopenharmony_ci    struct file *file;
7513d0407baSopenharmony_ci
7523d0407baSopenharmony_ci    file = fget(fd);
7533d0407baSopenharmony_ci    if (!file) {
7543d0407baSopenharmony_ci        return ERR_PTR(-EBADF);
7553d0407baSopenharmony_ci    }
7563d0407baSopenharmony_ci
7573d0407baSopenharmony_ci    if (!is_dma_buf_file(file)) {
7583d0407baSopenharmony_ci        fput(file);
7593d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
7603d0407baSopenharmony_ci    }
7613d0407baSopenharmony_ci
7623d0407baSopenharmony_ci    return file->private_data;
7633d0407baSopenharmony_ci}
7643d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_get);
7653d0407baSopenharmony_ci
7663d0407baSopenharmony_ci/**
7673d0407baSopenharmony_ci * dma_buf_put - decreases refcount of the buffer
7683d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to reduce refcount of
7693d0407baSopenharmony_ci *
7703d0407baSopenharmony_ci * Uses file's refcounting done implicitly by fput().
7713d0407baSopenharmony_ci *
7723d0407baSopenharmony_ci * If, as a result of this call, the refcount becomes 0, the 'release' file
7733d0407baSopenharmony_ci * operation related to this fd is called. It calls &dma_buf_ops.release vfunc
7743d0407baSopenharmony_ci * in turn, and frees the memory allocated for dmabuf when exported.
7753d0407baSopenharmony_ci */
7763d0407baSopenharmony_civoid dma_buf_put(struct dma_buf *dmabuf)
7773d0407baSopenharmony_ci{
7783d0407baSopenharmony_ci    if (WARN_ON(!dmabuf || !dmabuf->file)) {
7793d0407baSopenharmony_ci        return;
7803d0407baSopenharmony_ci    }
7813d0407baSopenharmony_ci
7823d0407baSopenharmony_ci    fput(dmabuf->file);
7833d0407baSopenharmony_ci}
7843d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_put);
7853d0407baSopenharmony_ci
7863d0407baSopenharmony_ci/**
7873d0407baSopenharmony_ci * dma_buf_pin - Lock down the DMA-buf
7883d0407baSopenharmony_ci *
7893d0407baSopenharmony_ci * @attach:    [in]    attachment which should be pinned
7903d0407baSopenharmony_ci *
7913d0407baSopenharmony_ci * Returns:
7923d0407baSopenharmony_ci * 0 on success, negative error code on failure.
7933d0407baSopenharmony_ci */
7943d0407baSopenharmony_ciint dma_buf_pin(struct dma_buf_attachment *attach)
7953d0407baSopenharmony_ci{
7963d0407baSopenharmony_ci    struct dma_buf *dmabuf = attach->dmabuf;
7973d0407baSopenharmony_ci    int ret = 0;
7983d0407baSopenharmony_ci
7993d0407baSopenharmony_ci    dma_resv_assert_held(dmabuf->resv);
8003d0407baSopenharmony_ci
8013d0407baSopenharmony_ci    if (dmabuf->ops->pin) {
8023d0407baSopenharmony_ci        ret = dmabuf->ops->pin(attach);
8033d0407baSopenharmony_ci    }
8043d0407baSopenharmony_ci
8053d0407baSopenharmony_ci    return ret;
8063d0407baSopenharmony_ci}
8073d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_pin);
8083d0407baSopenharmony_ci
8093d0407baSopenharmony_ci/**
8103d0407baSopenharmony_ci * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list; optionally,
8113d0407baSopenharmony_ci * calls attach() of dma_buf_ops to allow device-specific attach functionality
8123d0407baSopenharmony_ci * @dmabuf:        [in]    buffer to attach device to.
8133d0407baSopenharmony_ci * @dev:        [in]    device to be attached.
8143d0407baSopenharmony_ci * @importer_ops:    [in]    importer operations for the attachment
8153d0407baSopenharmony_ci * @importer_priv:    [in]    importer private pointer for the attachment
8163d0407baSopenharmony_ci *
8173d0407baSopenharmony_ci * Returns struct dma_buf_attachment pointer for this attachment. Attachments
8183d0407baSopenharmony_ci * must be cleaned up by calling dma_buf_detach().
8193d0407baSopenharmony_ci *
8203d0407baSopenharmony_ci * Returns
8213d0407baSopenharmony_ci *
8223d0407baSopenharmony_ci * A pointer to newly created &dma_buf_attachment on success, or a negative
8233d0407baSopenharmony_ci * error code wrapped into a pointer on failure.
8243d0407baSopenharmony_ci *
8253d0407baSopenharmony_ci * Note that this can fail if the backing storage of @dmabuf is in a place not
8263d0407baSopenharmony_ci * accessible to @dev, and cannot be moved to a more suitable place. This is
8273d0407baSopenharmony_ci * indicated with the error code -EBUSY.
8283d0407baSopenharmony_ci */
8293d0407baSopenharmony_cistruct dma_buf_attachment *dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
8303d0407baSopenharmony_ci                                                  const struct dma_buf_attach_ops *importer_ops, void *importer_priv)
8313d0407baSopenharmony_ci{
8323d0407baSopenharmony_ci    struct dma_buf_attachment *attach;
8333d0407baSopenharmony_ci    int ret;
8343d0407baSopenharmony_ci
8353d0407baSopenharmony_ci    if (WARN_ON(!dmabuf || !dev)) {
8363d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
8373d0407baSopenharmony_ci    }
8383d0407baSopenharmony_ci
8393d0407baSopenharmony_ci    if (WARN_ON(importer_ops && !importer_ops->move_notify)) {
8403d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
8413d0407baSopenharmony_ci    }
8423d0407baSopenharmony_ci
8433d0407baSopenharmony_ci    attach = kzalloc(sizeof(*attach), GFP_KERNEL);
8443d0407baSopenharmony_ci    if (!attach) {
8453d0407baSopenharmony_ci        return ERR_PTR(-ENOMEM);
8463d0407baSopenharmony_ci    }
8473d0407baSopenharmony_ci
8483d0407baSopenharmony_ci    attach->dev = dev;
8493d0407baSopenharmony_ci    attach->dmabuf = dmabuf;
8503d0407baSopenharmony_ci    if (importer_ops) {
8513d0407baSopenharmony_ci        attach->peer2peer = importer_ops->allow_peer2peer;
8523d0407baSopenharmony_ci    }
8533d0407baSopenharmony_ci    attach->importer_ops = importer_ops;
8543d0407baSopenharmony_ci    attach->importer_priv = importer_priv;
8553d0407baSopenharmony_ci
8563d0407baSopenharmony_ci    if (dmabuf->ops->attach) {
8573d0407baSopenharmony_ci        ret = dmabuf->ops->attach(dmabuf, attach);
8583d0407baSopenharmony_ci        if (ret) {
8593d0407baSopenharmony_ci            goto err_attach;
8603d0407baSopenharmony_ci        }
8613d0407baSopenharmony_ci    }
8623d0407baSopenharmony_ci    dma_resv_lock(dmabuf->resv, NULL);
8633d0407baSopenharmony_ci    list_add(&attach->node, &dmabuf->attachments);
8643d0407baSopenharmony_ci    dma_resv_unlock(dmabuf->resv);
8653d0407baSopenharmony_ci
8663d0407baSopenharmony_ci    /* When either the importer or the exporter can't handle dynamic
8673d0407baSopenharmony_ci     * mappings we cache the mapping here to avoid issues with the
8683d0407baSopenharmony_ci     * reservation object lock.
8693d0407baSopenharmony_ci     */
8703d0407baSopenharmony_ci    if (dma_buf_attachment_is_dynamic(attach) != dma_buf_is_dynamic(dmabuf)) {
8713d0407baSopenharmony_ci        struct sg_table *sgt;
8723d0407baSopenharmony_ci
8733d0407baSopenharmony_ci        if (dma_buf_is_dynamic(attach->dmabuf)) {
8743d0407baSopenharmony_ci            dma_resv_lock(attach->dmabuf->resv, NULL);
8753d0407baSopenharmony_ci            ret = dma_buf_pin(attach);
8763d0407baSopenharmony_ci            if (ret) {
8773d0407baSopenharmony_ci                goto err_unlock;
8783d0407baSopenharmony_ci            }
8793d0407baSopenharmony_ci        }
8803d0407baSopenharmony_ci
8813d0407baSopenharmony_ci        sgt = dmabuf->ops->map_dma_buf(attach, DMA_BIDIRECTIONAL);
8823d0407baSopenharmony_ci        if (!sgt) {
8833d0407baSopenharmony_ci            sgt = ERR_PTR(-ENOMEM);
8843d0407baSopenharmony_ci        }
8853d0407baSopenharmony_ci        if (IS_ERR(sgt)) {
8863d0407baSopenharmony_ci            ret = PTR_ERR(sgt);
8873d0407baSopenharmony_ci            goto err_unpin;
8883d0407baSopenharmony_ci        }
8893d0407baSopenharmony_ci        if (dma_buf_is_dynamic(attach->dmabuf)) {
8903d0407baSopenharmony_ci            dma_resv_unlock(attach->dmabuf->resv);
8913d0407baSopenharmony_ci        }
8923d0407baSopenharmony_ci        attach->sgt = sgt;
8933d0407baSopenharmony_ci        attach->dir = DMA_BIDIRECTIONAL;
8943d0407baSopenharmony_ci    }
8953d0407baSopenharmony_ci
8963d0407baSopenharmony_ci    return attach;
8973d0407baSopenharmony_ci
8983d0407baSopenharmony_cierr_attach:
8993d0407baSopenharmony_ci    kfree(attach);
9003d0407baSopenharmony_ci    return ERR_PTR(ret);
9013d0407baSopenharmony_ci
9023d0407baSopenharmony_cierr_unpin:
9033d0407baSopenharmony_ci    if (dma_buf_is_dynamic(attach->dmabuf)) {
9043d0407baSopenharmony_ci        dma_buf_unpin(attach);
9053d0407baSopenharmony_ci    }
9063d0407baSopenharmony_ci
9073d0407baSopenharmony_cierr_unlock:
9083d0407baSopenharmony_ci    if (dma_buf_is_dynamic(attach->dmabuf)) {
9093d0407baSopenharmony_ci        dma_resv_unlock(attach->dmabuf->resv);
9103d0407baSopenharmony_ci    }
9113d0407baSopenharmony_ci
9123d0407baSopenharmony_ci    dma_buf_detach(dmabuf, attach);
9133d0407baSopenharmony_ci    return ERR_PTR(ret);
9143d0407baSopenharmony_ci}
9153d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_dynamic_attach);
9163d0407baSopenharmony_ci
9173d0407baSopenharmony_ci/**
9183d0407baSopenharmony_ci * dma_buf_attach - Wrapper for dma_buf_dynamic_attach
9193d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to attach device to.
9203d0407baSopenharmony_ci * @dev:    [in]    device to be attached.
9213d0407baSopenharmony_ci *
9223d0407baSopenharmony_ci * Wrapper to call dma_buf_dynamic_attach() for drivers which still use a static
9233d0407baSopenharmony_ci * mapping.
9243d0407baSopenharmony_ci */
9253d0407baSopenharmony_cistruct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, struct device *dev)
9263d0407baSopenharmony_ci{
9273d0407baSopenharmony_ci    return dma_buf_dynamic_attach(dmabuf, dev, NULL, NULL);
9283d0407baSopenharmony_ci}
9293d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_attach);
9303d0407baSopenharmony_ci
9313d0407baSopenharmony_ci/**
9323d0407baSopenharmony_ci * dma_buf_detach - Remove the given attachment from dmabuf's attachments list;
9333d0407baSopenharmony_ci * optionally calls detach() of dma_buf_ops for device-specific detach
9343d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to detach from.
9353d0407baSopenharmony_ci * @attach:    [in]    attachment to be detached; is free'd after this call.
9363d0407baSopenharmony_ci *
9373d0407baSopenharmony_ci * Clean up a device attachment obtained by calling dma_buf_attach().
9383d0407baSopenharmony_ci */
9393d0407baSopenharmony_civoid dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
9403d0407baSopenharmony_ci{
9413d0407baSopenharmony_ci    if (WARN_ON(!dmabuf || !attach)) {
9423d0407baSopenharmony_ci        return;
9433d0407baSopenharmony_ci    }
9443d0407baSopenharmony_ci
9453d0407baSopenharmony_ci    if (attach->sgt) {
9463d0407baSopenharmony_ci        if (dma_buf_is_dynamic(attach->dmabuf)) {
9473d0407baSopenharmony_ci            dma_resv_lock(attach->dmabuf->resv, NULL);
9483d0407baSopenharmony_ci        }
9493d0407baSopenharmony_ci
9503d0407baSopenharmony_ci        dmabuf->ops->unmap_dma_buf(attach, attach->sgt, attach->dir);
9513d0407baSopenharmony_ci
9523d0407baSopenharmony_ci        if (dma_buf_is_dynamic(attach->dmabuf)) {
9533d0407baSopenharmony_ci            dma_buf_unpin(attach);
9543d0407baSopenharmony_ci            dma_resv_unlock(attach->dmabuf->resv);
9553d0407baSopenharmony_ci        }
9563d0407baSopenharmony_ci    }
9573d0407baSopenharmony_ci
9583d0407baSopenharmony_ci    dma_resv_lock(dmabuf->resv, NULL);
9593d0407baSopenharmony_ci    list_del(&attach->node);
9603d0407baSopenharmony_ci    dma_resv_unlock(dmabuf->resv);
9613d0407baSopenharmony_ci    if (dmabuf->ops->detach) {
9623d0407baSopenharmony_ci        dmabuf->ops->detach(dmabuf, attach);
9633d0407baSopenharmony_ci    }
9643d0407baSopenharmony_ci
9653d0407baSopenharmony_ci    kfree(attach);
9663d0407baSopenharmony_ci}
9673d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_detach);
9683d0407baSopenharmony_ci
9693d0407baSopenharmony_ci/**
9703d0407baSopenharmony_ci * dma_buf_unpin - Remove lock from DMA-buf
9713d0407baSopenharmony_ci *
9723d0407baSopenharmony_ci * @attach:    [in]    attachment which should be unpinned
9733d0407baSopenharmony_ci */
9743d0407baSopenharmony_civoid dma_buf_unpin(struct dma_buf_attachment *attach)
9753d0407baSopenharmony_ci{
9763d0407baSopenharmony_ci    struct dma_buf *dmabuf = attach->dmabuf;
9773d0407baSopenharmony_ci
9783d0407baSopenharmony_ci    dma_resv_assert_held(dmabuf->resv);
9793d0407baSopenharmony_ci
9803d0407baSopenharmony_ci    if (dmabuf->ops->unpin) {
9813d0407baSopenharmony_ci        dmabuf->ops->unpin(attach);
9823d0407baSopenharmony_ci    }
9833d0407baSopenharmony_ci}
9843d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_unpin);
9853d0407baSopenharmony_ci
9863d0407baSopenharmony_ci/**
9873d0407baSopenharmony_ci * dma_buf_map_attachment - Returns the scatterlist table of the attachment;
9883d0407baSopenharmony_ci * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the
9893d0407baSopenharmony_ci * dma_buf_ops.
9903d0407baSopenharmony_ci * @attach:    [in]    attachment whose scatterlist is to be returned
9913d0407baSopenharmony_ci * @direction:    [in]    direction of DMA transfer
9923d0407baSopenharmony_ci *
9933d0407baSopenharmony_ci * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR
9943d0407baSopenharmony_ci * on error. May return -EINTR if it is interrupted by a signal.
9953d0407baSopenharmony_ci *
9963d0407baSopenharmony_ci * A mapping must be unmapped by using dma_buf_unmap_attachment(). Note that
9973d0407baSopenharmony_ci * the underlying backing storage is pinned for as long as a mapping exists,
9983d0407baSopenharmony_ci * therefore users/importers should not hold onto a mapping for undue amounts of
9993d0407baSopenharmony_ci * time.
10003d0407baSopenharmony_ci */
10013d0407baSopenharmony_cistruct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction)
10023d0407baSopenharmony_ci{
10033d0407baSopenharmony_ci    struct sg_table *sg_table;
10043d0407baSopenharmony_ci    int r;
10053d0407baSopenharmony_ci
10063d0407baSopenharmony_ci    might_sleep();
10073d0407baSopenharmony_ci
10083d0407baSopenharmony_ci    if (WARN_ON(!attach || !attach->dmabuf)) {
10093d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
10103d0407baSopenharmony_ci    }
10113d0407baSopenharmony_ci
10123d0407baSopenharmony_ci    if (dma_buf_attachment_is_dynamic(attach)) {
10133d0407baSopenharmony_ci        dma_resv_assert_held(attach->dmabuf->resv);
10143d0407baSopenharmony_ci    }
10153d0407baSopenharmony_ci
10163d0407baSopenharmony_ci    if (attach->sgt) {
10173d0407baSopenharmony_ci        /*
10183d0407baSopenharmony_ci         * Two mappings with different directions for the same
10193d0407baSopenharmony_ci         * attachment are not allowed.
10203d0407baSopenharmony_ci         */
10213d0407baSopenharmony_ci        if (attach->dir != direction && attach->dir != DMA_BIDIRECTIONAL) {
10223d0407baSopenharmony_ci            return ERR_PTR(-EBUSY);
10233d0407baSopenharmony_ci        }
10243d0407baSopenharmony_ci
10253d0407baSopenharmony_ci        return attach->sgt;
10263d0407baSopenharmony_ci    }
10273d0407baSopenharmony_ci
10283d0407baSopenharmony_ci    if (dma_buf_is_dynamic(attach->dmabuf)) {
10293d0407baSopenharmony_ci        dma_resv_assert_held(attach->dmabuf->resv);
10303d0407baSopenharmony_ci        if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) {
10313d0407baSopenharmony_ci            r = dma_buf_pin(attach);
10323d0407baSopenharmony_ci            if (r) {
10333d0407baSopenharmony_ci                return ERR_PTR(r);
10343d0407baSopenharmony_ci            }
10353d0407baSopenharmony_ci        }
10363d0407baSopenharmony_ci    }
10373d0407baSopenharmony_ci
10383d0407baSopenharmony_ci    sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
10393d0407baSopenharmony_ci    if (!sg_table) {
10403d0407baSopenharmony_ci        sg_table = ERR_PTR(-ENOMEM);
10413d0407baSopenharmony_ci    }
10423d0407baSopenharmony_ci
10433d0407baSopenharmony_ci    if (IS_ERR(sg_table) && dma_buf_is_dynamic(attach->dmabuf) && !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) {
10443d0407baSopenharmony_ci        dma_buf_unpin(attach);
10453d0407baSopenharmony_ci    }
10463d0407baSopenharmony_ci
10473d0407baSopenharmony_ci    if (!IS_ERR(sg_table) && attach->dmabuf->ops->cache_sgt_mapping) {
10483d0407baSopenharmony_ci        attach->sgt = sg_table;
10493d0407baSopenharmony_ci        attach->dir = direction;
10503d0407baSopenharmony_ci    }
10513d0407baSopenharmony_ci
10523d0407baSopenharmony_ci    return sg_table;
10533d0407baSopenharmony_ci}
10543d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_map_attachment);
10553d0407baSopenharmony_ci
10563d0407baSopenharmony_ci/**
10573d0407baSopenharmony_ci * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might
10583d0407baSopenharmony_ci * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of
10593d0407baSopenharmony_ci * dma_buf_ops.
10603d0407baSopenharmony_ci * @attach:    [in]    attachment to unmap buffer from
10613d0407baSopenharmony_ci * @sg_table:    [in]    scatterlist info of the buffer to unmap
10623d0407baSopenharmony_ci * @direction:  [in]    direction of DMA transfer
10633d0407baSopenharmony_ci *
10643d0407baSopenharmony_ci * This unmaps a DMA mapping for @attached obtained by dma_buf_map_attachment().
10653d0407baSopenharmony_ci */
10663d0407baSopenharmony_civoid dma_buf_unmap_attachment(struct dma_buf_attachment *attach, struct sg_table *sg_table,
10673d0407baSopenharmony_ci                              enum dma_data_direction direction)
10683d0407baSopenharmony_ci{
10693d0407baSopenharmony_ci    might_sleep();
10703d0407baSopenharmony_ci
10713d0407baSopenharmony_ci    if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) {
10723d0407baSopenharmony_ci        return;
10733d0407baSopenharmony_ci    }
10743d0407baSopenharmony_ci
10753d0407baSopenharmony_ci    if (dma_buf_attachment_is_dynamic(attach)) {
10763d0407baSopenharmony_ci        dma_resv_assert_held(attach->dmabuf->resv);
10773d0407baSopenharmony_ci    }
10783d0407baSopenharmony_ci
10793d0407baSopenharmony_ci    if (attach->sgt == sg_table) {
10803d0407baSopenharmony_ci        return;
10813d0407baSopenharmony_ci    }
10823d0407baSopenharmony_ci
10833d0407baSopenharmony_ci    if (dma_buf_is_dynamic(attach->dmabuf)) {
10843d0407baSopenharmony_ci        dma_resv_assert_held(attach->dmabuf->resv);
10853d0407baSopenharmony_ci    }
10863d0407baSopenharmony_ci
10873d0407baSopenharmony_ci    attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction);
10883d0407baSopenharmony_ci
10893d0407baSopenharmony_ci    if (dma_buf_is_dynamic(attach->dmabuf) && !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) {
10903d0407baSopenharmony_ci        dma_buf_unpin(attach);
10913d0407baSopenharmony_ci    }
10923d0407baSopenharmony_ci}
10933d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
10943d0407baSopenharmony_ci
10953d0407baSopenharmony_ci/**
10963d0407baSopenharmony_ci * dma_buf_move_notify - notify attachments that DMA-buf is moving
10973d0407baSopenharmony_ci *
10983d0407baSopenharmony_ci * @dmabuf:    [in]    buffer which is moving
10993d0407baSopenharmony_ci *
11003d0407baSopenharmony_ci * Informs all attachmenst that they need to destroy and recreated all their
11013d0407baSopenharmony_ci * mappings.
11023d0407baSopenharmony_ci */
11033d0407baSopenharmony_civoid dma_buf_move_notify(struct dma_buf *dmabuf)
11043d0407baSopenharmony_ci{
11053d0407baSopenharmony_ci    struct dma_buf_attachment *attach;
11063d0407baSopenharmony_ci
11073d0407baSopenharmony_ci    dma_resv_assert_held(dmabuf->resv);
11083d0407baSopenharmony_ci
11093d0407baSopenharmony_ci    list_for_each_entry(attach, &dmabuf->attachments, node) if (attach->importer_ops)
11103d0407baSopenharmony_ci        attach->importer_ops->move_notify(attach);
11113d0407baSopenharmony_ci}
11123d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_move_notify);
11133d0407baSopenharmony_ci
11143d0407baSopenharmony_ci/**
11153d0407baSopenharmony_ci * DOC: cpu access
11163d0407baSopenharmony_ci *
11173d0407baSopenharmony_ci * There are mutliple reasons for supporting CPU access to a dma buffer object:
11183d0407baSopenharmony_ci *
11193d0407baSopenharmony_ci * - Fallback operations in the kernel, for example when a device is connected
11203d0407baSopenharmony_ci *   over USB and the kernel needs to shuffle the data around first before
11213d0407baSopenharmony_ci *   sending it away. Cache coherency is handled by braketing any transactions
11223d0407baSopenharmony_ci *   with calls to dma_buf_begin_cpu_access() and dma_buf_end_cpu_access()
11233d0407baSopenharmony_ci *   access.
11243d0407baSopenharmony_ci *
11253d0407baSopenharmony_ci *   Since for most kernel internal dma-buf accesses need the entire buffer, a
11263d0407baSopenharmony_ci *   vmap interface is introduced. Note that on very old 32-bit architectures
11273d0407baSopenharmony_ci *   vmalloc space might be limited and result in vmap calls failing.
11283d0407baSopenharmony_ci *
11293d0407baSopenharmony_ci *   Interfaces::
11303d0407baSopenharmony_ci *      void \*dma_buf_vmap(struct dma_buf \*dmabuf)
11313d0407baSopenharmony_ci *      void dma_buf_vunmap(struct dma_buf \*dmabuf, void \*vaddr)
11323d0407baSopenharmony_ci *
11333d0407baSopenharmony_ci *   The vmap call can fail if there is no vmap support in the exporter, or if
11343d0407baSopenharmony_ci *   it runs out of vmalloc space. Fallback to kmap should be implemented. Note
11353d0407baSopenharmony_ci *   that the dma-buf layer keeps a reference count for all vmap access and
11363d0407baSopenharmony_ci *   calls down into the exporter's vmap function only when no vmapping exists,
11373d0407baSopenharmony_ci *   and only unmaps it once. Protection against concurrent vmap/vunmap calls is
11383d0407baSopenharmony_ci *   provided by taking the dma_buf->lock mutex.
11393d0407baSopenharmony_ci *
11403d0407baSopenharmony_ci * - For full compatibility on the importer side with existing userspace
11413d0407baSopenharmony_ci *   interfaces, which might already support mmap'ing buffers. This is needed in
11423d0407baSopenharmony_ci *   many processing pipelines (e.g. feeding a software rendered image into a
11433d0407baSopenharmony_ci *   hardware pipeline, thumbnail creation, snapshots, ...). Also, Android's ION
11443d0407baSopenharmony_ci *   framework already supported this and for DMA buffer file descriptors to
11453d0407baSopenharmony_ci *   replace ION buffers mmap support was needed.
11463d0407baSopenharmony_ci *
11473d0407baSopenharmony_ci *   There is no special interfaces, userspace simply calls mmap on the dma-buf
11483d0407baSopenharmony_ci *   fd. But like for CPU access there's a need to braket the actual access,
11493d0407baSopenharmony_ci *   which is handled by the ioctl (DMA_BUF_IOCTL_SYNC). Note that
11503d0407baSopenharmony_ci *   DMA_BUF_IOCTL_SYNC can fail with -EAGAIN or -EINTR, in which case it must
11513d0407baSopenharmony_ci *   be restarted.
11523d0407baSopenharmony_ci *
11533d0407baSopenharmony_ci *   Some systems might need some sort of cache coherency management e.g. when
11543d0407baSopenharmony_ci *   CPU and GPU domains are being accessed through dma-buf at the same time.
11553d0407baSopenharmony_ci *   To circumvent this problem there are begin/end coherency markers, that
11563d0407baSopenharmony_ci *   forward directly to existing dma-buf device drivers vfunc hooks. Userspace
11573d0407baSopenharmony_ci *   can make use of those markers through the DMA_BUF_IOCTL_SYNC ioctl. The
11583d0407baSopenharmony_ci *   sequence would be used like following:
11593d0407baSopenharmony_ci *
11603d0407baSopenharmony_ci *     - mmap dma-buf fd
11613d0407baSopenharmony_ci *     - for each drawing/upload cycle in CPU 1. SYNC_START ioctl, 2. read/write
11623d0407baSopenharmony_ci *       to mmap area 3. SYNC_END ioctl. This can be repeated as often as you
11633d0407baSopenharmony_ci *       want (with the new data being consumed by say the GPU or the scanout
11643d0407baSopenharmony_ci *       device)
11653d0407baSopenharmony_ci *     - munmap once you don't need the buffer any more
11663d0407baSopenharmony_ci *
11673d0407baSopenharmony_ci *    For correctness and optimal performance, it is always required to use
11683d0407baSopenharmony_ci *    SYNC_START and SYNC_END before and after, respectively, when accessing the
11693d0407baSopenharmony_ci *    mapped address. Userspace cannot rely on coherent access, even when there
11703d0407baSopenharmony_ci *    are systems where it just works without calling these ioctls.
11713d0407baSopenharmony_ci *
11723d0407baSopenharmony_ci * - And as a CPU fallback in userspace processing pipelines.
11733d0407baSopenharmony_ci *
11743d0407baSopenharmony_ci *   Similar to the motivation for kernel cpu access it is again important that
11753d0407baSopenharmony_ci *   the userspace code of a given importing subsystem can use the same
11763d0407baSopenharmony_ci *   interfaces with a imported dma-buf buffer object as with a native buffer
11773d0407baSopenharmony_ci *   object. This is especially important for drm where the userspace part of
11783d0407baSopenharmony_ci *   contemporary OpenGL, X, and other drivers is huge, and reworking them to
11793d0407baSopenharmony_ci *   use a different way to mmap a buffer rather invasive.
11803d0407baSopenharmony_ci *
11813d0407baSopenharmony_ci *   The assumption in the current dma-buf interfaces is that redirecting the
11823d0407baSopenharmony_ci *   initial mmap is all that's needed. A survey of some of the existing
11833d0407baSopenharmony_ci *   subsystems shows that no driver seems to do any nefarious thing like
11843d0407baSopenharmony_ci *   syncing up with outstanding asynchronous processing on the device or
11853d0407baSopenharmony_ci *   allocating special resources at fault time. So hopefully this is good
11863d0407baSopenharmony_ci *   enough, since adding interfaces to intercept pagefaults and allow pte
11873d0407baSopenharmony_ci *   shootdowns would increase the complexity quite a bit.
11883d0407baSopenharmony_ci *
11893d0407baSopenharmony_ci *   Interface::
11903d0407baSopenharmony_ci *      int dma_buf_mmap(struct dma_buf \*, struct vm_area_struct \*,
11913d0407baSopenharmony_ci *               unsigned long);
11923d0407baSopenharmony_ci *
11933d0407baSopenharmony_ci *   If the importing subsystem simply provides a special-purpose mmap call to
11943d0407baSopenharmony_ci *   set up a mapping in userspace, calling do_mmap with dma_buf->file will
11953d0407baSopenharmony_ci *   equally achieve that for a dma-buf object.
11963d0407baSopenharmony_ci */
11973d0407baSopenharmony_ci
11983d0407baSopenharmony_cistatic int _dma_buf_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction direction)
11993d0407baSopenharmony_ci{
12003d0407baSopenharmony_ci    bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE);
12013d0407baSopenharmony_ci    struct dma_resv *resv = dmabuf->resv;
12023d0407baSopenharmony_ci    long ret;
12033d0407baSopenharmony_ci
12043d0407baSopenharmony_ci    /* Wait on any implicit rendering fences */
12053d0407baSopenharmony_ci    ret = dma_resv_wait_timeout_rcu(resv, write, true, MAX_SCHEDULE_TIMEOUT);
12063d0407baSopenharmony_ci    if (ret < 0) {
12073d0407baSopenharmony_ci        return ret;
12083d0407baSopenharmony_ci    }
12093d0407baSopenharmony_ci
12103d0407baSopenharmony_ci    return 0;
12113d0407baSopenharmony_ci}
12123d0407baSopenharmony_ci
12133d0407baSopenharmony_ci/**
12143d0407baSopenharmony_ci * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
12153d0407baSopenharmony_ci * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
12163d0407baSopenharmony_ci * preparations. Coherency is only guaranteed in the specified range for the
12173d0407baSopenharmony_ci * specified access direction.
12183d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to prepare cpu access for.
12193d0407baSopenharmony_ci * @direction:    [in]    length of range for cpu access.
12203d0407baSopenharmony_ci *
12213d0407baSopenharmony_ci * After the cpu access is complete the caller should call
12223d0407baSopenharmony_ci * dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is
12233d0407baSopenharmony_ci * it guaranteed to be coherent with other DMA access.
12243d0407baSopenharmony_ci *
12253d0407baSopenharmony_ci * Can return negative error values, returns 0 on success.
12263d0407baSopenharmony_ci */
12273d0407baSopenharmony_ciint dma_buf_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction direction)
12283d0407baSopenharmony_ci{
12293d0407baSopenharmony_ci    int ret = 0;
12303d0407baSopenharmony_ci
12313d0407baSopenharmony_ci    if (WARN_ON(!dmabuf)) {
12323d0407baSopenharmony_ci        return -EINVAL;
12333d0407baSopenharmony_ci    }
12343d0407baSopenharmony_ci
12353d0407baSopenharmony_ci    if (dmabuf->ops->begin_cpu_access) {
12363d0407baSopenharmony_ci        ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
12373d0407baSopenharmony_ci    }
12383d0407baSopenharmony_ci
12393d0407baSopenharmony_ci    /* Ensure that all fences are waited upon - but we first allow
12403d0407baSopenharmony_ci     * the native handler the chance to do so more efficiently if it
12413d0407baSopenharmony_ci     * chooses. A double invocation here will be reasonably cheap no-op.
12423d0407baSopenharmony_ci     */
12433d0407baSopenharmony_ci    if (ret == 0) {
12443d0407baSopenharmony_ci        ret = _dma_buf_begin_cpu_access(dmabuf, direction);
12453d0407baSopenharmony_ci    }
12463d0407baSopenharmony_ci
12473d0407baSopenharmony_ci    return ret;
12483d0407baSopenharmony_ci}
12493d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
12503d0407baSopenharmony_ci
12513d0407baSopenharmony_ciint dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, enum dma_data_direction direction, unsigned int offset,
12523d0407baSopenharmony_ci                                     unsigned int len)
12533d0407baSopenharmony_ci{
12543d0407baSopenharmony_ci    int ret = 0;
12553d0407baSopenharmony_ci
12563d0407baSopenharmony_ci    if (WARN_ON(!dmabuf)) {
12573d0407baSopenharmony_ci        return -EINVAL;
12583d0407baSopenharmony_ci    }
12593d0407baSopenharmony_ci
12603d0407baSopenharmony_ci    if (dmabuf->ops->begin_cpu_access_partial) {
12613d0407baSopenharmony_ci        ret = dmabuf->ops->begin_cpu_access_partial(dmabuf, direction, offset, len);
12623d0407baSopenharmony_ci    }
12633d0407baSopenharmony_ci
12643d0407baSopenharmony_ci    /* Ensure that all fences are waited upon - but we first allow
12653d0407baSopenharmony_ci     * the native handler the chance to do so more efficiently if it
12663d0407baSopenharmony_ci     * chooses. A double invocation here will be reasonably cheap no-op.
12673d0407baSopenharmony_ci     */
12683d0407baSopenharmony_ci    if (ret == 0) {
12693d0407baSopenharmony_ci        ret = _dma_buf_begin_cpu_access(dmabuf, direction);
12703d0407baSopenharmony_ci    }
12713d0407baSopenharmony_ci
12723d0407baSopenharmony_ci    return ret;
12733d0407baSopenharmony_ci}
12743d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access_partial);
12753d0407baSopenharmony_ci
12763d0407baSopenharmony_ci/**
12773d0407baSopenharmony_ci * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the
12783d0407baSopenharmony_ci * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
12793d0407baSopenharmony_ci * actions. Coherency is only guaranteed in the specified range for the
12803d0407baSopenharmony_ci * specified access direction.
12813d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to complete cpu access for.
12823d0407baSopenharmony_ci * @direction:    [in]    length of range for cpu access.
12833d0407baSopenharmony_ci *
12843d0407baSopenharmony_ci * This terminates CPU access started with dma_buf_begin_cpu_access().
12853d0407baSopenharmony_ci *
12863d0407baSopenharmony_ci * Can return negative error values, returns 0 on success.
12873d0407baSopenharmony_ci */
12883d0407baSopenharmony_ciint dma_buf_end_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction direction)
12893d0407baSopenharmony_ci{
12903d0407baSopenharmony_ci    int ret = 0;
12913d0407baSopenharmony_ci
12923d0407baSopenharmony_ci    WARN_ON(!dmabuf);
12933d0407baSopenharmony_ci
12943d0407baSopenharmony_ci    if (dmabuf->ops->end_cpu_access) {
12953d0407baSopenharmony_ci        ret = dmabuf->ops->end_cpu_access(dmabuf, direction);
12963d0407baSopenharmony_ci    }
12973d0407baSopenharmony_ci
12983d0407baSopenharmony_ci    return ret;
12993d0407baSopenharmony_ci}
13003d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
13013d0407baSopenharmony_ci
13023d0407baSopenharmony_ciint dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, enum dma_data_direction direction, unsigned int offset,
13033d0407baSopenharmony_ci                                   unsigned int len)
13043d0407baSopenharmony_ci{
13053d0407baSopenharmony_ci    int ret = 0;
13063d0407baSopenharmony_ci
13073d0407baSopenharmony_ci    WARN_ON(!dmabuf);
13083d0407baSopenharmony_ci
13093d0407baSopenharmony_ci    if (dmabuf->ops->end_cpu_access_partial) {
13103d0407baSopenharmony_ci        ret = dmabuf->ops->end_cpu_access_partial(dmabuf, direction, offset, len);
13113d0407baSopenharmony_ci    }
13123d0407baSopenharmony_ci
13133d0407baSopenharmony_ci    return ret;
13143d0407baSopenharmony_ci}
13153d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_end_cpu_access_partial);
13163d0407baSopenharmony_ci
13173d0407baSopenharmony_ci/**
13183d0407baSopenharmony_ci * dma_buf_mmap - Setup up a userspace mmap with the given vma
13193d0407baSopenharmony_ci * @dmabuf:    [in]    buffer that should back the vma
13203d0407baSopenharmony_ci * @vma:    [in]    vma for the mmap
13213d0407baSopenharmony_ci * @pgoff:    [in]    offset in pages where this mmap should start within the
13223d0407baSopenharmony_ci *            dma-buf buffer.
13233d0407baSopenharmony_ci *
13243d0407baSopenharmony_ci * This function adjusts the passed in vma so that it points at the file of the
13253d0407baSopenharmony_ci * dma_buf operation. It also adjusts the starting pgoff and does bounds
13263d0407baSopenharmony_ci * checking on the size of the vma. Then it calls the exporters mmap function to
13273d0407baSopenharmony_ci * set up the mapping.
13283d0407baSopenharmony_ci *
13293d0407baSopenharmony_ci * Can return negative error values, returns 0 on success.
13303d0407baSopenharmony_ci */
13313d0407baSopenharmony_ciint dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, unsigned long pgoff)
13323d0407baSopenharmony_ci{
13333d0407baSopenharmony_ci    struct file *oldfile;
13343d0407baSopenharmony_ci    int ret;
13353d0407baSopenharmony_ci
13363d0407baSopenharmony_ci    if (WARN_ON(!dmabuf || !vma)) {
13373d0407baSopenharmony_ci        return -EINVAL;
13383d0407baSopenharmony_ci    }
13393d0407baSopenharmony_ci
13403d0407baSopenharmony_ci    /* check if buffer supports mmap */
13413d0407baSopenharmony_ci    if (!dmabuf->ops->mmap) {
13423d0407baSopenharmony_ci        return -EINVAL;
13433d0407baSopenharmony_ci    }
13443d0407baSopenharmony_ci
13453d0407baSopenharmony_ci    /* check for offset overflow */
13463d0407baSopenharmony_ci    if (pgoff + vma_pages(vma) < pgoff) {
13473d0407baSopenharmony_ci        return -EOVERFLOW;
13483d0407baSopenharmony_ci    }
13493d0407baSopenharmony_ci
13503d0407baSopenharmony_ci    /* check for overflowing the buffer's size */
13513d0407baSopenharmony_ci    if ((pgoff + vma_pages(vma)) > (dmabuf->size >> PAGE_SHIFT)) {
13523d0407baSopenharmony_ci        return -EINVAL;
13533d0407baSopenharmony_ci    }
13543d0407baSopenharmony_ci
13553d0407baSopenharmony_ci    /* readjust the vma */
13563d0407baSopenharmony_ci    get_file(dmabuf->file);
13573d0407baSopenharmony_ci    oldfile = vma->vm_file;
13583d0407baSopenharmony_ci    vma->vm_file = dmabuf->file;
13593d0407baSopenharmony_ci    vma->vm_pgoff = pgoff;
13603d0407baSopenharmony_ci
13613d0407baSopenharmony_ci    ret = dmabuf->ops->mmap(dmabuf, vma);
13623d0407baSopenharmony_ci    if (ret) {
13633d0407baSopenharmony_ci        /* restore old parameters on failure */
13643d0407baSopenharmony_ci        vma->vm_file = oldfile;
13653d0407baSopenharmony_ci        fput(dmabuf->file);
13663d0407baSopenharmony_ci    } else {
13673d0407baSopenharmony_ci        if (oldfile) {
13683d0407baSopenharmony_ci            fput(oldfile);
13693d0407baSopenharmony_ci        }
13703d0407baSopenharmony_ci    }
13713d0407baSopenharmony_ci    return ret;
13723d0407baSopenharmony_ci}
13733d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_mmap);
13743d0407baSopenharmony_ci
13753d0407baSopenharmony_ci/**
13763d0407baSopenharmony_ci * dma_buf_vmap - Create virtual mapping for the buffer object into kernel
13773d0407baSopenharmony_ci * address space. Same restrictions as for vmap and friends apply.
13783d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to vmap
13793d0407baSopenharmony_ci *
13803d0407baSopenharmony_ci * This call may fail due to lack of virtual mapping address space.
13813d0407baSopenharmony_ci * These calls are optional in drivers. The intended use for them
13823d0407baSopenharmony_ci * is for mapping objects linear in kernel space for high use objects.
13833d0407baSopenharmony_ci * Please attempt to use kmap/kunmap before thinking about these interfaces.
13843d0407baSopenharmony_ci *
13853d0407baSopenharmony_ci * Returns NULL on error.
13863d0407baSopenharmony_ci */
13873d0407baSopenharmony_civoid *dma_buf_vmap(struct dma_buf *dmabuf)
13883d0407baSopenharmony_ci{
13893d0407baSopenharmony_ci    void *ptr;
13903d0407baSopenharmony_ci
13913d0407baSopenharmony_ci    if (WARN_ON(!dmabuf)) {
13923d0407baSopenharmony_ci        return NULL;
13933d0407baSopenharmony_ci    }
13943d0407baSopenharmony_ci
13953d0407baSopenharmony_ci    if (!dmabuf->ops->vmap) {
13963d0407baSopenharmony_ci        return NULL;
13973d0407baSopenharmony_ci    }
13983d0407baSopenharmony_ci
13993d0407baSopenharmony_ci    mutex_lock(&dmabuf->lock);
14003d0407baSopenharmony_ci    if (dmabuf->vmapping_counter) {
14013d0407baSopenharmony_ci        dmabuf->vmapping_counter++;
14023d0407baSopenharmony_ci        BUG_ON(!dmabuf->vmap_ptr);
14033d0407baSopenharmony_ci        ptr = dmabuf->vmap_ptr;
14043d0407baSopenharmony_ci        goto out_unlock;
14053d0407baSopenharmony_ci    }
14063d0407baSopenharmony_ci
14073d0407baSopenharmony_ci    BUG_ON(dmabuf->vmap_ptr);
14083d0407baSopenharmony_ci
14093d0407baSopenharmony_ci    ptr = dmabuf->ops->vmap(dmabuf);
14103d0407baSopenharmony_ci    if (WARN_ON_ONCE(IS_ERR(ptr))) {
14113d0407baSopenharmony_ci        ptr = NULL;
14123d0407baSopenharmony_ci    }
14133d0407baSopenharmony_ci    if (!ptr) {
14143d0407baSopenharmony_ci        goto out_unlock;
14153d0407baSopenharmony_ci    }
14163d0407baSopenharmony_ci
14173d0407baSopenharmony_ci    dmabuf->vmap_ptr = ptr;
14183d0407baSopenharmony_ci    dmabuf->vmapping_counter = 1;
14193d0407baSopenharmony_ci
14203d0407baSopenharmony_ciout_unlock:
14213d0407baSopenharmony_ci    mutex_unlock(&dmabuf->lock);
14223d0407baSopenharmony_ci    return ptr;
14233d0407baSopenharmony_ci}
14243d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_vmap);
14253d0407baSopenharmony_ci
14263d0407baSopenharmony_ci/**
14273d0407baSopenharmony_ci * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap.
14283d0407baSopenharmony_ci * @dmabuf:    [in]    buffer to vunmap
14293d0407baSopenharmony_ci * @vaddr:    [in]    vmap to vunmap
14303d0407baSopenharmony_ci */
14313d0407baSopenharmony_civoid dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
14323d0407baSopenharmony_ci{
14333d0407baSopenharmony_ci    if (WARN_ON(!dmabuf)) {
14343d0407baSopenharmony_ci        return;
14353d0407baSopenharmony_ci    }
14363d0407baSopenharmony_ci
14373d0407baSopenharmony_ci    BUG_ON(!dmabuf->vmap_ptr);
14383d0407baSopenharmony_ci    BUG_ON(dmabuf->vmapping_counter == 0);
14393d0407baSopenharmony_ci    BUG_ON(dmabuf->vmap_ptr != vaddr);
14403d0407baSopenharmony_ci
14413d0407baSopenharmony_ci    mutex_lock(&dmabuf->lock);
14423d0407baSopenharmony_ci    if (--dmabuf->vmapping_counter == 0) {
14433d0407baSopenharmony_ci        if (dmabuf->ops->vunmap) {
14443d0407baSopenharmony_ci            dmabuf->ops->vunmap(dmabuf, vaddr);
14453d0407baSopenharmony_ci        }
14463d0407baSopenharmony_ci        dmabuf->vmap_ptr = NULL;
14473d0407baSopenharmony_ci    }
14483d0407baSopenharmony_ci    mutex_unlock(&dmabuf->lock);
14493d0407baSopenharmony_ci}
14503d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_vunmap);
14513d0407baSopenharmony_ci
14523d0407baSopenharmony_ciint dma_buf_get_flags(struct dma_buf *dmabuf, unsigned long *flags)
14533d0407baSopenharmony_ci{
14543d0407baSopenharmony_ci    int ret = 0;
14553d0407baSopenharmony_ci
14563d0407baSopenharmony_ci    if (WARN_ON(!dmabuf) || !flags) {
14573d0407baSopenharmony_ci        return -EINVAL;
14583d0407baSopenharmony_ci    }
14593d0407baSopenharmony_ci
14603d0407baSopenharmony_ci    if (dmabuf->ops->get_flags) {
14613d0407baSopenharmony_ci        ret = dmabuf->ops->get_flags(dmabuf, flags);
14623d0407baSopenharmony_ci    }
14633d0407baSopenharmony_ci
14643d0407baSopenharmony_ci    return ret;
14653d0407baSopenharmony_ci}
14663d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_get_flags);
14673d0407baSopenharmony_ci
14683d0407baSopenharmony_ciint dma_buf_get_uuid(struct dma_buf *dmabuf, uuid_t *uuid)
14693d0407baSopenharmony_ci{
14703d0407baSopenharmony_ci    if (WARN_ON(!dmabuf) || !uuid) {
14713d0407baSopenharmony_ci        return -EINVAL;
14723d0407baSopenharmony_ci    }
14733d0407baSopenharmony_ci
14743d0407baSopenharmony_ci    if (!dmabuf->ops->get_uuid) {
14753d0407baSopenharmony_ci        return -ENODEV;
14763d0407baSopenharmony_ci    }
14773d0407baSopenharmony_ci
14783d0407baSopenharmony_ci    return dmabuf->ops->get_uuid(dmabuf, uuid);
14793d0407baSopenharmony_ci}
14803d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(dma_buf_get_uuid);
14813d0407baSopenharmony_ci
14823d0407baSopenharmony_ci#ifdef CONFIG_DEBUG_FS
14833d0407baSopenharmony_cistatic int dma_buf_debug_show(struct seq_file *s, void *unused)
14843d0407baSopenharmony_ci{
14853d0407baSopenharmony_ci    int ret;
14863d0407baSopenharmony_ci    struct dma_buf *buf_obj;
14873d0407baSopenharmony_ci    struct dma_buf_attachment *attach_obj;
14883d0407baSopenharmony_ci    struct dma_resv *robj;
14893d0407baSopenharmony_ci    struct dma_resv_list *fobj;
14903d0407baSopenharmony_ci    struct dma_fence *fence;
14913d0407baSopenharmony_ci    unsigned seq;
14923d0407baSopenharmony_ci    int count = 0, attach_count, shared_count, i;
14933d0407baSopenharmony_ci    size_t size = 0;
14943d0407baSopenharmony_ci
14953d0407baSopenharmony_ci    ret = mutex_lock_interruptible(&db_list.lock);
14963d0407baSopenharmony_ci    if (ret) {
14973d0407baSopenharmony_ci        return ret;
14983d0407baSopenharmony_ci    }
14993d0407baSopenharmony_ci
15003d0407baSopenharmony_ci    seq_puts(s, "\nDma-buf Objects:\n");
15013d0407baSopenharmony_ci    seq_printf(s,
15023d0407baSopenharmony_ci               "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\t"
15033d0407baSopenharmony_ci               "%-16s\t%-16s\t%-16s\n",
15043d0407baSopenharmony_ci               "size", "flags", "mode", "count", "ino", "buf_name", "exp_pid", "exp_task_comm");
15053d0407baSopenharmony_ci
15063d0407baSopenharmony_ci    list_for_each_entry(buf_obj, &db_list.head, list_node)
15073d0407baSopenharmony_ci    {
15083d0407baSopenharmony_ci        ret = dma_resv_lock_interruptible(buf_obj->resv, NULL);
15093d0407baSopenharmony_ci        if (ret) {
15103d0407baSopenharmony_ci            goto error_unlock;
15113d0407baSopenharmony_ci        }
15123d0407baSopenharmony_ci
15133d0407baSopenharmony_ci        seq_printf(s,
15143d0407baSopenharmony_ci                   "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\t"
15153d0407baSopenharmony_ci                   "%-16d\t%-16s\n",
15163d0407baSopenharmony_ci                   buf_obj->size, buf_obj->file->f_flags, buf_obj->file->f_mode, file_count(buf_obj->file),
15173d0407baSopenharmony_ci                   buf_obj->exp_name, file_inode(buf_obj->file)->i_ino, buf_obj->name ?: "NULL",
15183d0407baSopenharmony_ci                   dma_buf_exp_pid(buf_obj), dma_buf_exp_task_comm(buf_obj) ?: "NULL");
15193d0407baSopenharmony_ci
15203d0407baSopenharmony_ci        robj = buf_obj->resv;
15213d0407baSopenharmony_ci        while (true) {
15223d0407baSopenharmony_ci            seq = read_seqcount_begin(&robj->seq);
15233d0407baSopenharmony_ci            rcu_read_lock();
15243d0407baSopenharmony_ci            fobj = rcu_dereference(robj->fence);
15253d0407baSopenharmony_ci            shared_count = fobj ? fobj->shared_count : 0;
15263d0407baSopenharmony_ci            fence = rcu_dereference(robj->fence_excl);
15273d0407baSopenharmony_ci            if (!read_seqcount_retry(&robj->seq, seq)) {
15283d0407baSopenharmony_ci                break;
15293d0407baSopenharmony_ci            }
15303d0407baSopenharmony_ci            rcu_read_unlock();
15313d0407baSopenharmony_ci        }
15323d0407baSopenharmony_ci
15333d0407baSopenharmony_ci        if (fence) {
15343d0407baSopenharmony_ci            seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n", fence->ops->get_driver_name(fence),
15353d0407baSopenharmony_ci                       fence->ops->get_timeline_name(fence), dma_fence_is_signaled(fence) ? "" : "un");
15363d0407baSopenharmony_ci        }
15373d0407baSopenharmony_ci        for (i = 0; i < shared_count; i++) {
15383d0407baSopenharmony_ci            fence = rcu_dereference(fobj->shared[i]);
15393d0407baSopenharmony_ci            if (!dma_fence_get_rcu(fence)) {
15403d0407baSopenharmony_ci                continue;
15413d0407baSopenharmony_ci            }
15423d0407baSopenharmony_ci            seq_printf(s, "\tShared fence: %s %s %ssignalled\n", fence->ops->get_driver_name(fence),
15433d0407baSopenharmony_ci                       fence->ops->get_timeline_name(fence), dma_fence_is_signaled(fence) ? "" : "un");
15443d0407baSopenharmony_ci            dma_fence_put(fence);
15453d0407baSopenharmony_ci        }
15463d0407baSopenharmony_ci        rcu_read_unlock();
15473d0407baSopenharmony_ci
15483d0407baSopenharmony_ci        seq_puts(s, "\tAttached Devices:\n");
15493d0407baSopenharmony_ci        attach_count = 0;
15503d0407baSopenharmony_ci
15513d0407baSopenharmony_ci        list_for_each_entry(attach_obj, &buf_obj->attachments, node)
15523d0407baSopenharmony_ci        {
15533d0407baSopenharmony_ci            seq_printf(s, "\t%s\n", dev_name(attach_obj->dev));
15543d0407baSopenharmony_ci            attach_count++;
15553d0407baSopenharmony_ci        }
15563d0407baSopenharmony_ci        dma_resv_unlock(buf_obj->resv);
15573d0407baSopenharmony_ci
15583d0407baSopenharmony_ci        seq_printf(s, "Total %d devices attached\n\n", attach_count);
15593d0407baSopenharmony_ci
15603d0407baSopenharmony_ci        count++;
15613d0407baSopenharmony_ci        size += buf_obj->size;
15623d0407baSopenharmony_ci    }
15633d0407baSopenharmony_ci
15643d0407baSopenharmony_ci    seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size);
15653d0407baSopenharmony_ci
15663d0407baSopenharmony_ci    mutex_unlock(&db_list.lock);
15673d0407baSopenharmony_ci    return 0;
15683d0407baSopenharmony_ci
15693d0407baSopenharmony_cierror_unlock:
15703d0407baSopenharmony_ci    mutex_unlock(&db_list.lock);
15713d0407baSopenharmony_ci    return ret;
15723d0407baSopenharmony_ci}
15733d0407baSopenharmony_ci
15743d0407baSopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dma_buf_debug);
15753d0407baSopenharmony_ci
15763d0407baSopenharmony_cistatic struct dentry *dma_buf_debugfs_dir;
15773d0407baSopenharmony_ci
15783d0407baSopenharmony_cistatic int dma_buf_init_debugfs(void)
15793d0407baSopenharmony_ci{
15803d0407baSopenharmony_ci    struct dentry *d;
15813d0407baSopenharmony_ci    int err = 0;
15823d0407baSopenharmony_ci
15833d0407baSopenharmony_ci    d = debugfs_create_dir("dma_buf", NULL);
15843d0407baSopenharmony_ci    if (IS_ERR(d)) {
15853d0407baSopenharmony_ci        return PTR_ERR(d);
15863d0407baSopenharmony_ci    }
15873d0407baSopenharmony_ci
15883d0407baSopenharmony_ci    dma_buf_debugfs_dir = d;
15893d0407baSopenharmony_ci
15903d0407baSopenharmony_ci    d = debugfs_create_file("bufinfo", S_IRUGO, dma_buf_debugfs_dir, NULL, &dma_buf_debug_fops);
15913d0407baSopenharmony_ci    if (IS_ERR(d)) {
15923d0407baSopenharmony_ci        pr_debug("dma_buf: debugfs: failed to create node bufinfo\n");
15933d0407baSopenharmony_ci        debugfs_remove_recursive(dma_buf_debugfs_dir);
15943d0407baSopenharmony_ci        dma_buf_debugfs_dir = NULL;
15953d0407baSopenharmony_ci        err = PTR_ERR(d);
15963d0407baSopenharmony_ci    }
15973d0407baSopenharmony_ci
15983d0407baSopenharmony_ci    dma_buf_process_info_init_debugfs(dma_buf_debugfs_dir);
15993d0407baSopenharmony_ci    return err;
16003d0407baSopenharmony_ci}
16013d0407baSopenharmony_ci
16023d0407baSopenharmony_cistatic void dma_buf_uninit_debugfs(void)
16033d0407baSopenharmony_ci{
16043d0407baSopenharmony_ci    debugfs_remove_recursive(dma_buf_debugfs_dir);
16053d0407baSopenharmony_ci}
16063d0407baSopenharmony_ci#else
16073d0407baSopenharmony_cistatic inline int dma_buf_init_debugfs(void)
16083d0407baSopenharmony_ci{
16093d0407baSopenharmony_ci    return 0;
16103d0407baSopenharmony_ci}
16113d0407baSopenharmony_cistatic inline void dma_buf_uninit_debugfs(void)
16123d0407baSopenharmony_ci{
16133d0407baSopenharmony_ci}
16143d0407baSopenharmony_ci#endif
16153d0407baSopenharmony_ci
16163d0407baSopenharmony_ci#ifdef CONFIG_DMABUF_PROCESS_INFO
16173d0407baSopenharmony_cistruct dma_buf *get_dma_buf_from_file(struct file *f)
16183d0407baSopenharmony_ci{
16193d0407baSopenharmony_ci    if (IS_ERR_OR_NULL(f)) {
16203d0407baSopenharmony_ci        return NULL;
16213d0407baSopenharmony_ci    }
16223d0407baSopenharmony_ci
16233d0407baSopenharmony_ci    if (!is_dma_buf_file(f)) {
16243d0407baSopenharmony_ci        return NULL;
16253d0407baSopenharmony_ci    }
16263d0407baSopenharmony_ci
16273d0407baSopenharmony_ci    return f->private_data;
16283d0407baSopenharmony_ci}
16293d0407baSopenharmony_ci#endif /* CONFIG_DMABUF_PROCESS_INFO */
16303d0407baSopenharmony_ci
16313d0407baSopenharmony_cistatic int __init dma_buf_init(void)
16323d0407baSopenharmony_ci{
16333d0407baSopenharmony_ci    int ret;
16343d0407baSopenharmony_ci
16353d0407baSopenharmony_ci    ret = dma_buf_init_sysfs_statistics();
16363d0407baSopenharmony_ci    if (ret) {
16373d0407baSopenharmony_ci        return ret;
16383d0407baSopenharmony_ci    }
16393d0407baSopenharmony_ci
16403d0407baSopenharmony_ci    dma_buf_mnt = kern_mount(&dma_buf_fs_type);
16413d0407baSopenharmony_ci    if (IS_ERR(dma_buf_mnt)) {
16423d0407baSopenharmony_ci        return PTR_ERR(dma_buf_mnt);
16433d0407baSopenharmony_ci    }
16443d0407baSopenharmony_ci
16453d0407baSopenharmony_ci    mutex_init(&db_list.lock);
16463d0407baSopenharmony_ci    INIT_LIST_HEAD(&db_list.head);
16473d0407baSopenharmony_ci    dma_buf_init_debugfs();
16483d0407baSopenharmony_ci    dma_buf_process_info_init_procfs();
16493d0407baSopenharmony_ci    return 0;
16503d0407baSopenharmony_ci}
16513d0407baSopenharmony_cisubsys_initcall(dma_buf_init);
16523d0407baSopenharmony_ci
16533d0407baSopenharmony_cistatic void __exit dma_buf_deinit(void)
16543d0407baSopenharmony_ci{
16553d0407baSopenharmony_ci    dma_buf_uninit_debugfs();
16563d0407baSopenharmony_ci    kern_unmount(dma_buf_mnt);
16573d0407baSopenharmony_ci    dma_buf_uninit_sysfs_statistics();
16583d0407baSopenharmony_ci    dma_buf_process_info_uninit_procfs();
16593d0407baSopenharmony_ci}
16603d0407baSopenharmony_ci__exitcall(dma_buf_deinit);
1661