i915_gem_dmabuf.c 7.9 KB
Newer Older
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright 2012 Red Hat Inc
5
 */
6 7

#include <linux/dma-buf.h>
8
#include <linux/highmem.h>
9
#include <linux/dma-resv.h>
10

11
#include "i915_drv.h"
12
#include "i915_gem_object.h"
13
#include "i915_scatterlist.h"
14

15 16
I915_SELFTEST_DECLARE(static bool force_different_devices;)

17 18 19 20 21
static struct drm_i915_gem_object *dma_buf_to_obj(struct dma_buf *buf)
{
	return to_intel_bo(buf->priv);
}

22
static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
23
					     enum dma_data_direction dir)
24
{
25
	struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf);
26 27 28
	struct sg_table *st;
	struct scatterlist *src, *dst;
	int ret, i;
29

30 31 32
	/* Copy sg so that we make an independent mapping */
	st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
	if (st == NULL) {
33
		ret = -ENOMEM;
34
		goto err;
35 36
	}

C
Chris Wilson 已提交
37
	ret = sg_alloc_table(st, obj->mm.pages->nents, GFP_KERNEL);
38 39
	if (ret)
		goto err_free;
40

C
Chris Wilson 已提交
41
	src = obj->mm.pages->sgl;
42
	dst = st->sgl;
C
Chris Wilson 已提交
43
	for (i = 0; i < obj->mm.pages->nents; i++) {
44
		sg_set_page(dst, sg_page(src), src->length, 0);
45 46 47 48
		dst = sg_next(dst);
		src = sg_next(src);
	}

49 50
	ret = dma_map_sgtable(attachment->dev, st, dir, DMA_ATTR_SKIP_CPU_SYNC);
	if (ret)
51
		goto err_free_sg;
52

53
	return st;
54 55 56 57 58 59 60

err_free_sg:
	sg_free_table(st);
err_free:
	kfree(st);
err:
	return ERR_PTR(ret);
61 62
}

63
static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
64 65
				   struct sg_table *sg,
				   enum dma_data_direction dir)
66
{
67
	dma_unmap_sgtable(attachment->dev, sg, dir, DMA_ATTR_SKIP_CPU_SYNC);
68 69 70 71
	sg_free_table(sg);
	kfree(sg);
}

72
static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
73
{
74
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
75
	void *vaddr;
76

77
	vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB);
78 79 80 81 82 83
	if (IS_ERR(vaddr))
		return PTR_ERR(vaddr);

	dma_buf_map_set_vaddr(map, vaddr);

	return 0;
84 85
}

86
static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
87
{
88
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
89

90
	i915_gem_object_flush_map(obj);
91
	i915_gem_object_unpin_map(obj);
92 93
}

94 95
static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
{
96 97 98 99 100 101 102 103 104
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
	int ret;

	if (obj->base.size < vma->vm_end - vma->vm_start)
		return -EINVAL;

	if (!obj->base.filp)
		return -ENODEV;

105
	ret = call_mmap(obj->base.filp, vma);
106 107 108
	if (ret)
		return ret;

109
	vma_set_file(vma, obj->base.filp);
110 111

	return 0;
112 113
}

114
static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
115
{
116
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
117
	bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE);
118
	struct i915_gem_ww_ctx ww;
119
	int err;
120

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	i915_gem_ww_ctx_init(&ww, true);
retry:
	err = i915_gem_object_lock(obj, &ww);
	if (!err)
		err = i915_gem_object_pin_pages(obj);
	if (!err) {
		err = i915_gem_object_set_to_cpu_domain(obj, write);
		i915_gem_object_unpin_pages(obj);
	}
	if (err == -EDEADLK) {
		err = i915_gem_ww_ctx_backoff(&ww);
		if (!err)
			goto retry;
	}
	i915_gem_ww_ctx_fini(&ww);
136
	return err;
137 138
}

139
static int i915_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
140 141
{
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
142
	struct i915_gem_ww_ctx ww;
143
	int err;
144

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	i915_gem_ww_ctx_init(&ww, true);
retry:
	err = i915_gem_object_lock(obj, &ww);
	if (!err)
		err = i915_gem_object_pin_pages(obj);
	if (!err) {
		err = i915_gem_object_set_to_gtt_domain(obj, false);
		i915_gem_object_unpin_pages(obj);
	}
	if (err == -EDEADLK) {
		err = i915_gem_ww_ctx_backoff(&ww);
		if (!err)
			goto retry;
	}
	i915_gem_ww_ctx_fini(&ww);
160
	return err;
161 162
}

163 164 165 166
static int i915_gem_dmabuf_attach(struct dma_buf *dmabuf,
				  struct dma_buf_attachment *attach)
{
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dmabuf);
167 168 169 170 171 172 173 174 175 176 177 178 179 180
	struct i915_gem_ww_ctx ww;
	int err;

	if (!i915_gem_object_can_migrate(obj, INTEL_REGION_SMEM))
		return -EOPNOTSUPP;

	for_i915_gem_ww(&ww, err, true) {
		err = i915_gem_object_lock(obj, &ww);
		if (err)
			continue;

		err = i915_gem_object_migrate(obj, &ww, INTEL_REGION_SMEM);
		if (err)
			continue;
181

182 183 184 185 186 187 188 189
		err = i915_gem_object_wait_migration(obj, 0);
		if (err)
			continue;

		err = i915_gem_object_pin_pages(obj);
	}

	return err;
