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