summaryrefslogtreecommitdiffstats
path: root/drivers/xen/gntdev-dmabuf.c
blob: af782c0a8a1912ad3e9e42f9612d1badffc761a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
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);
}