190 191 192 193 194 195 196 197 198 199
}

static void i915_gem_dmabuf_detach(struct dma_buf *dmabuf,
				   struct dma_buf_attachment *attach)
{
	struct drm_i915_gem_object *obj = dma_buf_to_obj(dmabuf);

	i915_gem_object_unpin_pages(obj);
}

200
static const struct dma_buf_ops i915_dmabuf_ops =  {
201 202
	.attach = i915_gem_dmabuf_attach,
	.detach = i915_gem_dmabuf_detach,
203 204
	.map_dma_buf = i915_gem_map_dma_buf,
	.unmap_dma_buf = i915_gem_unmap_dma_buf,
205
	.release = drm_gem_dmabuf_release,
206
	.mmap = i915_gem_dmabuf_mmap,
207 208
	.vmap = i915_gem_dmabuf_vmap,
	.vunmap = i915_gem_dmabuf_vunmap,
209
	.begin_cpu_access = i915_gem_begin_cpu_access,
210
	.end_cpu_access = i915_gem_end_cpu_access,
211 212
};

D
Daniel Vetter 已提交
213
struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags)
214
{
215
	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
216 217 218 219 220 221
	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);

	exp_info.ops = &i915_dmabuf_ops;
	exp_info.size = gem_obj->size;
	exp_info.flags = flags;
	exp_info.priv = gem_obj;
C
Chris Wilson 已提交
222
	exp_info.resv = obj->base.resv;
223

224 225 226 227 228 229
	if (obj->ops->dmabuf_export) {
		int ret = obj->ops->dmabuf_export(obj);
		if (ret)
			return ERR_PTR(ret);
	}

D
Daniel Vetter 已提交
230
	return drm_gem_dmabuf_export(gem_obj->dev, &exp_info);
231 232
}

233
static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
234
{
235
	struct sg_table *pages;
M
Matthew Auld 已提交
236
	unsigned int sg_page_sizes;
237

238 239
	assert_object_held(obj);

240 241 242 243 244
	pages = dma_buf_map_attachment(obj->base.import_attach,
				       DMA_BIDIRECTIONAL);
	if (IS_ERR(pages))
		return PTR_ERR(pages);

245
	sg_page_sizes = i915_sg_dma_sizes(pages->sgl);
246

M
Matthew Auld 已提交
247
	__i915_gem_object_set_pages(obj, pages, sg_page_sizes);
248 249

	return 0;
250 251
}

252 253
static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj,
					     struct sg_table *pages)
254
{
255 256
	dma_buf_unmap_attachment(obj->base.import_attach, pages,
				 DMA_BIDIRECTIONAL);
257 258 259
}

static const struct drm_i915_gem_object_ops i915_gem_object_dmabuf_ops = {
260
	.name = "i915_gem_object_dmabuf",
261 262 263 264
	.get_pages = i915_gem_object_get_pages_dmabuf,
	.put_pages = i915_gem_object_put_pages_dmabuf,
};

265
struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
266
					     struct dma_buf *dma_buf)
267
{
268
	static struct lock_class_key lock_class;
269 270 271 272 273 274
	struct dma_buf_attachment *attach;
	struct drm_i915_gem_object *obj;
	int ret;

	/* is this one of own objects? */
	if (dma_buf->ops == &i915_dmabuf_ops) {
275
		obj = dma_buf_to_obj(dma_buf);
276
		/* is it from our device? */
277 278
		if (obj->base.dev == dev &&
		    !I915_SELFTEST_ONLY(force_different_devices)) {
279 280 281 282
			/*
			 * Importing dmabuf exported from out own gem increases
			 * refcount on gem itself instead of f_count of dmabuf.
			 */
283
			return &i915_gem_object_get(obj)->base;
284 285 286
		}
	}

287
	if (i915_gem_object_size_2big(dma_buf->size))
288 289
		return ERR_PTR(-E2BIG);

290 291 292 293 294
	/* need to attach */
	attach = dma_buf_attach(dma_buf, dev->dev);
	if (IS_ERR(attach))
		return ERR_CAST(attach);

295 296
	get_dma_buf(dma_buf);

297
	obj = i915_gem_object_alloc();
298 299
	if (obj == NULL) {
		ret = -ENOMEM;
300
		goto fail_detach;
301 302
	}

303
	drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
304
	i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops, &lock_class, 0);
305
	obj->base.import_attach = attach;
C
Chris Wilson 已提交
306
	obj->base.resv = dma_buf->resv;
307

308 309 310 311 312 313 314
	/* We use GTT as shorthand for a coherent domain, one that is
	 * neither in the GPU cache nor in the CPU cache, where all
	 * writes are immediately visible in memory. (That's not strictly
	 * true, but it's close! There are internal buffers such as the
	 * write-combined buffer or a delay through the chipset for GTT
	 * writes that do require us to treat GTT as a separate cache domain.)
	 */
315 316
	obj->read_domains = I915_GEM_DOMAIN_GTT;
	obj->write_domain = 0;
317

318 319 320 321
	return &obj->base;

fail_detach:
	dma_buf_detach(dma_buf, attach);
322 323
	dma_buf_put(dma_buf);

324 325
	return ERR_PTR(ret);
}
326 327 328 329 330

#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/mock_dmabuf.c"
#include "selftests/i915_gem_dmabuf.c"
#endif