Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 15static struct drm_i915_gem_object *dma_buf_to_obj(struct dma_buf *buf)
 16{
 17	return to_intel_bo(buf->priv);
 18}
 19
 20static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
 21					     enum dma_data_direction dir)
 22{
 23	struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf);
 24	struct sg_table *st;
 25	struct scatterlist *src, *dst;
 26	int ret, i;
 27
 28	ret = i915_gem_object_pin_pages_unlocked(obj);
 29	if (ret)
 30		goto err;
 31
 32	/* Copy sg so that we make an independent mapping */
 33	st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
 34	if (st == NULL) {
 35		ret = -ENOMEM;
 36		goto err_unpin_pages;
 37	}
 38
 39	ret = sg_alloc_table(st, obj->mm.pages->nents, GFP_KERNEL);
 40	if (ret)
 41		goto err_free;
 42
 43	src = obj->mm.pages->sgl;
 44	dst = st->sgl;
 45	for (i = 0; i < obj->mm.pages->nents; i++) {
 46		sg_set_page(dst, sg_page(src), src->length, 0);
 47		dst = sg_next(dst);
 48		src = sg_next(src);
 49	}
 50
 51	ret = dma_map_sgtable(attachment->dev, st, dir, DMA_ATTR_SKIP_CPU_SYNC);
 52	if (ret)
 53		goto err_free_sg;
 54
 55	return st;
 56
 57err_free_sg:
 58	sg_free_table(st);
 59err_free:
 60	kfree(st);
 61err_unpin_pages:
 62	i915_gem_object_unpin_pages(obj);
 63err:
 64	return ERR_PTR(ret);
 65}
 66
 67static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
 68				   struct sg_table *sg,
 69				   enum dma_data_direction dir)
 70{
 71	struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf);
 72
 73	dma_unmap_sgtable(attachment->dev, sg, dir, DMA_ATTR_SKIP_CPU_SYNC);
 74	sg_free_table(sg);
 75	kfree(sg);
 76
 77	i915_gem_object_unpin_pages(obj);
 78}
 79
 80static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
 81{
 82	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
 83	void *vaddr;
 84
 85	vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB);
 86	if (IS_ERR(vaddr))
 87		return PTR_ERR(vaddr);
 88
 89	dma_buf_map_set_vaddr(map, vaddr);
 90
 91	return 0;
 92}
 93
 94static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map)
 95{
 96	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
 97
 98	i915_gem_object_flush_map(obj);
 99	i915_gem_object_unpin_map(obj);
100}
101
102static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
103{
104	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
105	int ret;
106
107	if (obj->base.size < vma->vm_end - vma->vm_start)
108		return -EINVAL;
109
110	if (!obj->base.filp)
111		return -ENODEV;
112
113	ret = call_mmap(obj->base.filp, vma);
114	if (ret)
115		return ret;
116
117	vma_set_file(vma, obj->base.filp);
118
119	return 0;
120}
121
122static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
123{
124	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
125	bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE);
126	struct i915_gem_ww_ctx ww;
127	int err;
128
129	i915_gem_ww_ctx_init(&ww, true);
130retry:
131	err = i915_gem_object_lock(obj, &ww);
132	if (!err)
133		err = i915_gem_object_pin_pages(obj);
134	if (!err) {
135		err = i915_gem_object_set_to_cpu_domain(obj, write);
136		i915_gem_object_unpin_pages(obj);
137	}
138	if (err == -EDEADLK) {
139		err = i915_gem_ww_ctx_backoff(&ww);
140		if (!err)
141			goto retry;
142	}
143	i915_gem_ww_ctx_fini(&ww);
144	return err;
145}
146
147static int i915_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
148{
149	struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
150	struct i915_gem_ww_ctx ww;
151	int err;
152
153	i915_gem_ww_ctx_init(&ww, true);
154retry:
155	err = i915_gem_object_lock(obj, &ww);
156	if (!err)
157		err = i915_gem_object_pin_pages(obj);
158	if (!err) {
159		err = i915_gem_object_set_to_gtt_domain(obj, false);
160		i915_gem_object_unpin_pages(obj);
161	}
162	if (err == -EDEADLK) {
163		err = i915_gem_ww_ctx_backoff(&ww);
164		if (!err)
165			goto retry;
166	}
167	i915_gem_ww_ctx_fini(&ww);
168	return err;
169}
170
171static const struct dma_buf_ops i915_dmabuf_ops =  {
172	.map_dma_buf = i915_gem_map_dma_buf,
173	.unmap_dma_buf = i915_gem_unmap_dma_buf,
174	.release = drm_gem_dmabuf_release,
175	.mmap = i915_gem_dmabuf_mmap,
176	.vmap = i915_gem_dmabuf_vmap,
177	.vunmap = i915_gem_dmabuf_vunmap,
178	.begin_cpu_access = i915_gem_begin_cpu_access,
179	.end_cpu_access = i915_gem_end_cpu_access,
180};
181
182struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags)
183{
184	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
185	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
186
187	exp_info.ops = &i915_dmabuf_ops;
188	exp_info.size = gem_obj->size;
189	exp_info.flags = flags;
190	exp_info.priv = gem_obj;
191	exp_info.resv = obj->base.resv;
192
193	if (obj->ops->dmabuf_export) {
194		int ret = obj->ops->dmabuf_export(obj);
195		if (ret)
196			return ERR_PTR(ret);
197	}
198
199	return drm_gem_dmabuf_export(gem_obj->dev, &exp_info);
200}
201
202static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
203{
204	struct sg_table *pages;
205	unsigned int sg_page_sizes;
206
207	pages = dma_buf_map_attachment(obj->base.import_attach,
208				       DMA_BIDIRECTIONAL);
209	if (IS_ERR(pages))
210		return PTR_ERR(pages);
211
212	sg_page_sizes = i915_sg_dma_sizes(pages->sgl);
213
214	__i915_gem_object_set_pages(obj, pages, sg_page_sizes);
215
216	return 0;
217}
218
219static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj,
220					     struct sg_table *pages)
221{
222	dma_buf_unmap_attachment(obj->base.import_attach, pages,
223				 DMA_BIDIRECTIONAL);
224}
225
226static const struct drm_i915_gem_object_ops i915_gem_object_dmabuf_ops = {
227	.name = "i915_gem_object_dmabuf",
228	.get_pages = i915_gem_object_get_pages_dmabuf,
229	.put_pages = i915_gem_object_put_pages_dmabuf,
230};
231
232struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
233					     struct dma_buf *dma_buf)
234{
235	static struct lock_class_key lock_class;
236	struct dma_buf_attachment *attach;
237	struct drm_i915_gem_object *obj;
238	int ret;
239
240	/* is this one of own objects? */
241	if (dma_buf->ops == &i915_dmabuf_ops) {
242		obj = dma_buf_to_obj(dma_buf);
243		/* is it from our device? */
244		if (obj->base.dev == dev) {
245			/*
246			 * Importing dmabuf exported from out own gem increases
247			 * refcount on gem itself instead of f_count of dmabuf.
248			 */
249			return &i915_gem_object_get(obj)->base;
250		}
251	}
252
253	if (i915_gem_object_size_2big(dma_buf->size))
254		return ERR_PTR(-E2BIG);
255
256	/* need to attach */
257	attach = dma_buf_attach(dma_buf, dev->dev);
258	if (IS_ERR(attach))
259		return ERR_CAST(attach);
260
261	get_dma_buf(dma_buf);
262
263	obj = i915_gem_object_alloc();
264	if (obj == NULL) {
265		ret = -ENOMEM;
266		goto fail_detach;
267	}
268
269	drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
270	i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops, &lock_class, 0);
271	obj->base.import_attach = attach;
272	obj->base.resv = dma_buf->resv;
273
274	/* We use GTT as shorthand for a coherent domain, one that is
275	 * neither in the GPU cache nor in the CPU cache, where all
276	 * writes are immediately visible in memory. (That's not strictly
277	 * true, but it's close! There are internal buffers such as the
278	 * write-combined buffer or a delay through the chipset for GTT
279	 * writes that do require us to treat GTT as a separate cache domain.)
280	 */
281	obj->read_domains = I915_GEM_DOMAIN_GTT;
282	obj->write_domain = 0;
283
284	return &obj->base;
285
286fail_detach:
287	dma_buf_detach(dma_buf, attach);
288	dma_buf_put(dma_buf);
289
290	return ERR_PTR(ret);
291}
292
293#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
294#include "selftests/mock_dmabuf.c"
295#include "selftests/i915_gem_dmabuf.c"
296#endif