Home | History | Annotate | Line # | Download | only in linux
linux_dma_buf.c revision 1.5.4.3
      1  1.5.4.3    martin /*	$NetBSD: linux_dma_buf.c,v 1.5.4.3 2020/04/13 08:04:59 martin Exp $	*/
      2  1.5.4.2  christos 
      3  1.5.4.2  christos /*-
      4  1.5.4.2  christos  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5  1.5.4.2  christos  * All rights reserved.
      6  1.5.4.2  christos  *
      7  1.5.4.2  christos  * This code is derived from software contributed to The NetBSD Foundation
      8  1.5.4.2  christos  * by Taylor R. Campbell.
      9  1.5.4.2  christos  *
     10  1.5.4.2  christos  * Redistribution and use in source and binary forms, with or without
     11  1.5.4.2  christos  * modification, are permitted provided that the following conditions
     12  1.5.4.2  christos  * are met:
     13  1.5.4.2  christos  * 1. Redistributions of source code must retain the above copyright
     14  1.5.4.2  christos  *    notice, this list of conditions and the following disclaimer.
     15  1.5.4.2  christos  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.5.4.2  christos  *    notice, this list of conditions and the following disclaimer in the
     17  1.5.4.2  christos  *    documentation and/or other materials provided with the distribution.
     18  1.5.4.2  christos  *
     19  1.5.4.2  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.5.4.2  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.5.4.2  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.5.4.2  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.5.4.2  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.5.4.2  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.5.4.2  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.5.4.2  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.5.4.2  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.5.4.2  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.5.4.2  christos  * POSSIBILITY OF SUCH DAMAGE.
     30  1.5.4.2  christos  */
     31  1.5.4.2  christos 
     32  1.5.4.2  christos #include <sys/cdefs.h>
     33  1.5.4.3    martin __KERNEL_RCSID(0, "$NetBSD: linux_dma_buf.c,v 1.5.4.3 2020/04/13 08:04:59 martin Exp $");
     34  1.5.4.2  christos 
     35  1.5.4.2  christos #include <sys/types.h>
     36  1.5.4.2  christos #include <sys/atomic.h>
     37  1.5.4.2  christos #include <sys/file.h>
     38  1.5.4.2  christos #include <sys/filedesc.h>
     39  1.5.4.2  christos #include <sys/kmem.h>
     40  1.5.4.2  christos #include <sys/mutex.h>
     41  1.5.4.2  christos 
     42  1.5.4.2  christos #include <linux/dma-buf.h>
     43  1.5.4.2  christos #include <linux/err.h>
     44  1.5.4.2  christos #include <linux/fence.h>
     45  1.5.4.2  christos #include <linux/reservation.h>
     46  1.5.4.2  christos 
     47  1.5.4.2  christos struct dma_buf_file {
     48  1.5.4.2  christos 	struct dma_buf	*dbf_dmabuf;
     49  1.5.4.2  christos };
     50  1.5.4.2  christos 
     51  1.5.4.2  christos static int	dmabuf_fop_poll(struct file *, int);
     52  1.5.4.2  christos static int	dmabuf_fop_close(struct file *);
     53  1.5.4.2  christos static int	dmabuf_fop_kqfilter(struct file *, struct knote *);
     54  1.5.4.2  christos static int	dmabuf_fop_mmap(struct file *, off_t *, size_t, int, int *,
     55  1.5.4.2  christos 		    int *, struct uvm_object **, int *);
     56  1.5.4.2  christos 
     57  1.5.4.2  christos static const struct fileops dmabuf_fileops = {
     58  1.5.4.2  christos 	.fo_name = "dmabuf",
     59  1.5.4.2  christos 	.fo_read = fbadop_read,
     60  1.5.4.2  christos 	.fo_write = fbadop_write,
     61  1.5.4.2  christos 	.fo_ioctl = fbadop_ioctl,
     62  1.5.4.2  christos 	.fo_fcntl = fnullop_fcntl,
     63  1.5.4.2  christos 	.fo_poll = dmabuf_fop_poll,
     64  1.5.4.2  christos 	.fo_stat = fbadop_stat,
     65  1.5.4.2  christos 	.fo_close = dmabuf_fop_close,
     66  1.5.4.2  christos 	.fo_kqfilter = dmabuf_fop_kqfilter,
     67  1.5.4.2  christos 	.fo_restart = fnullop_restart,
     68  1.5.4.2  christos 	.fo_mmap = dmabuf_fop_mmap,
     69  1.5.4.2  christos };
     70  1.5.4.2  christos 
     71  1.5.4.2  christos struct dma_buf *
     72  1.5.4.2  christos dma_buf_export(struct dma_buf_export_info *info)
     73  1.5.4.2  christos {
     74  1.5.4.2  christos 	struct dma_buf *dmabuf;
     75  1.5.4.2  christos 
     76  1.5.4.2  christos 	if (info->resv == NULL) {
     77  1.5.4.2  christos 		dmabuf = kmem_zalloc(offsetof(struct dma_buf, db_resv_int[1]),
     78  1.5.4.2  christos 		    KM_SLEEP);
     79  1.5.4.2  christos 	} else {
     80  1.5.4.2  christos 		dmabuf = kmem_zalloc(sizeof(*dmabuf), KM_SLEEP);
     81  1.5.4.2  christos 	}
     82  1.5.4.2  christos 
     83  1.5.4.2  christos 	dmabuf->priv = info->priv;
     84  1.5.4.2  christos 	dmabuf->ops = info->ops;
     85  1.5.4.2  christos 	dmabuf->size = info->size;
     86  1.5.4.2  christos 	dmabuf->resv = info->resv;
     87  1.5.4.2  christos 
     88  1.5.4.2  christos 	mutex_init(&dmabuf->db_lock, MUTEX_DEFAULT, IPL_NONE);
     89  1.5.4.2  christos 	dmabuf->db_refcnt = 1;
     90  1.5.4.2  christos 	reservation_poll_init(&dmabuf->db_resv_poll);
     91  1.5.4.2  christos 
     92  1.5.4.2  christos 	if (dmabuf->resv == NULL) {
     93  1.5.4.2  christos 		dmabuf->resv = &dmabuf->db_resv_int[0];
     94  1.5.4.2  christos 		reservation_object_init(dmabuf->resv);
     95  1.5.4.2  christos 	}
     96  1.5.4.2  christos 
     97  1.5.4.2  christos 	return dmabuf;
     98  1.5.4.2  christos }
     99  1.5.4.2  christos 
    100  1.5.4.2  christos int
    101  1.5.4.2  christos dma_buf_fd(struct dma_buf *dmabuf, int flags)
    102  1.5.4.2  christos {
    103  1.5.4.2  christos 	struct file *file;
    104  1.5.4.2  christos 	int fd;
    105  1.5.4.2  christos 	unsigned refcnt __diagused;
    106  1.5.4.2  christos 	int ret;
    107  1.5.4.2  christos 
    108  1.5.4.2  christos 	ret = -fd_allocfile(&file, &fd);
    109  1.5.4.2  christos 	if (ret)
    110  1.5.4.2  christos 		goto out0;
    111  1.5.4.2  christos 
    112  1.5.4.2  christos 	refcnt = atomic_inc_uint_nv(&dmabuf->db_refcnt);
    113  1.5.4.2  christos 	KASSERT(refcnt > 1);
    114  1.5.4.2  christos 
    115  1.5.4.2  christos 	file->f_type = DTYPE_MISC;
    116  1.5.4.2  christos 	file->f_flag = 0;	/* XXX DRM code allows only O_CLOEXEC.  */
    117  1.5.4.2  christos 	file->f_ops = &dmabuf_fileops;
    118  1.5.4.2  christos 	file->f_data = dmabuf;
    119  1.5.4.2  christos 	fd_set_exclose(curlwp, fd, (flags & O_CLOEXEC) != 0);
    120  1.5.4.2  christos 	fd_affix(curproc, file, fd);
    121  1.5.4.2  christos 
    122  1.5.4.2  christos 	ret = fd;
    123  1.5.4.2  christos out0:	return ret;
    124  1.5.4.2  christos }
    125  1.5.4.2  christos 
    126  1.5.4.2  christos struct dma_buf *
    127  1.5.4.2  christos dma_buf_get(int fd)
    128  1.5.4.2  christos {
    129  1.5.4.2  christos 	struct file *file;
    130  1.5.4.2  christos 	struct dma_buf *dmabuf;
    131  1.5.4.2  christos 	unsigned refcnt __diagused;
    132  1.5.4.2  christos 	int error;
    133  1.5.4.2  christos 
    134  1.5.4.2  christos 	if ((file = fd_getfile(fd)) == NULL) {
    135  1.5.4.2  christos 		error = EBADF;
    136  1.5.4.3    martin 		goto fail0;
    137  1.5.4.2  christos 	}
    138  1.5.4.2  christos 	if (file->f_type != DTYPE_MISC || file->f_ops != &dmabuf_fileops) {
    139  1.5.4.2  christos 		error = EINVAL;
    140  1.5.4.3    martin 		goto fail1;
    141  1.5.4.2  christos 	}
    142  1.5.4.2  christos 
    143  1.5.4.2  christos 	dmabuf = file->f_data;
    144  1.5.4.2  christos 	refcnt = atomic_inc_uint_nv(&dmabuf->db_refcnt);
    145  1.5.4.2  christos 	KASSERT(refcnt > 1);
    146  1.5.4.2  christos 	fd_putfile(fd);
    147  1.5.4.2  christos 	return dmabuf;
    148  1.5.4.2  christos 
    149  1.5.4.2  christos fail1:	fd_putfile(fd);
    150  1.5.4.2  christos fail0:	KASSERT(error);
    151  1.5.4.2  christos 	return ERR_PTR(-error);
    152  1.5.4.2  christos }
    153  1.5.4.2  christos 
    154  1.5.4.2  christos void
    155  1.5.4.2  christos get_dma_buf(struct dma_buf *dmabuf)
    156  1.5.4.2  christos {
    157  1.5.4.2  christos 	unsigned refcnt __diagused;
    158  1.5.4.2  christos 
    159  1.5.4.2  christos 	refcnt = atomic_inc_uint_nv(&dmabuf->db_refcnt);
    160  1.5.4.2  christos 	KASSERT(refcnt > 1);
    161  1.5.4.2  christos }
    162  1.5.4.2  christos 
    163  1.5.4.2  christos void
    164  1.5.4.2  christos dma_buf_put(struct dma_buf *dmabuf)
    165  1.5.4.2  christos {
    166  1.5.4.2  christos 
    167  1.5.4.2  christos 	if (atomic_dec_uint_nv(&dmabuf->db_refcnt) != 0)
    168  1.5.4.2  christos 		return;
    169  1.5.4.2  christos 
    170  1.5.4.2  christos 	reservation_poll_fini(&dmabuf->db_resv_poll);
    171  1.5.4.2  christos 	mutex_destroy(&dmabuf->db_lock);
    172  1.5.4.2  christos 	if (dmabuf->resv == &dmabuf->db_resv_int[0]) {
    173  1.5.4.2  christos 		reservation_object_fini(dmabuf->resv);
    174  1.5.4.2  christos 		kmem_free(dmabuf, offsetof(struct dma_buf, db_resv_int[1]));
    175  1.5.4.2  christos 	} else {
    176  1.5.4.2  christos 		kmem_free(dmabuf, sizeof(*dmabuf));
    177  1.5.4.2  christos 	}
    178  1.5.4.2  christos }
    179  1.5.4.2  christos 
    180  1.5.4.2  christos struct dma_buf_attachment *
    181  1.5.4.2  christos dma_buf_attach(struct dma_buf *dmabuf, struct device *dev)
    182  1.5.4.2  christos {
    183  1.5.4.2  christos 	struct dma_buf_attachment *attach;
    184  1.5.4.2  christos 	int ret = 0;
    185  1.5.4.2  christos 
    186  1.5.4.2  christos 	attach = kmem_zalloc(sizeof(*attach), KM_SLEEP);
    187  1.5.4.2  christos 	attach->dmabuf = dmabuf;
    188  1.5.4.2  christos 
    189  1.5.4.2  christos 	mutex_enter(&dmabuf->db_lock);
    190  1.5.4.2  christos 	if (dmabuf->ops->attach)
    191  1.5.4.2  christos 		ret = dmabuf->ops->attach(dmabuf, dev, attach);
    192  1.5.4.2  christos 	mutex_exit(&dmabuf->db_lock);
    193  1.5.4.2  christos 	if (ret)
    194  1.5.4.2  christos 		goto fail0;
    195  1.5.4.2  christos 
    196  1.5.4.2  christos 	return attach;
    197  1.5.4.2  christos 
    198  1.5.4.2  christos fail0:	kmem_free(attach, sizeof(*attach));
    199  1.5.4.2  christos 	return ERR_PTR(ret);
    200  1.5.4.2  christos }
    201  1.5.4.2  christos 
    202  1.5.4.2  christos void
    203  1.5.4.2  christos dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
    204  1.5.4.2  christos {
    205  1.5.4.2  christos 
    206  1.5.4.2  christos 	mutex_enter(&dmabuf->db_lock);
    207  1.5.4.2  christos 	if (dmabuf->ops->detach)
    208  1.5.4.2  christos 		dmabuf->ops->detach(dmabuf, attach);
    209  1.5.4.2  christos 	mutex_exit(&dmabuf->db_lock);
    210  1.5.4.2  christos 
    211  1.5.4.2  christos 	kmem_free(attach, sizeof(*attach));
    212  1.5.4.2  christos }
    213  1.5.4.2  christos 
    214  1.5.4.2  christos struct sg_table *
    215  1.5.4.2  christos dma_buf_map_attachment(struct dma_buf_attachment *attach,
    216  1.5.4.2  christos     enum dma_data_direction dir)
    217  1.5.4.2  christos {
    218  1.5.4.2  christos 
    219  1.5.4.2  christos 	return attach->dmabuf->ops->map_dma_buf(attach, dir);
    220  1.5.4.2  christos }
    221  1.5.4.2  christos 
    222  1.5.4.2  christos void
    223  1.5.4.2  christos dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
    224  1.5.4.2  christos     struct sg_table *sg, enum dma_data_direction dir)
    225  1.5.4.2  christos {
    226  1.5.4.2  christos 
    227  1.5.4.2  christos 	return attach->dmabuf->ops->unmap_dma_buf(attach, sg, dir);
    228  1.5.4.2  christos }
    229  1.5.4.2  christos 
    230  1.5.4.2  christos static int
    231  1.5.4.2  christos dmabuf_fop_close(struct file *file)
    232  1.5.4.2  christos {
    233  1.5.4.2  christos 	struct dma_buf_file *dbf = file->f_data;
    234  1.5.4.2  christos 	struct dma_buf *dmabuf = dbf->dbf_dmabuf;
    235  1.5.4.2  christos 
    236  1.5.4.2  christos 	dma_buf_put(dmabuf);
    237  1.5.4.2  christos 	return 0;
    238  1.5.4.2  christos }
    239  1.5.4.2  christos 
    240  1.5.4.2  christos static int
    241  1.5.4.2  christos dmabuf_fop_poll(struct file *file, int events)
    242  1.5.4.2  christos {
    243  1.5.4.2  christos 	struct dma_buf_file *dbf = file->f_data;
    244  1.5.4.2  christos 	struct dma_buf *dmabuf = dbf->dbf_dmabuf;
    245  1.5.4.2  christos 	struct reservation_poll *rpoll = &dmabuf->db_resv_poll;
    246  1.5.4.2  christos 
    247  1.5.4.2  christos 	return reservation_object_poll(dmabuf->resv, events, rpoll);
    248  1.5.4.2  christos }
    249  1.5.4.2  christos 
    250  1.5.4.2  christos static int
    251  1.5.4.2  christos dmabuf_fop_kqfilter(struct file *file, struct knote *kn)
    252  1.5.4.2  christos {
    253  1.5.4.2  christos 	struct dma_buf_file *dbf = file->f_data;
    254  1.5.4.2  christos 	struct dma_buf *dmabuf = dbf->dbf_dmabuf;
    255  1.5.4.2  christos 	struct reservation_poll *rpoll = &dmabuf->db_resv_poll;
    256  1.5.4.2  christos 
    257  1.5.4.2  christos 	return reservation_object_kqfilter(dmabuf->resv, kn, rpoll);
    258  1.5.4.2  christos }
    259  1.5.4.2  christos 
    260  1.5.4.2  christos static int
    261  1.5.4.2  christos dmabuf_fop_mmap(struct file *file, off_t *offp, size_t size, int prot,
    262  1.5.4.2  christos     int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp)
    263  1.5.4.2  christos {
    264  1.5.4.2  christos 	struct dma_buf_file *dbf = file->f_data;
    265  1.5.4.2  christos 	struct dma_buf *dmabuf = dbf->dbf_dmabuf;
    266  1.5.4.2  christos 
    267  1.5.4.2  christos 	if (size > dmabuf->size)
    268  1.5.4.2  christos 		return EINVAL;
    269  1.5.4.2  christos 
    270  1.5.4.2  christos 	return dmabuf->ops->mmap(dmabuf, offp, size, prot, flagsp, advicep,
    271  1.5.4.2  christos 	    uobjp, maxprotp);
    272  1.5.4.2  christos }
    273