diff options
author | Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | 2018-07-20 12:01:48 +0300 |
---|---|---|
committer | Boris Ostrovsky <boris.ostrovsky@oracle.com> | 2018-07-26 23:05:14 -0400 |
commit | 932d6562179efe8e2460a0343dbe0fcacf288a9e (patch) | |
tree | edaf27dad5042f971a9f098ca7c6217132e4d08c /drivers/xen/gntdev-dmabuf.c | |
parent | 1d314567553883d9f606cc59e8e66f465a4b6ccd (diff) |
xen/gntdev: Add initial support for dma-buf UAPI
Add UAPI and IOCTLs for dma-buf grant device driver extension:
the extension allows userspace processes and kernel modules to
use Xen backed dma-buf implementation. With this extension grant
references to the pages of an imported dma-buf can be exported
for other domain use and grant references coming from a foreign
domain can be converted into a local dma-buf for local export.
Implement basic initialization and stubs for Xen DMA buffers'
support.
Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Diffstat (limited to 'drivers/xen/gntdev-dmabuf.c')
-rw-r--r-- | drivers/xen/gntdev-dmabuf.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/drivers/xen/gntdev-dmabuf.c b/drivers/xen/gntdev-dmabuf.c new file mode 100644 index 000000000000..af782c0a8a19 --- /dev/null +++ b/drivers/xen/gntdev-dmabuf.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Xen dma-buf functionality for gntdev. + * + * Copyright (c) 2018 Oleksandr Andrushchenko, EPAM Systems Inc. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/uaccess.h> + +#include <xen/xen.h> +#include <xen/grant_table.h> + +#include "gntdev-common.h" +#include "gntdev-dmabuf.h" + +struct gntdev_dmabuf_priv { + /* List of exported DMA buffers. */ + struct list_head exp_list; + /* List of wait objects. */ + struct list_head exp_wait_list; + /* This is the lock which protects dma_buf_xxx lists. */ + struct mutex lock; +}; + +/* DMA buffer export support. */ + +/* Implementation of wait for exported DMA buffer to be released. */ + +static int dmabuf_exp_wait_released(struct gntdev_dmabuf_priv *priv, int fd, + int wait_to_ms) +{ + return -EINVAL; +} + +static int dmabuf_exp_from_refs(struct gntdev_priv *priv, int flags, + int count, u32 domid, u32 *refs, u32 *fd) +{ + *fd = -1; + return -EINVAL; +} + +/* DMA buffer import support. */ + +static struct gntdev_dmabuf * +dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev, + int fd, int count, int domid) +{ + return ERR_PTR(-ENOMEM); +} + +static u32 *dmabuf_imp_get_refs(struct gntdev_dmabuf *gntdev_dmabuf) +{ + return NULL; +} + +static int dmabuf_imp_release(struct gntdev_dmabuf_priv *priv, u32 fd) +{ + return -EINVAL; +} + +/* DMA buffer IOCTL support. */ + +long gntdev_ioctl_dmabuf_exp_from_refs(struct gntdev_priv *priv, int use_ptemod, + struct ioctl_gntdev_dmabuf_exp_from_refs __user *u) +{ + struct ioctl_gntdev_dmabuf_exp_from_refs op; + u32 *refs; + long ret; + + if (use_ptemod) { + pr_debug("Cannot provide dma-buf: use_ptemode %d\n", + use_ptemod); + return -EINVAL; + } + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + + if (unlikely(op.count <= 0)) + return -EINVAL; + + refs = kcalloc(op.count, sizeof(*refs), GFP_KERNEL); + if (!refs) + return -ENOMEM; + + if (copy_from_user(refs, u->refs, sizeof(*refs) * op.count) != 0) { + ret = -EFAULT; + goto out; + } + + ret = dmabuf_exp_from_refs(priv, op.flags, op.count, + op.domid, refs, &op.fd); + if (ret) + goto out; + + if (copy_to_user(u, &op, sizeof(op)) != 0) + ret = -EFAULT; + +out: + kfree(refs); + return ret; +} + +long gntdev_ioctl_dmabuf_exp_wait_released(struct gntdev_priv *priv, + struct ioctl_gntdev_dmabuf_exp_wait_released __user *u) +{ + struct ioctl_gntdev_dmabuf_exp_wait_released op; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + + return dmabuf_exp_wait_released(priv->dmabuf_priv, op.fd, + op.wait_to_ms); +} + +long gntdev_ioctl_dmabuf_imp_to_refs(struct gntdev_priv *priv, + struct ioctl_gntdev_dmabuf_imp_to_refs __user *u) +{ + struct ioctl_gntdev_dmabuf_imp_to_refs op; + struct gntdev_dmabuf *gntdev_dmabuf; + long ret; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + + if (unlikely(op.count <= 0)) + return -EINVAL; + + gntdev_dmabuf = dmabuf_imp_to_refs(priv->dmabuf_priv, + priv->dma_dev, op.fd, + op.count, op.domid); + if (IS_ERR(gntdev_dmabuf)) + return PTR_ERR(gntdev_dmabuf); + + if (copy_to_user(u->refs, dmabuf_imp_get_refs(gntdev_dmabuf), + sizeof(*u->refs) * op.count) != 0) { + ret = -EFAULT; + goto out_release; + } + return 0; + +out_release: + dmabuf_imp_release(priv->dmabuf_priv, op.fd); + return ret; +} + +long gntdev_ioctl_dmabuf_imp_release(struct gntdev_priv *priv, + struct ioctl_gntdev_dmabuf_imp_release __user *u) +{ + struct ioctl_gntdev_dmabuf_imp_release op; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + + return dmabuf_imp_release(priv->dmabuf_priv, op.fd); +} + +struct gntdev_dmabuf_priv *gntdev_dmabuf_init(void) +{ + struct gntdev_dmabuf_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + + return priv; +} + +void gntdev_dmabuf_fini(struct gntdev_dmabuf_priv *priv) +{ + kfree(priv); +} |