1 | /* |
2 | * Copyright 2008 Advanced Micro Devices, Inc. |
3 | * Copyright 2008 Red Hat Inc. |
4 | * Copyright 2009 Jerome Glisse. |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the "Software"), |
8 | * to deal in the Software without restriction, including without limitation |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | * and/or sell copies of the Software, and to permit persons to whom the |
11 | * Software is furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
22 | * OTHER DEALINGS IN THE SOFTWARE. |
23 | * |
24 | * Authors: Dave Airlie |
25 | * Alex Deucher |
26 | * Jerome Glisse |
27 | */ |
28 | |
29 | #include <linux/iosys-map.h> |
30 | #include <linux/pci.h> |
31 | |
32 | #include <drm/drm_device.h> |
33 | #include <drm/drm_file.h> |
34 | #include <drm/drm_gem_ttm_helper.h> |
35 | #include <drm/radeon_drm.h> |
36 | |
37 | #include "radeon.h" |
38 | #include "radeon_prime.h" |
39 | |
40 | struct dma_buf *radeon_gem_prime_export(struct drm_gem_object *gobj, |
41 | int flags); |
42 | struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj); |
43 | int radeon_gem_prime_pin(struct drm_gem_object *obj); |
44 | void radeon_gem_prime_unpin(struct drm_gem_object *obj); |
45 | |
46 | const struct drm_gem_object_funcs radeon_gem_object_funcs; |
47 | |
48 | static vm_fault_t radeon_gem_fault(struct vm_fault *vmf) |
49 | { |
50 | struct ttm_buffer_object *bo = vmf->vma->vm_private_data; |
51 | struct radeon_device *rdev = radeon_get_rdev(bdev: bo->bdev); |
52 | vm_fault_t ret; |
53 | |
54 | down_read(sem: &rdev->pm.mclk_lock); |
55 | |
56 | ret = ttm_bo_vm_reserve(bo, vmf); |
57 | if (ret) |
58 | goto unlock_mclk; |
59 | |
60 | ret = radeon_bo_fault_reserve_notify(bo); |
61 | if (ret) |
62 | goto unlock_resv; |
63 | |
64 | ret = ttm_bo_vm_fault_reserved(vmf, prot: vmf->vma->vm_page_prot, |
65 | TTM_BO_VM_NUM_PREFAULT); |
66 | if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) |
67 | goto unlock_mclk; |
68 | |
69 | unlock_resv: |
70 | dma_resv_unlock(obj: bo->base.resv); |
71 | |
72 | unlock_mclk: |
73 | up_read(sem: &rdev->pm.mclk_lock); |
74 | return ret; |
75 | } |
76 | |
77 | static const struct vm_operations_struct radeon_gem_vm_ops = { |
78 | .fault = radeon_gem_fault, |
79 | .open = ttm_bo_vm_open, |
80 | .close = ttm_bo_vm_close, |
81 | .access = ttm_bo_vm_access |
82 | }; |
83 | |
84 | static void radeon_gem_object_free(struct drm_gem_object *gobj) |
85 | { |
86 | struct radeon_bo *robj = gem_to_radeon_bo(gobj); |
87 | |
88 | if (robj) { |
89 | radeon_mn_unregister(bo: robj); |
90 | radeon_bo_unref(bo: &robj); |
91 | } |
92 | } |
93 | |
94 | int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size, |
95 | int alignment, int initial_domain, |
96 | u32 flags, bool kernel, |
97 | struct drm_gem_object **obj) |
98 | { |
99 | struct radeon_bo *robj; |
100 | unsigned long max_size; |
101 | int r; |
102 | |
103 | *obj = NULL; |
104 | /* At least align on page size */ |
105 | if (alignment < PAGE_SIZE) { |
106 | alignment = PAGE_SIZE; |
107 | } |
108 | |
109 | /* Maximum bo size is the unpinned gtt size since we use the gtt to |
110 | * handle vram to system pool migrations. |
111 | */ |
112 | max_size = rdev->mc.gtt_size - rdev->gart_pin_size; |
113 | if (size > max_size) { |
114 | DRM_DEBUG("Allocation size %ldMb bigger than %ldMb limit\n" , |
115 | size >> 20, max_size >> 20); |
116 | return -ENOMEM; |
117 | } |
118 | |
119 | retry: |
120 | r = radeon_bo_create(rdev, size, byte_align: alignment, kernel, domain: initial_domain, |
121 | flags, NULL, NULL, bo_ptr: &robj); |
122 | if (r) { |
123 | if (r != -ERESTARTSYS) { |
124 | if (initial_domain == RADEON_GEM_DOMAIN_VRAM) { |
125 | initial_domain |= RADEON_GEM_DOMAIN_GTT; |
126 | goto retry; |
127 | } |
128 | DRM_ERROR("Failed to allocate GEM object (%ld, %d, %u, %d)\n" , |
129 | size, initial_domain, alignment, r); |
130 | } |
131 | return r; |
132 | } |
133 | *obj = &robj->tbo.base; |
134 | (*obj)->funcs = &radeon_gem_object_funcs; |
135 | robj->pid = task_pid_nr(current); |
136 | |
137 | mutex_lock(&rdev->gem.mutex); |
138 | list_add_tail(new: &robj->list, head: &rdev->gem.objects); |
139 | mutex_unlock(lock: &rdev->gem.mutex); |
140 | |
141 | return 0; |
142 | } |
143 | |
144 | static int radeon_gem_set_domain(struct drm_gem_object *gobj, |
145 | uint32_t rdomain, uint32_t wdomain) |
146 | { |
147 | struct radeon_bo *robj; |
148 | uint32_t domain; |
149 | long r; |
150 | |
151 | /* FIXME: reeimplement */ |
152 | robj = gem_to_radeon_bo(gobj); |
153 | /* work out where to validate the buffer to */ |
154 | domain = wdomain; |
155 | if (!domain) { |
156 | domain = rdomain; |
157 | } |
158 | if (!domain) { |
159 | /* Do nothings */ |
160 | pr_warn("Set domain without domain !\n" ); |
161 | return 0; |
162 | } |
163 | if (domain == RADEON_GEM_DOMAIN_CPU) { |
164 | /* Asking for cpu access wait for object idle */ |
165 | r = dma_resv_wait_timeout(obj: robj->tbo.base.resv, |
166 | usage: DMA_RESV_USAGE_BOOKKEEP, |
167 | intr: true, timeout: 30 * HZ); |
168 | if (!r) |
169 | r = -EBUSY; |
170 | |
171 | if (r < 0 && r != -EINTR) { |
172 | pr_err("Failed to wait for object: %li\n" , r); |
173 | return r; |
174 | } |
175 | } |
176 | if (domain == RADEON_GEM_DOMAIN_VRAM && robj->prime_shared_count) { |
177 | /* A BO that is associated with a dma-buf cannot be sensibly migrated to VRAM */ |
178 | return -EINVAL; |
179 | } |
180 | return 0; |
181 | } |
182 | |
183 | int radeon_gem_init(struct radeon_device *rdev) |
184 | { |
185 | INIT_LIST_HEAD(list: &rdev->gem.objects); |
186 | return 0; |
187 | } |
188 | |
189 | void radeon_gem_fini(struct radeon_device *rdev) |
190 | { |
191 | radeon_bo_force_delete(rdev); |
192 | } |
193 | |
194 | /* |
195 | * Call from drm_gem_handle_create which appear in both new and open ioctl |
196 | * case. |
197 | */ |
198 | static int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) |
199 | { |
200 | struct radeon_bo *rbo = gem_to_radeon_bo(obj); |
201 | struct radeon_device *rdev = rbo->rdev; |
202 | struct radeon_fpriv *fpriv = file_priv->driver_priv; |
203 | struct radeon_vm *vm = &fpriv->vm; |
204 | struct radeon_bo_va *bo_va; |
205 | int r; |
206 | |
207 | if ((rdev->family < CHIP_CAYMAN) || |
208 | (!rdev->accel_working)) { |
209 | return 0; |
210 | } |
211 | |
212 | r = radeon_bo_reserve(bo: rbo, no_intr: false); |
213 | if (r) { |
214 | return r; |
215 | } |
216 | |
217 | bo_va = radeon_vm_bo_find(vm, bo: rbo); |
218 | if (!bo_va) { |
219 | bo_va = radeon_vm_bo_add(rdev, vm, bo: rbo); |
220 | } else { |
221 | ++bo_va->ref_count; |
222 | } |
223 | radeon_bo_unreserve(bo: rbo); |
224 | |
225 | return 0; |
226 | } |
227 | |
228 | static void radeon_gem_object_close(struct drm_gem_object *obj, |
229 | struct drm_file *file_priv) |
230 | { |
231 | struct radeon_bo *rbo = gem_to_radeon_bo(obj); |
232 | struct radeon_device *rdev = rbo->rdev; |
233 | struct radeon_fpriv *fpriv = file_priv->driver_priv; |
234 | struct radeon_vm *vm = &fpriv->vm; |
235 | struct radeon_bo_va *bo_va; |
236 | int r; |
237 | |
238 | if ((rdev->family < CHIP_CAYMAN) || |
239 | (!rdev->accel_working)) { |
240 | return; |
241 | } |
242 | |
243 | r = radeon_bo_reserve(bo: rbo, no_intr: true); |
244 | if (r) { |
245 | dev_err(rdev->dev, "leaking bo va because " |
246 | "we fail to reserve bo (%d)\n" , r); |
247 | return; |
248 | } |
249 | bo_va = radeon_vm_bo_find(vm, bo: rbo); |
250 | if (bo_va) { |
251 | if (--bo_va->ref_count == 0) { |
252 | radeon_vm_bo_rmv(rdev, bo_va); |
253 | } |
254 | } |
255 | radeon_bo_unreserve(bo: rbo); |
256 | } |
257 | |
258 | static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r) |
259 | { |
260 | if (r == -EDEADLK) { |
261 | r = radeon_gpu_reset(rdev); |
262 | if (!r) |
263 | r = -EAGAIN; |
264 | } |
265 | return r; |
266 | } |
267 | |
268 | static int radeon_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) |
269 | { |
270 | struct radeon_bo *bo = gem_to_radeon_bo(obj); |
271 | struct radeon_device *rdev = radeon_get_rdev(bdev: bo->tbo.bdev); |
272 | |
273 | if (radeon_ttm_tt_has_userptr(rdev, ttm: bo->tbo.ttm)) |
274 | return -EPERM; |
275 | |
276 | return drm_gem_ttm_mmap(gem: obj, vma); |
277 | } |
278 | |
279 | const struct drm_gem_object_funcs radeon_gem_object_funcs = { |
280 | .free = radeon_gem_object_free, |
281 | .open = radeon_gem_object_open, |
282 | .close = radeon_gem_object_close, |
283 | .export = radeon_gem_prime_export, |
284 | .pin = radeon_gem_prime_pin, |
285 | .unpin = radeon_gem_prime_unpin, |
286 | .get_sg_table = radeon_gem_prime_get_sg_table, |
287 | .vmap = drm_gem_ttm_vmap, |
288 | .vunmap = drm_gem_ttm_vunmap, |
289 | .mmap = radeon_gem_object_mmap, |
290 | .vm_ops = &radeon_gem_vm_ops, |
291 | }; |
292 | |
293 | /* |
294 | * GEM ioctls. |
295 | */ |
296 | int radeon_gem_info_ioctl(struct drm_device *dev, void *data, |
297 | struct drm_file *filp) |
298 | { |
299 | struct radeon_device *rdev = dev->dev_private; |
300 | struct drm_radeon_gem_info *args = data; |
301 | struct ttm_resource_manager *man; |
302 | |
303 | man = ttm_manager_type(bdev: &rdev->mman.bdev, TTM_PL_VRAM); |
304 | |
305 | args->vram_size = (u64)man->size << PAGE_SHIFT; |
306 | args->vram_visible = rdev->mc.visible_vram_size; |
307 | args->vram_visible -= rdev->vram_pin_size; |
308 | args->gart_size = rdev->mc.gtt_size; |
309 | args->gart_size -= rdev->gart_pin_size; |
310 | |
311 | return 0; |
312 | } |
313 | |
314 | int radeon_gem_create_ioctl(struct drm_device *dev, void *data, |
315 | struct drm_file *filp) |
316 | { |
317 | struct radeon_device *rdev = dev->dev_private; |
318 | struct drm_radeon_gem_create *args = data; |
319 | struct drm_gem_object *gobj; |
320 | uint32_t handle; |
321 | int r; |
322 | |
323 | down_read(sem: &rdev->exclusive_lock); |
324 | /* create a gem object to contain this object in */ |
325 | args->size = roundup(args->size, PAGE_SIZE); |
326 | r = radeon_gem_object_create(rdev, size: args->size, alignment: args->alignment, |
327 | initial_domain: args->initial_domain, flags: args->flags, |
328 | kernel: false, obj: &gobj); |
329 | if (r) { |
330 | up_read(sem: &rdev->exclusive_lock); |
331 | r = radeon_gem_handle_lockup(rdev, r); |
332 | return r; |
333 | } |
334 | r = drm_gem_handle_create(file_priv: filp, obj: gobj, handlep: &handle); |
335 | /* drop reference from allocate - handle holds it now */ |
336 | drm_gem_object_put(obj: gobj); |
337 | if (r) { |
338 | up_read(sem: &rdev->exclusive_lock); |
339 | r = radeon_gem_handle_lockup(rdev, r); |
340 | return r; |
341 | } |
342 | args->handle = handle; |
343 | up_read(sem: &rdev->exclusive_lock); |
344 | return 0; |
345 | } |
346 | |
347 | int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, |
348 | struct drm_file *filp) |
349 | { |
350 | struct ttm_operation_ctx ctx = { true, false }; |
351 | struct radeon_device *rdev = dev->dev_private; |
352 | struct drm_radeon_gem_userptr *args = data; |
353 | struct drm_gem_object *gobj; |
354 | struct radeon_bo *bo; |
355 | uint32_t handle; |
356 | int r; |
357 | |
358 | args->addr = untagged_addr(args->addr); |
359 | |
360 | if (offset_in_page(args->addr | args->size)) |
361 | return -EINVAL; |
362 | |
363 | /* reject unknown flag values */ |
364 | if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | |
365 | RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE | |
366 | RADEON_GEM_USERPTR_REGISTER)) |
367 | return -EINVAL; |
368 | |
369 | if (args->flags & RADEON_GEM_USERPTR_READONLY) { |
370 | /* readonly pages not tested on older hardware */ |
371 | if (rdev->family < CHIP_R600) |
372 | return -EINVAL; |
373 | |
374 | } else if (!(args->flags & RADEON_GEM_USERPTR_ANONONLY) || |
375 | !(args->flags & RADEON_GEM_USERPTR_REGISTER)) { |
376 | |
377 | /* if we want to write to it we must require anonymous |
378 | memory and install a MMU notifier */ |
379 | return -EACCES; |
380 | } |
381 | |
382 | down_read(sem: &rdev->exclusive_lock); |
383 | |
384 | /* create a gem object to contain this object in */ |
385 | r = radeon_gem_object_create(rdev, size: args->size, alignment: 0, |
386 | RADEON_GEM_DOMAIN_CPU, flags: 0, |
387 | kernel: false, obj: &gobj); |
388 | if (r) |
389 | goto handle_lockup; |
390 | |
391 | bo = gem_to_radeon_bo(gobj); |
392 | r = radeon_ttm_tt_set_userptr(rdev, ttm: bo->tbo.ttm, addr: args->addr, flags: args->flags); |
393 | if (r) |
394 | goto release_object; |
395 | |
396 | if (args->flags & RADEON_GEM_USERPTR_REGISTER) { |
397 | r = radeon_mn_register(bo, addr: args->addr); |
398 | if (r) |
399 | goto release_object; |
400 | } |
401 | |
402 | if (args->flags & RADEON_GEM_USERPTR_VALIDATE) { |
403 | mmap_read_lock(current->mm); |
404 | r = radeon_bo_reserve(bo, no_intr: true); |
405 | if (r) { |
406 | mmap_read_unlock(current->mm); |
407 | goto release_object; |
408 | } |
409 | |
410 | radeon_ttm_placement_from_domain(rbo: bo, RADEON_GEM_DOMAIN_GTT); |
411 | r = ttm_bo_validate(bo: &bo->tbo, placement: &bo->placement, ctx: &ctx); |
412 | radeon_bo_unreserve(bo); |
413 | mmap_read_unlock(current->mm); |
414 | if (r) |
415 | goto release_object; |
416 | } |
417 | |
418 | r = drm_gem_handle_create(file_priv: filp, obj: gobj, handlep: &handle); |
419 | /* drop reference from allocate - handle holds it now */ |
420 | drm_gem_object_put(obj: gobj); |
421 | if (r) |
422 | goto handle_lockup; |
423 | |
424 | args->handle = handle; |
425 | up_read(sem: &rdev->exclusive_lock); |
426 | return 0; |
427 | |
428 | release_object: |
429 | drm_gem_object_put(obj: gobj); |
430 | |
431 | handle_lockup: |
432 | up_read(sem: &rdev->exclusive_lock); |
433 | r = radeon_gem_handle_lockup(rdev, r); |
434 | |
435 | return r; |
436 | } |
437 | |
438 | int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, |
439 | struct drm_file *filp) |
440 | { |
441 | /* transition the BO to a domain - |
442 | * just validate the BO into a certain domain */ |
443 | struct radeon_device *rdev = dev->dev_private; |
444 | struct drm_radeon_gem_set_domain *args = data; |
445 | struct drm_gem_object *gobj; |
446 | int r; |
447 | |
448 | /* for now if someone requests domain CPU - |
449 | * just make sure the buffer is finished with */ |
450 | down_read(sem: &rdev->exclusive_lock); |
451 | |
452 | /* just do a BO wait for now */ |
453 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
454 | if (gobj == NULL) { |
455 | up_read(sem: &rdev->exclusive_lock); |
456 | return -ENOENT; |
457 | } |
458 | |
459 | r = radeon_gem_set_domain(gobj, rdomain: args->read_domains, wdomain: args->write_domain); |
460 | |
461 | drm_gem_object_put(obj: gobj); |
462 | up_read(sem: &rdev->exclusive_lock); |
463 | r = radeon_gem_handle_lockup(rdev, r); |
464 | return r; |
465 | } |
466 | |
467 | int radeon_mode_dumb_mmap(struct drm_file *filp, |
468 | struct drm_device *dev, |
469 | uint32_t handle, uint64_t *offset_p) |
470 | { |
471 | struct drm_gem_object *gobj; |
472 | struct radeon_bo *robj; |
473 | |
474 | gobj = drm_gem_object_lookup(filp, handle); |
475 | if (gobj == NULL) { |
476 | return -ENOENT; |
477 | } |
478 | robj = gem_to_radeon_bo(gobj); |
479 | if (radeon_ttm_tt_has_userptr(rdev: robj->rdev, ttm: robj->tbo.ttm)) { |
480 | drm_gem_object_put(obj: gobj); |
481 | return -EPERM; |
482 | } |
483 | *offset_p = radeon_bo_mmap_offset(bo: robj); |
484 | drm_gem_object_put(obj: gobj); |
485 | return 0; |
486 | } |
487 | |
488 | int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, |
489 | struct drm_file *filp) |
490 | { |
491 | struct drm_radeon_gem_mmap *args = data; |
492 | |
493 | return radeon_mode_dumb_mmap(filp, dev, handle: args->handle, offset_p: &args->addr_ptr); |
494 | } |
495 | |
496 | int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, |
497 | struct drm_file *filp) |
498 | { |
499 | struct drm_radeon_gem_busy *args = data; |
500 | struct drm_gem_object *gobj; |
501 | struct radeon_bo *robj; |
502 | int r; |
503 | uint32_t cur_placement = 0; |
504 | |
505 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
506 | if (gobj == NULL) { |
507 | return -ENOENT; |
508 | } |
509 | robj = gem_to_radeon_bo(gobj); |
510 | |
511 | r = dma_resv_test_signaled(obj: robj->tbo.base.resv, usage: DMA_RESV_USAGE_READ); |
512 | if (r == 0) |
513 | r = -EBUSY; |
514 | else |
515 | r = 0; |
516 | |
517 | cur_placement = READ_ONCE(robj->tbo.resource->mem_type); |
518 | args->domain = radeon_mem_type_to_domain(mem_type: cur_placement); |
519 | drm_gem_object_put(obj: gobj); |
520 | return r; |
521 | } |
522 | |
523 | int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, |
524 | struct drm_file *filp) |
525 | { |
526 | struct radeon_device *rdev = dev->dev_private; |
527 | struct drm_radeon_gem_wait_idle *args = data; |
528 | struct drm_gem_object *gobj; |
529 | struct radeon_bo *robj; |
530 | int r = 0; |
531 | uint32_t cur_placement = 0; |
532 | long ret; |
533 | |
534 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
535 | if (gobj == NULL) { |
536 | return -ENOENT; |
537 | } |
538 | robj = gem_to_radeon_bo(gobj); |
539 | |
540 | ret = dma_resv_wait_timeout(obj: robj->tbo.base.resv, usage: DMA_RESV_USAGE_READ, |
541 | intr: true, timeout: 30 * HZ); |
542 | if (ret == 0) |
543 | r = -EBUSY; |
544 | else if (ret < 0) |
545 | r = ret; |
546 | |
547 | /* Flush HDP cache via MMIO if necessary */ |
548 | cur_placement = READ_ONCE(robj->tbo.resource->mem_type); |
549 | if (rdev->asic->mmio_hdp_flush && |
550 | radeon_mem_type_to_domain(mem_type: cur_placement) == RADEON_GEM_DOMAIN_VRAM) |
551 | robj->rdev->asic->mmio_hdp_flush(rdev); |
552 | drm_gem_object_put(obj: gobj); |
553 | r = radeon_gem_handle_lockup(rdev, r); |
554 | return r; |
555 | } |
556 | |
557 | int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, |
558 | struct drm_file *filp) |
559 | { |
560 | struct drm_radeon_gem_set_tiling *args = data; |
561 | struct drm_gem_object *gobj; |
562 | struct radeon_bo *robj; |
563 | int r = 0; |
564 | |
565 | DRM_DEBUG("%d \n" , args->handle); |
566 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
567 | if (gobj == NULL) |
568 | return -ENOENT; |
569 | robj = gem_to_radeon_bo(gobj); |
570 | r = radeon_bo_set_tiling_flags(bo: robj, tiling_flags: args->tiling_flags, pitch: args->pitch); |
571 | drm_gem_object_put(obj: gobj); |
572 | return r; |
573 | } |
574 | |
575 | int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, |
576 | struct drm_file *filp) |
577 | { |
578 | struct drm_radeon_gem_get_tiling *args = data; |
579 | struct drm_gem_object *gobj; |
580 | struct radeon_bo *rbo; |
581 | int r = 0; |
582 | |
583 | DRM_DEBUG("\n" ); |
584 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
585 | if (gobj == NULL) |
586 | return -ENOENT; |
587 | rbo = gem_to_radeon_bo(gobj); |
588 | r = radeon_bo_reserve(bo: rbo, no_intr: false); |
589 | if (unlikely(r != 0)) |
590 | goto out; |
591 | radeon_bo_get_tiling_flags(bo: rbo, tiling_flags: &args->tiling_flags, pitch: &args->pitch); |
592 | radeon_bo_unreserve(bo: rbo); |
593 | out: |
594 | drm_gem_object_put(obj: gobj); |
595 | return r; |
596 | } |
597 | |
598 | /** |
599 | * radeon_gem_va_update_vm -update the bo_va in its VM |
600 | * |
601 | * @rdev: radeon_device pointer |
602 | * @bo_va: bo_va to update |
603 | * |
604 | * Update the bo_va directly after setting it's address. Errors are not |
605 | * vital here, so they are not reported back to userspace. |
606 | */ |
607 | static void radeon_gem_va_update_vm(struct radeon_device *rdev, |
608 | struct radeon_bo_va *bo_va) |
609 | { |
610 | struct ttm_validate_buffer tv, *entry; |
611 | struct radeon_bo_list *vm_bos; |
612 | struct ww_acquire_ctx ticket; |
613 | struct list_head list; |
614 | unsigned domain; |
615 | int r; |
616 | |
617 | INIT_LIST_HEAD(list: &list); |
618 | |
619 | tv.bo = &bo_va->bo->tbo; |
620 | tv.num_shared = 1; |
621 | list_add(new: &tv.head, head: &list); |
622 | |
623 | vm_bos = radeon_vm_get_bos(rdev, vm: bo_va->vm, head: &list); |
624 | if (!vm_bos) |
625 | return; |
626 | |
627 | r = ttm_eu_reserve_buffers(ticket: &ticket, list: &list, intr: true, NULL); |
628 | if (r) |
629 | goto error_free; |
630 | |
631 | list_for_each_entry(entry, &list, head) { |
632 | domain = radeon_mem_type_to_domain(mem_type: entry->bo->resource->mem_type); |
633 | /* if anything is swapped out don't swap it in here, |
634 | just abort and wait for the next CS */ |
635 | if (domain == RADEON_GEM_DOMAIN_CPU) |
636 | goto error_unreserve; |
637 | } |
638 | |
639 | mutex_lock(&bo_va->vm->mutex); |
640 | r = radeon_vm_clear_freed(rdev, vm: bo_va->vm); |
641 | if (r) |
642 | goto error_unlock; |
643 | |
644 | if (bo_va->it.start) |
645 | r = radeon_vm_bo_update(rdev, bo_va, mem: bo_va->bo->tbo.resource); |
646 | |
647 | error_unlock: |
648 | mutex_unlock(lock: &bo_va->vm->mutex); |
649 | |
650 | error_unreserve: |
651 | ttm_eu_backoff_reservation(ticket: &ticket, list: &list); |
652 | |
653 | error_free: |
654 | kvfree(addr: vm_bos); |
655 | |
656 | if (r && r != -ERESTARTSYS) |
657 | DRM_ERROR("Couldn't update BO_VA (%d)\n" , r); |
658 | } |
659 | |
660 | int radeon_gem_va_ioctl(struct drm_device *dev, void *data, |
661 | struct drm_file *filp) |
662 | { |
663 | struct drm_radeon_gem_va *args = data; |
664 | struct drm_gem_object *gobj; |
665 | struct radeon_device *rdev = dev->dev_private; |
666 | struct radeon_fpriv *fpriv = filp->driver_priv; |
667 | struct radeon_bo *rbo; |
668 | struct radeon_bo_va *bo_va; |
669 | u32 invalid_flags; |
670 | int r = 0; |
671 | |
672 | if (!rdev->vm_manager.enabled) { |
673 | args->operation = RADEON_VA_RESULT_ERROR; |
674 | return -ENOTTY; |
675 | } |
676 | |
677 | /* !! DONT REMOVE !! |
678 | * We don't support vm_id yet, to be sure we don't have broken |
679 | * userspace, reject anyone trying to use non 0 value thus moving |
680 | * forward we can use those fields without breaking existant userspace |
681 | */ |
682 | if (args->vm_id) { |
683 | args->operation = RADEON_VA_RESULT_ERROR; |
684 | return -EINVAL; |
685 | } |
686 | |
687 | if (args->offset < RADEON_VA_RESERVED_SIZE) { |
688 | dev_err(dev->dev, |
689 | "offset 0x%lX is in reserved area 0x%X\n" , |
690 | (unsigned long)args->offset, |
691 | RADEON_VA_RESERVED_SIZE); |
692 | args->operation = RADEON_VA_RESULT_ERROR; |
693 | return -EINVAL; |
694 | } |
695 | |
696 | /* don't remove, we need to enforce userspace to set the snooped flag |
697 | * otherwise we will endup with broken userspace and we won't be able |
698 | * to enable this feature without adding new interface |
699 | */ |
700 | invalid_flags = RADEON_VM_PAGE_VALID | RADEON_VM_PAGE_SYSTEM; |
701 | if ((args->flags & invalid_flags)) { |
702 | dev_err(dev->dev, "invalid flags 0x%08X vs 0x%08X\n" , |
703 | args->flags, invalid_flags); |
704 | args->operation = RADEON_VA_RESULT_ERROR; |
705 | return -EINVAL; |
706 | } |
707 | |
708 | switch (args->operation) { |
709 | case RADEON_VA_MAP: |
710 | case RADEON_VA_UNMAP: |
711 | break; |
712 | default: |
713 | dev_err(dev->dev, "unsupported operation %d\n" , |
714 | args->operation); |
715 | args->operation = RADEON_VA_RESULT_ERROR; |
716 | return -EINVAL; |
717 | } |
718 | |
719 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
720 | if (gobj == NULL) { |
721 | args->operation = RADEON_VA_RESULT_ERROR; |
722 | return -ENOENT; |
723 | } |
724 | rbo = gem_to_radeon_bo(gobj); |
725 | r = radeon_bo_reserve(bo: rbo, no_intr: false); |
726 | if (r) { |
727 | args->operation = RADEON_VA_RESULT_ERROR; |
728 | drm_gem_object_put(obj: gobj); |
729 | return r; |
730 | } |
731 | bo_va = radeon_vm_bo_find(vm: &fpriv->vm, bo: rbo); |
732 | if (!bo_va) { |
733 | args->operation = RADEON_VA_RESULT_ERROR; |
734 | radeon_bo_unreserve(bo: rbo); |
735 | drm_gem_object_put(obj: gobj); |
736 | return -ENOENT; |
737 | } |
738 | |
739 | switch (args->operation) { |
740 | case RADEON_VA_MAP: |
741 | if (bo_va->it.start) { |
742 | args->operation = RADEON_VA_RESULT_VA_EXIST; |
743 | args->offset = bo_va->it.start * RADEON_GPU_PAGE_SIZE; |
744 | radeon_bo_unreserve(bo: rbo); |
745 | goto out; |
746 | } |
747 | r = radeon_vm_bo_set_addr(rdev, bo_va, offset: args->offset, flags: args->flags); |
748 | break; |
749 | case RADEON_VA_UNMAP: |
750 | r = radeon_vm_bo_set_addr(rdev, bo_va, offset: 0, flags: 0); |
751 | break; |
752 | default: |
753 | break; |
754 | } |
755 | if (!r) |
756 | radeon_gem_va_update_vm(rdev, bo_va); |
757 | args->operation = RADEON_VA_RESULT_OK; |
758 | if (r) { |
759 | args->operation = RADEON_VA_RESULT_ERROR; |
760 | } |
761 | out: |
762 | drm_gem_object_put(obj: gobj); |
763 | return r; |
764 | } |
765 | |
766 | int radeon_gem_op_ioctl(struct drm_device *dev, void *data, |
767 | struct drm_file *filp) |
768 | { |
769 | struct drm_radeon_gem_op *args = data; |
770 | struct drm_gem_object *gobj; |
771 | struct radeon_bo *robj; |
772 | int r; |
773 | |
774 | gobj = drm_gem_object_lookup(filp, handle: args->handle); |
775 | if (gobj == NULL) { |
776 | return -ENOENT; |
777 | } |
778 | robj = gem_to_radeon_bo(gobj); |
779 | |
780 | r = -EPERM; |
781 | if (radeon_ttm_tt_has_userptr(rdev: robj->rdev, ttm: robj->tbo.ttm)) |
782 | goto out; |
783 | |
784 | r = radeon_bo_reserve(bo: robj, no_intr: false); |
785 | if (unlikely(r)) |
786 | goto out; |
787 | |
788 | switch (args->op) { |
789 | case RADEON_GEM_OP_GET_INITIAL_DOMAIN: |
790 | args->value = robj->initial_domain; |
791 | break; |
792 | case RADEON_GEM_OP_SET_INITIAL_DOMAIN: |
793 | robj->initial_domain = args->value & (RADEON_GEM_DOMAIN_VRAM | |
794 | RADEON_GEM_DOMAIN_GTT | |
795 | RADEON_GEM_DOMAIN_CPU); |
796 | break; |
797 | default: |
798 | r = -EINVAL; |
799 | } |
800 | |
801 | radeon_bo_unreserve(bo: robj); |
802 | out: |
803 | drm_gem_object_put(obj: gobj); |
804 | return r; |
805 | } |
806 | |
807 | int radeon_align_pitch(struct radeon_device *rdev, int width, int cpp, bool tiled) |
808 | { |
809 | int aligned = width; |
810 | int align_large = (ASIC_IS_AVIVO(rdev)) || tiled; |
811 | int pitch_mask = 0; |
812 | |
813 | switch (cpp) { |
814 | case 1: |
815 | pitch_mask = align_large ? 255 : 127; |
816 | break; |
817 | case 2: |
818 | pitch_mask = align_large ? 127 : 31; |
819 | break; |
820 | case 3: |
821 | case 4: |
822 | pitch_mask = align_large ? 63 : 15; |
823 | break; |
824 | } |
825 | |
826 | aligned += pitch_mask; |
827 | aligned &= ~pitch_mask; |
828 | return aligned * cpp; |
829 | } |
830 | |
831 | int radeon_mode_dumb_create(struct drm_file *file_priv, |
832 | struct drm_device *dev, |
833 | struct drm_mode_create_dumb *args) |
834 | { |
835 | struct radeon_device *rdev = dev->dev_private; |
836 | struct drm_gem_object *gobj; |
837 | uint32_t handle; |
838 | int r; |
839 | |
840 | args->pitch = radeon_align_pitch(rdev, width: args->width, |
841 | DIV_ROUND_UP(args->bpp, 8), tiled: 0); |
842 | args->size = (u64)args->pitch * args->height; |
843 | args->size = ALIGN(args->size, PAGE_SIZE); |
844 | |
845 | r = radeon_gem_object_create(rdev, size: args->size, alignment: 0, |
846 | RADEON_GEM_DOMAIN_VRAM, flags: 0, |
847 | kernel: false, obj: &gobj); |
848 | if (r) |
849 | return -ENOMEM; |
850 | |
851 | r = drm_gem_handle_create(file_priv, obj: gobj, handlep: &handle); |
852 | /* drop reference from allocate - handle holds it now */ |
853 | drm_gem_object_put(obj: gobj); |
854 | if (r) { |
855 | return r; |
856 | } |
857 | args->handle = handle; |
858 | return 0; |
859 | } |
860 | |
861 | #if defined(CONFIG_DEBUG_FS) |
862 | static int radeon_debugfs_gem_info_show(struct seq_file *m, void *unused) |
863 | { |
864 | struct radeon_device *rdev = m->private; |
865 | struct radeon_bo *rbo; |
866 | unsigned i = 0; |
867 | |
868 | mutex_lock(&rdev->gem.mutex); |
869 | list_for_each_entry(rbo, &rdev->gem.objects, list) { |
870 | unsigned domain; |
871 | const char *placement; |
872 | |
873 | domain = radeon_mem_type_to_domain(mem_type: rbo->tbo.resource->mem_type); |
874 | switch (domain) { |
875 | case RADEON_GEM_DOMAIN_VRAM: |
876 | placement = "VRAM" ; |
877 | break; |
878 | case RADEON_GEM_DOMAIN_GTT: |
879 | placement = " GTT" ; |
880 | break; |
881 | case RADEON_GEM_DOMAIN_CPU: |
882 | default: |
883 | placement = " CPU" ; |
884 | break; |
885 | } |
886 | seq_printf(m, fmt: "bo[0x%08x] %8ldkB %8ldMB %s pid %8ld\n" , |
887 | i, radeon_bo_size(bo: rbo) >> 10, radeon_bo_size(bo: rbo) >> 20, |
888 | placement, (unsigned long)rbo->pid); |
889 | i++; |
890 | } |
891 | mutex_unlock(lock: &rdev->gem.mutex); |
892 | return 0; |
893 | } |
894 | |
895 | DEFINE_SHOW_ATTRIBUTE(radeon_debugfs_gem_info); |
896 | #endif |
897 | |
898 | void radeon_gem_debugfs_init(struct radeon_device *rdev) |
899 | { |
900 | #if defined(CONFIG_DEBUG_FS) |
901 | struct dentry *root = rdev->ddev->primary->debugfs_root; |
902 | |
903 | debugfs_create_file(name: "radeon_gem_info" , mode: 0444, parent: root, data: rdev, |
904 | fops: &radeon_debugfs_gem_info_fops); |
905 | |
906 | #endif |
907 | } |
908 | |