Commit | Line | Data |
---|---|---|
6ee73861 BS |
1 | /* |
2 | * Copyright (C) 2008 Ben Skeggs. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining | |
6 | * a copy of this software and associated documentation files (the | |
7 | * "Software"), to deal in the Software without restriction, including | |
8 | * without limitation the rights to use, copy, modify, merge, publish, | |
9 | * distribute, sublicense, and/or sell copies of the Software, and to | |
10 | * permit persons to whom the Software is furnished to do so, subject to | |
11 | * the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice (including the | |
14 | * next paragraph) shall be included in all copies or substantial | |
15 | * portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
20 | * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE | |
21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
24 | * | |
25 | */ | |
6ee73861 | 26 | |
4dc28134 | 27 | #include "nouveau_drv.h" |
6ee73861 | 28 | #include "nouveau_dma.h" |
d375e7d5 | 29 | #include "nouveau_fence.h" |
ebb945a9 | 30 | #include "nouveau_abi16.h" |
6ee73861 | 31 | |
ebb945a9 BS |
32 | #include "nouveau_ttm.h" |
33 | #include "nouveau_gem.h" | |
6ee73861 | 34 | |
6ee73861 BS |
35 | void |
36 | nouveau_gem_object_del(struct drm_gem_object *gem) | |
37 | { | |
55fb74ad | 38 | struct nouveau_bo *nvbo = nouveau_gem_object(gem); |
5cc8d536 | 39 | struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); |
6ee73861 | 40 | struct ttm_buffer_object *bo = &nvbo->bo; |
5cc8d536 BS |
41 | struct device *dev = drm->dev->dev; |
42 | int ret; | |
43 | ||
44 | ret = pm_runtime_get_sync(dev); | |
45 | if (WARN_ON(ret < 0 && ret != -EACCES)) | |
46 | return; | |
6ee73861 | 47 | |
22b33e8e DA |
48 | if (gem->import_attach) |
49 | drm_prime_gem_destroy(gem, nvbo->bo.sg); | |
50 | ||
fd632aa3 | 51 | drm_gem_object_release(gem); |
55fb74ad DH |
52 | |
53 | /* reset filp so nouveau_bo_del_ttm() can test for it */ | |
54 | gem->filp = NULL; | |
55 | ttm_bo_unref(&bo); | |
5cc8d536 BS |
56 | |
57 | pm_runtime_mark_last_busy(dev); | |
58 | pm_runtime_put_autosuspend(dev); | |
6ee73861 BS |
59 | } |
60 | ||
639212d0 BS |
61 | int |
62 | nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) | |
63 | { | |
ebb945a9 | 64 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
2fd3db6f | 65 | struct nouveau_bo *nvbo = nouveau_gem_object(gem); |
5cc8d536 | 66 | struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); |
be83cd4e | 67 | struct nvkm_vma *vma; |
5cc8d536 | 68 | struct device *dev = drm->dev->dev; |
2fd3db6f | 69 | int ret; |
639212d0 | 70 | |
3ee6f5b5 | 71 | if (!cli->vm) |
639212d0 BS |
72 | return 0; |
73 | ||
dfd5e50e | 74 | ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); |
2fd3db6f BS |
75 | if (ret) |
76 | return ret; | |
77 | ||
3ee6f5b5 | 78 | vma = nouveau_bo_vma_find(nvbo, cli->vm); |
2fd3db6f BS |
79 | if (!vma) { |
80 | vma = kzalloc(sizeof(*vma), GFP_KERNEL); | |
81 | if (!vma) { | |
82 | ret = -ENOMEM; | |
83 | goto out; | |
84 | } | |
85 | ||
5cc8d536 | 86 | ret = pm_runtime_get_sync(dev); |
bad4274a SM |
87 | if (ret < 0 && ret != -EACCES) { |
88 | kfree(vma); | |
5cc8d536 | 89 | goto out; |
bad4274a | 90 | } |
5cc8d536 | 91 | |
3ee6f5b5 | 92 | ret = nouveau_bo_vma_add(nvbo, cli->vm, vma); |
5cc8d536 | 93 | if (ret) |
2fd3db6f | 94 | kfree(vma); |
5cc8d536 BS |
95 | |
96 | pm_runtime_mark_last_busy(dev); | |
97 | pm_runtime_put_autosuspend(dev); | |
2fd3db6f BS |
98 | } else { |
99 | vma->refcount++; | |
100 | } | |
101 | ||
102 | out: | |
103 | ttm_bo_unreserve(&nvbo->bo); | |
104 | return ret; | |
639212d0 BS |
105 | } |
106 | ||
c4c7044f BS |
107 | static void |
108 | nouveau_gem_object_delete(void *data) | |
109 | { | |
be83cd4e BS |
110 | struct nvkm_vma *vma = data; |
111 | nvkm_vm_unmap(vma); | |
112 | nvkm_vm_put(vma); | |
c4c7044f BS |
113 | kfree(vma); |
114 | } | |
115 | ||
116 | static void | |
be83cd4e | 117 | nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nvkm_vma *vma) |
c4c7044f BS |
118 | { |
119 | const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM; | |
809e9447 ML |
120 | struct reservation_object *resv = nvbo->bo.resv; |
121 | struct reservation_object_list *fobj; | |
f2c24b83 | 122 | struct fence *fence = NULL; |
c4c7044f | 123 | |
809e9447 ML |
124 | fobj = reservation_object_get_list(resv); |
125 | ||
c4c7044f BS |
126 | list_del(&vma->head); |
127 | ||
809e9447 | 128 | if (fobj && fobj->shared_count > 1) |
8aa6d4fc | 129 | ttm_bo_wait(&nvbo->bo, false, false); |
809e9447 ML |
130 | else if (fobj && fobj->shared_count == 1) |
131 | fence = rcu_dereference_protected(fobj->shared[0], | |
132 | reservation_object_held(resv)); | |
133 | else | |
f2c24b83 | 134 | fence = reservation_object_get_excl(nvbo->bo.resv); |
c4c7044f | 135 | |
809e9447 | 136 | if (fence && mapped) { |
c4c7044f BS |
137 | nouveau_fence_work(fence, nouveau_gem_object_delete, vma); |
138 | } else { | |
139 | if (mapped) | |
be83cd4e BS |
140 | nvkm_vm_unmap(vma); |
141 | nvkm_vm_put(vma); | |
c4c7044f BS |
142 | kfree(vma); |
143 | } | |
c4c7044f BS |
144 | } |
145 | ||
639212d0 BS |
146 | void |
147 | nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) | |
148 | { | |
ebb945a9 | 149 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
2fd3db6f | 150 | struct nouveau_bo *nvbo = nouveau_gem_object(gem); |
5cc8d536 BS |
151 | struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); |
152 | struct device *dev = drm->dev->dev; | |
be83cd4e | 153 | struct nvkm_vma *vma; |
2fd3db6f | 154 | int ret; |
639212d0 | 155 | |
3ee6f5b5 | 156 | if (!cli->vm) |
639212d0 | 157 | return; |
2fd3db6f | 158 | |
dfd5e50e | 159 | ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); |
2fd3db6f BS |
160 | if (ret) |
161 | return; | |
162 | ||
3ee6f5b5 | 163 | vma = nouveau_bo_vma_find(nvbo, cli->vm); |
2fd3db6f | 164 | if (vma) { |
5cc8d536 BS |
165 | if (--vma->refcount == 0) { |
166 | ret = pm_runtime_get_sync(dev); | |
167 | if (!WARN_ON(ret < 0 && ret != -EACCES)) { | |
168 | nouveau_gem_object_unmap(nvbo, vma); | |
169 | pm_runtime_mark_last_busy(dev); | |
170 | pm_runtime_put_autosuspend(dev); | |
171 | } | |
172 | } | |
2fd3db6f BS |
173 | } |
174 | ttm_bo_unreserve(&nvbo->bo); | |
639212d0 BS |
175 | } |
176 | ||
6ee73861 | 177 | int |
f6d4e621 BS |
178 | nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain, |
179 | uint32_t tile_mode, uint32_t tile_flags, | |
180 | struct nouveau_bo **pnvbo) | |
6ee73861 | 181 | { |
ebb945a9 | 182 | struct nouveau_drm *drm = nouveau_drm(dev); |
6ee73861 | 183 | struct nouveau_bo *nvbo; |
6ba9a683 | 184 | u32 flags = 0; |
6ee73861 BS |
185 | int ret; |
186 | ||
6ba9a683 BS |
187 | if (domain & NOUVEAU_GEM_DOMAIN_VRAM) |
188 | flags |= TTM_PL_FLAG_VRAM; | |
189 | if (domain & NOUVEAU_GEM_DOMAIN_GART) | |
190 | flags |= TTM_PL_FLAG_TT; | |
191 | if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU) | |
192 | flags |= TTM_PL_FLAG_SYSTEM; | |
193 | ||
996f545f AC |
194 | if (domain & NOUVEAU_GEM_DOMAIN_COHERENT) |
195 | flags |= TTM_PL_FLAG_UNCACHED; | |
196 | ||
7375c95b | 197 | ret = nouveau_bo_new(dev, size, align, flags, tile_mode, |
bb6178b0 | 198 | tile_flags, NULL, NULL, pnvbo); |
6ee73861 BS |
199 | if (ret) |
200 | return ret; | |
201 | nvbo = *pnvbo; | |
202 | ||
db5c8e29 BS |
203 | /* we restrict allowed domains on nv50+ to only the types |
204 | * that were requested at creation time. not possibly on | |
205 | * earlier chips without busting the ABI. | |
206 | */ | |
207 | nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | | |
208 | NOUVEAU_GEM_DOMAIN_GART; | |
967e7bde | 209 | if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) |
db5c8e29 BS |
210 | nvbo->valid_domains &= domain; |
211 | ||
55fb74ad DH |
212 | /* Initialize the embedded gem-object. We return a single gem-reference |
213 | * to the caller, instead of a normal nouveau_bo ttm reference. */ | |
214 | ret = drm_gem_object_init(dev, &nvbo->gem, nvbo->bo.mem.size); | |
215 | if (ret) { | |
6ee73861 BS |
216 | nouveau_bo_ref(NULL, pnvbo); |
217 | return -ENOMEM; | |
218 | } | |
219 | ||
55fb74ad | 220 | nvbo->bo.persistent_swap_storage = nvbo->gem.filp; |
6ee73861 BS |
221 | return 0; |
222 | } | |
223 | ||
224 | static int | |
e758a311 BS |
225 | nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, |
226 | struct drm_nouveau_gem_info *rep) | |
6ee73861 | 227 | { |
ebb945a9 | 228 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
6ee73861 | 229 | struct nouveau_bo *nvbo = nouveau_gem_object(gem); |
be83cd4e | 230 | struct nvkm_vma *vma; |
6ee73861 | 231 | |
04b8a4bd IM |
232 | if (is_power_of_2(nvbo->valid_domains)) |
233 | rep->domain = nvbo->valid_domains; | |
234 | else if (nvbo->bo.mem.mem_type == TTM_PL_TT) | |
6ee73861 BS |
235 | rep->domain = NOUVEAU_GEM_DOMAIN_GART; |
236 | else | |
237 | rep->domain = NOUVEAU_GEM_DOMAIN_VRAM; | |
e758a311 | 238 | rep->offset = nvbo->bo.offset; |
3ee6f5b5 BS |
239 | if (cli->vm) { |
240 | vma = nouveau_bo_vma_find(nvbo, cli->vm); | |
e758a311 BS |
241 | if (!vma) |
242 | return -EINVAL; | |
243 | ||
244 | rep->offset = vma->offset; | |
245 | } | |
246 | ||
6ee73861 | 247 | rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; |
72525b3f | 248 | rep->map_handle = drm_vma_node_offset_addr(&nvbo->bo.vma_node); |
6ee73861 BS |
249 | rep->tile_mode = nvbo->tile_mode; |
250 | rep->tile_flags = nvbo->tile_flags; | |
251 | return 0; | |
252 | } | |
253 | ||
6ee73861 BS |
254 | int |
255 | nouveau_gem_ioctl_new(struct drm_device *dev, void *data, | |
256 | struct drm_file *file_priv) | |
257 | { | |
ebb945a9 | 258 | struct nouveau_drm *drm = nouveau_drm(dev); |
a84fa1a3 | 259 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
b1e4553c | 260 | struct nvkm_fb *fb = nvxx_fb(&drm->device); |
6ee73861 BS |
261 | struct drm_nouveau_gem_new *req = data; |
262 | struct nouveau_bo *nvbo = NULL; | |
6ee73861 BS |
263 | int ret = 0; |
264 | ||
03c8952f | 265 | if (!nvkm_fb_memtype_valid(fb, req->info.tile_flags)) { |
9ad97ede | 266 | NV_PRINTK(err, cli, "bad page flags: 0x%08x\n", req->info.tile_flags); |
6ee73861 | 267 | return -EINVAL; |
60d2a88a | 268 | } |
6ee73861 | 269 | |
f6d4e621 | 270 | ret = nouveau_gem_new(dev, req->info.size, req->align, |
6ba9a683 BS |
271 | req->info.domain, req->info.tile_mode, |
272 | req->info.tile_flags, &nvbo); | |
6ee73861 BS |
273 | if (ret) |
274 | return ret; | |
275 | ||
55fb74ad | 276 | ret = drm_gem_handle_create(file_priv, &nvbo->gem, &req->info.handle); |
e758a311 | 277 | if (ret == 0) { |
55fb74ad | 278 | ret = nouveau_gem_info(file_priv, &nvbo->gem, &req->info); |
e758a311 BS |
279 | if (ret) |
280 | drm_gem_handle_delete(file_priv, req->info.handle); | |
281 | } | |
282 | ||
29d08b3e | 283 | /* drop reference from allocate - handle holds it now */ |
55fb74ad | 284 | drm_gem_object_unreference_unlocked(&nvbo->gem); |
6ee73861 BS |
285 | return ret; |
286 | } | |
287 | ||
288 | static int | |
289 | nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, | |
290 | uint32_t write_domains, uint32_t valid_domains) | |
291 | { | |
55fb74ad | 292 | struct nouveau_bo *nvbo = nouveau_gem_object(gem); |
6ee73861 | 293 | struct ttm_buffer_object *bo = &nvbo->bo; |
db5c8e29 | 294 | uint32_t domains = valid_domains & nvbo->valid_domains & |
78ad0f7b FJ |
295 | (write_domains ? write_domains : read_domains); |
296 | uint32_t pref_flags = 0, valid_flags = 0; | |
6ee73861 | 297 | |
78ad0f7b | 298 | if (!domains) |
6ee73861 BS |
299 | return -EINVAL; |
300 | ||
78ad0f7b FJ |
301 | if (valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) |
302 | valid_flags |= TTM_PL_FLAG_VRAM; | |
303 | ||
304 | if (valid_domains & NOUVEAU_GEM_DOMAIN_GART) | |
305 | valid_flags |= TTM_PL_FLAG_TT; | |
306 | ||
307 | if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) && | |
308 | bo->mem.mem_type == TTM_PL_VRAM) | |
309 | pref_flags |= TTM_PL_FLAG_VRAM; | |
310 | ||
311 | else if ((domains & NOUVEAU_GEM_DOMAIN_GART) && | |
312 | bo->mem.mem_type == TTM_PL_TT) | |
313 | pref_flags |= TTM_PL_FLAG_TT; | |
314 | ||
315 | else if (domains & NOUVEAU_GEM_DOMAIN_VRAM) | |
316 | pref_flags |= TTM_PL_FLAG_VRAM; | |
317 | ||
318 | else | |
319 | pref_flags |= TTM_PL_FLAG_TT; | |
320 | ||
321 | nouveau_bo_placement_set(nvbo, pref_flags, valid_flags); | |
6ee73861 | 322 | |
6ee73861 BS |
323 | return 0; |
324 | } | |
325 | ||
326 | struct validate_op { | |
9242829a | 327 | struct list_head list; |
ecff665f | 328 | struct ww_acquire_ctx ticket; |
6ee73861 BS |
329 | }; |
330 | ||
331 | static void | |
809e9447 ML |
332 | validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence, |
333 | struct drm_nouveau_gem_pushbuf_bo *pbbo) | |
6ee73861 | 334 | { |
6ee73861 | 335 | struct nouveau_bo *nvbo; |
809e9447 | 336 | struct drm_nouveau_gem_pushbuf_bo *b; |
6ee73861 | 337 | |
9242829a ML |
338 | while (!list_empty(&op->list)) { |
339 | nvbo = list_entry(op->list.next, struct nouveau_bo, entry); | |
809e9447 | 340 | b = &pbbo[nvbo->pbbo_index]; |
332b242f | 341 | |
9360bd11 | 342 | if (likely(fence)) |
809e9447 | 343 | nouveau_bo_fence(nvbo, fence, !!b->write_domains); |
6ee73861 | 344 | |
a1606a95 BS |
345 | if (unlikely(nvbo->validate_mapped)) { |
346 | ttm_bo_kunmap(&nvbo->kmap); | |
347 | nvbo->validate_mapped = false; | |
348 | } | |
349 | ||
6ee73861 BS |
350 | list_del(&nvbo->entry); |
351 | nvbo->reserved_by = NULL; | |
9242829a | 352 | ttm_bo_unreserve_ticket(&nvbo->bo, &op->ticket); |
55fb74ad | 353 | drm_gem_object_unreference_unlocked(&nvbo->gem); |
6ee73861 BS |
354 | } |
355 | } | |
356 | ||
ecff665f | 357 | static void |
809e9447 ML |
358 | validate_fini(struct validate_op *op, struct nouveau_fence *fence, |
359 | struct drm_nouveau_gem_pushbuf_bo *pbbo) | |
ecff665f | 360 | { |
809e9447 | 361 | validate_fini_no_ticket(op, fence, pbbo); |
ecff665f | 362 | ww_acquire_fini(&op->ticket); |
6ee73861 BS |
363 | } |
364 | ||
365 | static int | |
366 | validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, | |
367 | struct drm_nouveau_gem_pushbuf_bo *pbbo, | |
368 | int nr_buffers, struct validate_op *op) | |
369 | { | |
a84fa1a3 | 370 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
6ee73861 BS |
371 | int trycnt = 0; |
372 | int ret, i; | |
c354c893 | 373 | struct nouveau_bo *res_bo = NULL; |
9242829a ML |
374 | LIST_HEAD(gart_list); |
375 | LIST_HEAD(vram_list); | |
376 | LIST_HEAD(both_list); | |
6ee73861 | 377 | |
ecff665f | 378 | ww_acquire_init(&op->ticket, &reservation_ww_class); |
6ee73861 BS |
379 | retry: |
380 | if (++trycnt > 100000) { | |
9ad97ede | 381 | NV_PRINTK(err, cli, "%s failed and gave up.\n", __func__); |
6ee73861 BS |
382 | return -EINVAL; |
383 | } | |
384 | ||
385 | for (i = 0; i < nr_buffers; i++) { | |
386 | struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[i]; | |
387 | struct drm_gem_object *gem; | |
388 | struct nouveau_bo *nvbo; | |
389 | ||
a8ad0bd8 | 390 | gem = drm_gem_object_lookup(file_priv, b->handle); |
6ee73861 | 391 | if (!gem) { |
9ad97ede | 392 | NV_PRINTK(err, cli, "Unknown handle 0x%08x\n", b->handle); |
9242829a ML |
393 | ret = -ENOENT; |
394 | break; | |
6ee73861 | 395 | } |
55fb74ad | 396 | nvbo = nouveau_gem_object(gem); |
c354c893 ML |
397 | if (nvbo == res_bo) { |
398 | res_bo = NULL; | |
399 | drm_gem_object_unreference_unlocked(gem); | |
400 | continue; | |
401 | } | |
6ee73861 BS |
402 | |
403 | if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { | |
9ad97ede | 404 | NV_PRINTK(err, cli, "multiple instances of buffer %d on " |
6ee73861 | 405 | "validation list\n", b->handle); |
5086f69e | 406 | drm_gem_object_unreference_unlocked(gem); |
9242829a ML |
407 | ret = -EINVAL; |
408 | break; | |
6ee73861 BS |
409 | } |
410 | ||
dfd5e50e | 411 | ret = ttm_bo_reserve(&nvbo->bo, true, false, &op->ticket); |
6ee73861 | 412 | if (ret) { |
9242829a ML |
413 | list_splice_tail_init(&vram_list, &op->list); |
414 | list_splice_tail_init(&gart_list, &op->list); | |
415 | list_splice_tail_init(&both_list, &op->list); | |
809e9447 | 416 | validate_fini_no_ticket(op, NULL, NULL); |
5e338405 | 417 | if (unlikely(ret == -EDEADLK)) { |
c354c893 | 418 | ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, |
ecff665f | 419 | &op->ticket); |
c354c893 ML |
420 | if (!ret) |
421 | res_bo = nvbo; | |
422 | } | |
938c40ed BS |
423 | if (unlikely(ret)) { |
424 | if (ret != -ERESTARTSYS) | |
9ad97ede | 425 | NV_PRINTK(err, cli, "fail reserve\n"); |
9242829a | 426 | break; |
a1606a95 | 427 | } |
6ee73861 BS |
428 | } |
429 | ||
a1606a95 | 430 | b->user_priv = (uint64_t)(unsigned long)nvbo; |
6ee73861 BS |
431 | nvbo->reserved_by = file_priv; |
432 | nvbo->pbbo_index = i; | |
433 | if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && | |
434 | (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)) | |
9242829a | 435 | list_add_tail(&nvbo->entry, &both_list); |
6ee73861 BS |
436 | else |
437 | if (b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) | |
9242829a | 438 | list_add_tail(&nvbo->entry, &vram_list); |
6ee73861 BS |
439 | else |
440 | if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART) | |
9242829a | 441 | list_add_tail(&nvbo->entry, &gart_list); |
6ee73861 | 442 | else { |
9ad97ede | 443 | NV_PRINTK(err, cli, "invalid valid domains: 0x%08x\n", |
6ee73861 | 444 | b->valid_domains); |
9242829a ML |
445 | list_add_tail(&nvbo->entry, &both_list); |
446 | ret = -EINVAL; | |
447 | break; | |
6ee73861 | 448 | } |
c354c893 ML |
449 | if (nvbo == res_bo) |
450 | goto retry; | |
6ee73861 BS |
451 | } |
452 | ||
ecff665f | 453 | ww_acquire_done(&op->ticket); |
9242829a ML |
454 | list_splice_tail(&vram_list, &op->list); |
455 | list_splice_tail(&gart_list, &op->list); | |
456 | list_splice_tail(&both_list, &op->list); | |
457 | if (ret) | |
809e9447 | 458 | validate_fini(op, NULL, NULL); |
9242829a ML |
459 | return ret; |
460 | ||
6ee73861 BS |
461 | } |
462 | ||
463 | static int | |
a84fa1a3 MS |
464 | validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, |
465 | struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo, | |
466 | uint64_t user_pbbo_ptr) | |
6ee73861 | 467 | { |
ebb945a9 | 468 | struct nouveau_drm *drm = chan->drm; |
6ee73861 BS |
469 | struct drm_nouveau_gem_pushbuf_bo __user *upbbo = |
470 | (void __force __user *)(uintptr_t)user_pbbo_ptr; | |
471 | struct nouveau_bo *nvbo; | |
472 | int ret, relocs = 0; | |
473 | ||
474 | list_for_each_entry(nvbo, list, entry) { | |
475 | struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; | |
6ee73861 | 476 | |
55fb74ad | 477 | ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains, |
6ee73861 BS |
478 | b->write_domains, |
479 | b->valid_domains); | |
a1606a95 | 480 | if (unlikely(ret)) { |
9ad97ede | 481 | NV_PRINTK(err, cli, "fail set_domain\n"); |
6ee73861 | 482 | return ret; |
a1606a95 | 483 | } |
6ee73861 | 484 | |
97a875cb | 485 | ret = nouveau_bo_validate(nvbo, true, false); |
a1606a95 | 486 | if (unlikely(ret)) { |
938c40ed | 487 | if (ret != -ERESTARTSYS) |
9ad97ede | 488 | NV_PRINTK(err, cli, "fail ttm_validate\n"); |
6ee73861 | 489 | return ret; |
a1606a95 | 490 | } |
6ee73861 | 491 | |
e3be4c23 | 492 | ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true); |
415e6186 | 493 | if (unlikely(ret)) { |
29ba89b2 | 494 | if (ret != -ERESTARTSYS) |
9ad97ede | 495 | NV_PRINTK(err, cli, "fail post-validate sync\n"); |
415e6186 BS |
496 | return ret; |
497 | } | |
498 | ||
967e7bde | 499 | if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { |
a3fcd0a9 BS |
500 | if (nvbo->bo.offset == b->presumed.offset && |
501 | ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && | |
502 | b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || | |
503 | (nvbo->bo.mem.mem_type == TTM_PL_TT && | |
504 | b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART))) | |
505 | continue; | |
506 | ||
507 | if (nvbo->bo.mem.mem_type == TTM_PL_TT) | |
508 | b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; | |
509 | else | |
510 | b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM; | |
511 | b->presumed.offset = nvbo->bo.offset; | |
512 | b->presumed.valid = 0; | |
513 | relocs++; | |
514 | ||
1d6ac185 | 515 | if (copy_to_user(&upbbo[nvbo->pbbo_index].presumed, |
a3fcd0a9 BS |
516 | &b->presumed, sizeof(b->presumed))) |
517 | return -EFAULT; | |
518 | } | |
6ee73861 BS |
519 | } |
520 | ||
521 | return relocs; | |
522 | } | |
523 | ||
524 | static int | |
525 | nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, | |
526 | struct drm_file *file_priv, | |
527 | struct drm_nouveau_gem_pushbuf_bo *pbbo, | |
528 | uint64_t user_buffers, int nr_buffers, | |
529 | struct validate_op *op, int *apply_relocs) | |
530 | { | |
a84fa1a3 | 531 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
9242829a | 532 | int ret; |
6ee73861 | 533 | |
9242829a | 534 | INIT_LIST_HEAD(&op->list); |
6ee73861 | 535 | |
6ee73861 BS |
536 | if (nr_buffers == 0) |
537 | return 0; | |
538 | ||
539 | ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); | |
a1606a95 | 540 | if (unlikely(ret)) { |
938c40ed | 541 | if (ret != -ERESTARTSYS) |
9ad97ede | 542 | NV_PRINTK(err, cli, "validate_init\n"); |
6ee73861 | 543 | return ret; |
a1606a95 | 544 | } |
6ee73861 | 545 | |
9242829a | 546 | ret = validate_list(chan, cli, &op->list, pbbo, user_buffers); |
6ee73861 | 547 | if (unlikely(ret < 0)) { |
938c40ed | 548 | if (ret != -ERESTARTSYS) |
9ad97ede | 549 | NV_PRINTK(err, cli, "validating bo list\n"); |
809e9447 | 550 | validate_fini(op, NULL, NULL); |
6ee73861 BS |
551 | return ret; |
552 | } | |
9242829a | 553 | *apply_relocs = ret; |
6ee73861 BS |
554 | return 0; |
555 | } | |
556 | ||
c859074e ML |
557 | static inline void |
558 | u_free(void *addr) | |
559 | { | |
48a20138 | 560 | kvfree(addr); |
c859074e ML |
561 | } |
562 | ||
6ee73861 BS |
563 | static inline void * |
564 | u_memcpya(uint64_t user, unsigned nmemb, unsigned size) | |
565 | { | |
566 | void *mem; | |
567 | void __user *userptr = (void __force __user *)(uintptr_t)user; | |
568 | ||
c859074e ML |
569 | size *= nmemb; |
570 | ||
571 | mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); | |
572 | if (!mem) | |
573 | mem = vmalloc(size); | |
6ee73861 BS |
574 | if (!mem) |
575 | return ERR_PTR(-ENOMEM); | |
576 | ||
1d6ac185 | 577 | if (copy_from_user(mem, userptr, size)) { |
c859074e | 578 | u_free(mem); |
6ee73861 BS |
579 | return ERR_PTR(-EFAULT); |
580 | } | |
581 | ||
582 | return mem; | |
583 | } | |
584 | ||
585 | static int | |
a84fa1a3 | 586 | nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, |
a1606a95 BS |
587 | struct drm_nouveau_gem_pushbuf *req, |
588 | struct drm_nouveau_gem_pushbuf_bo *bo) | |
6ee73861 BS |
589 | { |
590 | struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; | |
12f735b7 LB |
591 | int ret = 0; |
592 | unsigned i; | |
6ee73861 | 593 | |
a1606a95 | 594 | reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc)); |
6ee73861 BS |
595 | if (IS_ERR(reloc)) |
596 | return PTR_ERR(reloc); | |
597 | ||
a1606a95 | 598 | for (i = 0; i < req->nr_relocs; i++) { |
6ee73861 BS |
599 | struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i]; |
600 | struct drm_nouveau_gem_pushbuf_bo *b; | |
a1606a95 | 601 | struct nouveau_bo *nvbo; |
6ee73861 BS |
602 | uint32_t data; |
603 | ||
a1606a95 | 604 | if (unlikely(r->bo_index > req->nr_buffers)) { |
9ad97ede | 605 | NV_PRINTK(err, cli, "reloc bo index invalid\n"); |
6ee73861 BS |
606 | ret = -EINVAL; |
607 | break; | |
608 | } | |
609 | ||
610 | b = &bo[r->bo_index]; | |
a1606a95 | 611 | if (b->presumed.valid) |
6ee73861 BS |
612 | continue; |
613 | ||
a1606a95 | 614 | if (unlikely(r->reloc_bo_index > req->nr_buffers)) { |
9ad97ede | 615 | NV_PRINTK(err, cli, "reloc container bo index invalid\n"); |
a1606a95 BS |
616 | ret = -EINVAL; |
617 | break; | |
618 | } | |
619 | nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv; | |
620 | ||
621 | if (unlikely(r->reloc_bo_offset + 4 > | |
622 | nvbo->bo.mem.num_pages << PAGE_SHIFT)) { | |
9ad97ede | 623 | NV_PRINTK(err, cli, "reloc outside of bo\n"); |
a1606a95 BS |
624 | ret = -EINVAL; |
625 | break; | |
626 | } | |
627 | ||
628 | if (!nvbo->kmap.virtual) { | |
629 | ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, | |
630 | &nvbo->kmap); | |
631 | if (ret) { | |
9ad97ede | 632 | NV_PRINTK(err, cli, "failed kmap for reloc\n"); |
a1606a95 BS |
633 | break; |
634 | } | |
635 | nvbo->validate_mapped = true; | |
636 | } | |
637 | ||
6ee73861 | 638 | if (r->flags & NOUVEAU_GEM_RELOC_LOW) |
a1606a95 | 639 | data = b->presumed.offset + r->data; |
6ee73861 BS |
640 | else |
641 | if (r->flags & NOUVEAU_GEM_RELOC_HIGH) | |
a1606a95 | 642 | data = (b->presumed.offset + r->data) >> 32; |
6ee73861 BS |
643 | else |
644 | data = r->data; | |
645 | ||
646 | if (r->flags & NOUVEAU_GEM_RELOC_OR) { | |
a1606a95 | 647 | if (b->presumed.domain == NOUVEAU_GEM_DOMAIN_GART) |
6ee73861 BS |
648 | data |= r->tor; |
649 | else | |
650 | data |= r->vor; | |
651 | } | |
652 | ||
8aa6d4fc | 653 | ret = ttm_bo_wait(&nvbo->bo, false, false); |
a1606a95 | 654 | if (ret) { |
9ad97ede | 655 | NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret); |
a1606a95 BS |
656 | break; |
657 | } | |
a1606a95 BS |
658 | |
659 | nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); | |
6ee73861 BS |
660 | } |
661 | ||
c859074e | 662 | u_free(reloc); |
6ee73861 BS |
663 | return ret; |
664 | } | |
665 | ||
666 | int | |
667 | nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |
668 | struct drm_file *file_priv) | |
669 | { | |
09433f24 | 670 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv); |
a84fa1a3 | 671 | struct nouveau_cli *cli = nouveau_cli(file_priv); |
ebb945a9 BS |
672 | struct nouveau_abi16_chan *temp; |
673 | struct nouveau_drm *drm = nouveau_drm(dev); | |
6ee73861 | 674 | struct drm_nouveau_gem_pushbuf *req = data; |
a1606a95 BS |
675 | struct drm_nouveau_gem_pushbuf_push *push; |
676 | struct drm_nouveau_gem_pushbuf_bo *bo; | |
ebb945a9 | 677 | struct nouveau_channel *chan = NULL; |
6ee73861 | 678 | struct validate_op op; |
6e86e041 | 679 | struct nouveau_fence *fence = NULL; |
a1606a95 | 680 | int i, j, ret = 0, do_reloc = 0; |
6ee73861 | 681 | |
ebb945a9 BS |
682 | if (unlikely(!abi16)) |
683 | return -ENOMEM; | |
6ee73861 | 684 | |
ebb945a9 | 685 | list_for_each_entry(temp, &abi16->channels, head) { |
fcf3f91c | 686 | if (temp->chan->chid == req->channel) { |
ebb945a9 BS |
687 | chan = temp->chan; |
688 | break; | |
689 | } | |
690 | } | |
6ee73861 | 691 | |
ebb945a9 BS |
692 | if (!chan) |
693 | return nouveau_abi16_put(abi16, -ENOENT); | |
694 | ||
695 | req->vram_available = drm->gem.vram_available; | |
696 | req->gart_available = drm->gem.gart_available; | |
a1606a95 BS |
697 | if (unlikely(req->nr_push == 0)) |
698 | goto out_next; | |
6ee73861 | 699 | |
a1606a95 | 700 | if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { |
9ad97ede | 701 | NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n", |
a1606a95 | 702 | req->nr_push, NOUVEAU_GEM_MAX_PUSH); |
ebb945a9 | 703 | return nouveau_abi16_put(abi16, -EINVAL); |
6ee73861 BS |
704 | } |
705 | ||
a1606a95 | 706 | if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { |
9ad97ede | 707 | NV_PRINTK(err, cli, "pushbuf bo count exceeds limit: %d max %d\n", |
a1606a95 | 708 | req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); |
ebb945a9 | 709 | return nouveau_abi16_put(abi16, -EINVAL); |
6ee73861 BS |
710 | } |
711 | ||
a1606a95 | 712 | if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { |
9ad97ede | 713 | NV_PRINTK(err, cli, "pushbuf reloc count exceeds limit: %d max %d\n", |
a1606a95 | 714 | req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); |
ebb945a9 | 715 | return nouveau_abi16_put(abi16, -EINVAL); |
6ee73861 BS |
716 | } |
717 | ||
a1606a95 | 718 | push = u_memcpya(req->push, req->nr_push, sizeof(*push)); |
ebb945a9 BS |
719 | if (IS_ERR(push)) |
720 | return nouveau_abi16_put(abi16, PTR_ERR(push)); | |
a1606a95 | 721 | |
6ee73861 | 722 | bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); |
a1606a95 | 723 | if (IS_ERR(bo)) { |
c859074e | 724 | u_free(push); |
ebb945a9 | 725 | return nouveau_abi16_put(abi16, PTR_ERR(bo)); |
a1606a95 | 726 | } |
6ee73861 | 727 | |
accf9496 | 728 | /* Ensure all push buffers are on validate list */ |
415e6186 BS |
729 | for (i = 0; i < req->nr_push; i++) { |
730 | if (push[i].bo_index >= req->nr_buffers) { | |
9ad97ede | 731 | NV_PRINTK(err, cli, "push %d buffer not in list\n", i); |
415e6186 | 732 | ret = -EINVAL; |
7fa0cba2 | 733 | goto out_prevalid; |
415e6186 | 734 | } |
415e6186 BS |
735 | } |
736 | ||
6ee73861 BS |
737 | /* Validate buffer list */ |
738 | ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, | |
739 | req->nr_buffers, &op, &do_reloc); | |
740 | if (ret) { | |
938c40ed | 741 | if (ret != -ERESTARTSYS) |
9ad97ede | 742 | NV_PRINTK(err, cli, "validate: %d\n", ret); |
7fa0cba2 | 743 | goto out_prevalid; |
6ee73861 BS |
744 | } |
745 | ||
6ee73861 BS |
746 | /* Apply any relocations that are required */ |
747 | if (do_reloc) { | |
a84fa1a3 | 748 | ret = nouveau_gem_pushbuf_reloc_apply(cli, req, bo); |
6ee73861 | 749 | if (ret) { |
9ad97ede | 750 | NV_PRINTK(err, cli, "reloc apply: %d\n", ret); |
6ee73861 BS |
751 | goto out; |
752 | } | |
6ee73861 | 753 | } |
6ee73861 | 754 | |
9a391ad8 | 755 | if (chan->dma.ib_max) { |
5e120f6e | 756 | ret = nouveau_dma_wait(chan, req->nr_push + 1, 16); |
6ee73861 | 757 | if (ret) { |
9ad97ede | 758 | NV_PRINTK(err, cli, "nv50cal_space: %d\n", ret); |
6ee73861 BS |
759 | goto out; |
760 | } | |
6ee73861 | 761 | |
a1606a95 BS |
762 | for (i = 0; i < req->nr_push; i++) { |
763 | struct nouveau_bo *nvbo = (void *)(unsigned long) | |
764 | bo[push[i].bo_index].user_priv; | |
765 | ||
766 | nv50_dma_push(chan, nvbo, push[i].offset, | |
767 | push[i].length); | |
768 | } | |
9a391ad8 | 769 | } else |
967e7bde | 770 | if (drm->device.info.chipset >= 0x25) { |
a1606a95 | 771 | ret = RING_SPACE(chan, req->nr_push * 2); |
6ee73861 | 772 | if (ret) { |
9ad97ede | 773 | NV_PRINTK(err, cli, "cal_space: %d\n", ret); |
6ee73861 BS |
774 | goto out; |
775 | } | |
a1606a95 BS |
776 | |
777 | for (i = 0; i < req->nr_push; i++) { | |
778 | struct nouveau_bo *nvbo = (void *)(unsigned long) | |
779 | bo[push[i].bo_index].user_priv; | |
a1606a95 | 780 | |
3a92d37e | 781 | OUT_RING(chan, (nvbo->bo.offset + push[i].offset) | 2); |
a1606a95 BS |
782 | OUT_RING(chan, 0); |
783 | } | |
6ee73861 | 784 | } else { |
a1606a95 | 785 | ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS)); |
6ee73861 | 786 | if (ret) { |
9ad97ede | 787 | NV_PRINTK(err, cli, "jmp_space: %d\n", ret); |
6ee73861 BS |
788 | goto out; |
789 | } | |
6ee73861 | 790 | |
a1606a95 BS |
791 | for (i = 0; i < req->nr_push; i++) { |
792 | struct nouveau_bo *nvbo = (void *)(unsigned long) | |
793 | bo[push[i].bo_index].user_priv; | |
a1606a95 BS |
794 | uint32_t cmd; |
795 | ||
ebb945a9 | 796 | cmd = chan->push.vma.offset + ((chan->dma.cur + 2) << 2); |
a1606a95 BS |
797 | cmd |= 0x20000000; |
798 | if (unlikely(cmd != req->suffix0)) { | |
799 | if (!nvbo->kmap.virtual) { | |
800 | ret = ttm_bo_kmap(&nvbo->bo, 0, | |
801 | nvbo->bo.mem. | |
802 | num_pages, | |
803 | &nvbo->kmap); | |
804 | if (ret) { | |
805 | WIND_RING(chan); | |
806 | goto out; | |
807 | } | |
808 | nvbo->validate_mapped = true; | |
809 | } | |
810 | ||
811 | nouveau_bo_wr32(nvbo, (push[i].offset + | |
812 | push[i].length - 8) / 4, cmd); | |
813 | } | |
814 | ||
3a92d37e BS |
815 | OUT_RING(chan, 0x20000000 | |
816 | (nvbo->bo.offset + push[i].offset)); | |
6ee73861 | 817 | OUT_RING(chan, 0); |
a1606a95 BS |
818 | for (j = 0; j < NOUVEAU_DMA_SKIPS; j++) |
819 | OUT_RING(chan, 0); | |
820 | } | |
6ee73861 BS |
821 | } |
822 | ||
264ce192 | 823 | ret = nouveau_fence_new(chan, false, &fence); |
6ee73861 | 824 | if (ret) { |
9ad97ede | 825 | NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret); |
6ee73861 BS |
826 | WIND_RING(chan); |
827 | goto out; | |
828 | } | |
829 | ||
830 | out: | |
809e9447 | 831 | validate_fini(&op, fence, bo); |
382d62e5 | 832 | nouveau_fence_unref(&fence); |
7fa0cba2 MS |
833 | |
834 | out_prevalid: | |
c859074e ML |
835 | u_free(bo); |
836 | u_free(push); | |
6ee73861 BS |
837 | |
838 | out_next: | |
9a391ad8 BS |
839 | if (chan->dma.ib_max) { |
840 | req->suffix0 = 0x00000000; | |
841 | req->suffix1 = 0x00000000; | |
842 | } else | |
967e7bde | 843 | if (drm->device.info.chipset >= 0x25) { |
6ee73861 BS |
844 | req->suffix0 = 0x00020000; |
845 | req->suffix1 = 0x00000000; | |
846 | } else { | |
847 | req->suffix0 = 0x20000000 | | |
ebb945a9 | 848 | (chan->push.vma.offset + ((chan->dma.cur + 2) << 2)); |
6ee73861 BS |
849 | req->suffix1 = 0x00000000; |
850 | } | |
851 | ||
ebb945a9 | 852 | return nouveau_abi16_put(abi16, ret); |
6ee73861 BS |
853 | } |
854 | ||
6ee73861 BS |
855 | int |
856 | nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, | |
857 | struct drm_file *file_priv) | |
858 | { | |
859 | struct drm_nouveau_gem_cpu_prep *req = data; | |
860 | struct drm_gem_object *gem; | |
861 | struct nouveau_bo *nvbo; | |
862 | bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); | |
59701f96 | 863 | bool write = !!(req->flags & NOUVEAU_GEM_CPU_PREP_WRITE); |
d0b3c3b6 | 864 | int ret; |
6ee73861 | 865 | |
a8ad0bd8 | 866 | gem = drm_gem_object_lookup(file_priv, req->handle); |
6ee73861 | 867 | if (!gem) |
bf79cb91 | 868 | return -ENOENT; |
6ee73861 BS |
869 | nvbo = nouveau_gem_object(gem); |
870 | ||
59701f96 ML |
871 | if (no_wait) |
872 | ret = reservation_object_test_signaled_rcu(nvbo->bo.resv, write) ? 0 : -EBUSY; | |
873 | else { | |
874 | long lret; | |
d0b3c3b6 | 875 | |
59701f96 ML |
876 | lret = reservation_object_wait_timeout_rcu(nvbo->bo.resv, write, true, 30 * HZ); |
877 | if (!lret) | |
878 | ret = -EBUSY; | |
879 | else if (lret > 0) | |
880 | ret = 0; | |
881 | else | |
882 | ret = lret; | |
d0b3c3b6 | 883 | } |
b22870ba | 884 | nouveau_bo_sync_for_cpu(nvbo); |
bc9025bd | 885 | drm_gem_object_unreference_unlocked(gem); |
d0b3c3b6 | 886 | |
6ee73861 BS |
887 | return ret; |
888 | } | |
889 | ||
890 | int | |
891 | nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, | |
892 | struct drm_file *file_priv) | |
893 | { | |
b22870ba AC |
894 | struct drm_nouveau_gem_cpu_fini *req = data; |
895 | struct drm_gem_object *gem; | |
896 | struct nouveau_bo *nvbo; | |
897 | ||
a8ad0bd8 | 898 | gem = drm_gem_object_lookup(file_priv, req->handle); |
b22870ba AC |
899 | if (!gem) |
900 | return -ENOENT; | |
901 | nvbo = nouveau_gem_object(gem); | |
902 | ||
903 | nouveau_bo_sync_for_device(nvbo); | |
904 | drm_gem_object_unreference_unlocked(gem); | |
21e86c1c | 905 | return 0; |
6ee73861 BS |
906 | } |
907 | ||
908 | int | |
909 | nouveau_gem_ioctl_info(struct drm_device *dev, void *data, | |
910 | struct drm_file *file_priv) | |
911 | { | |
912 | struct drm_nouveau_gem_info *req = data; | |
913 | struct drm_gem_object *gem; | |
914 | int ret; | |
915 | ||
a8ad0bd8 | 916 | gem = drm_gem_object_lookup(file_priv, req->handle); |
6ee73861 | 917 | if (!gem) |
bf79cb91 | 918 | return -ENOENT; |
6ee73861 | 919 | |
e758a311 | 920 | ret = nouveau_gem_info(file_priv, gem, req); |
bc9025bd | 921 | drm_gem_object_unreference_unlocked(gem); |
6ee73861 BS |
922 | return ret; |
923 | } | |
924 |