.. | .. |
---|
4 | 4 | */ |
---|
5 | 5 | |
---|
6 | 6 | #include <linux/component.h> |
---|
| 7 | +#include <linux/dma-mapping.h> |
---|
| 8 | +#include <linux/module.h> |
---|
7 | 9 | #include <linux/of_platform.h> |
---|
| 10 | +#include <linux/uaccess.h> |
---|
| 11 | + |
---|
| 12 | +#include <drm/drm_debugfs.h> |
---|
| 13 | +#include <drm/drm_drv.h> |
---|
| 14 | +#include <drm/drm_file.h> |
---|
| 15 | +#include <drm/drm_ioctl.h> |
---|
8 | 16 | #include <drm/drm_of.h> |
---|
| 17 | +#include <drm/drm_prime.h> |
---|
9 | 18 | |
---|
10 | 19 | #include "etnaviv_cmdbuf.h" |
---|
11 | 20 | #include "etnaviv_drv.h" |
---|
.. | .. |
---|
41 | 50 | { |
---|
42 | 51 | struct etnaviv_drm_private *priv = dev->dev_private; |
---|
43 | 52 | struct etnaviv_file_private *ctx; |
---|
44 | | - int i; |
---|
| 53 | + int ret, i; |
---|
45 | 54 | |
---|
46 | 55 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
---|
47 | 56 | if (!ctx) |
---|
48 | 57 | return -ENOMEM; |
---|
49 | 58 | |
---|
| 59 | + ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global, |
---|
| 60 | + priv->cmdbuf_suballoc); |
---|
| 61 | + if (!ctx->mmu) { |
---|
| 62 | + ret = -ENOMEM; |
---|
| 63 | + goto out_free; |
---|
| 64 | + } |
---|
| 65 | + |
---|
50 | 66 | for (i = 0; i < ETNA_MAX_PIPES; i++) { |
---|
51 | 67 | struct etnaviv_gpu *gpu = priv->gpu[i]; |
---|
52 | | - struct drm_sched_rq *rq; |
---|
| 68 | + struct drm_gpu_scheduler *sched; |
---|
53 | 69 | |
---|
54 | 70 | if (gpu) { |
---|
55 | | - rq = &gpu->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; |
---|
| 71 | + sched = &gpu->sched; |
---|
56 | 72 | drm_sched_entity_init(&ctx->sched_entity[i], |
---|
57 | | - &rq, 1, NULL); |
---|
| 73 | + DRM_SCHED_PRIORITY_NORMAL, &sched, |
---|
| 74 | + 1, NULL); |
---|
58 | 75 | } |
---|
59 | 76 | } |
---|
60 | 77 | |
---|
61 | 78 | file->driver_priv = ctx; |
---|
62 | 79 | |
---|
63 | 80 | return 0; |
---|
| 81 | + |
---|
| 82 | +out_free: |
---|
| 83 | + kfree(ctx); |
---|
| 84 | + return ret; |
---|
64 | 85 | } |
---|
65 | 86 | |
---|
66 | 87 | static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) |
---|
.. | .. |
---|
72 | 93 | for (i = 0; i < ETNA_MAX_PIPES; i++) { |
---|
73 | 94 | struct etnaviv_gpu *gpu = priv->gpu[i]; |
---|
74 | 95 | |
---|
75 | | - if (gpu) { |
---|
76 | | - mutex_lock(&gpu->lock); |
---|
77 | | - if (gpu->lastctx == ctx) |
---|
78 | | - gpu->lastctx = NULL; |
---|
79 | | - mutex_unlock(&gpu->lock); |
---|
80 | | - |
---|
| 96 | + if (gpu) |
---|
81 | 97 | drm_sched_entity_destroy(&ctx->sched_entity[i]); |
---|
82 | | - } |
---|
83 | 98 | } |
---|
| 99 | + |
---|
| 100 | + etnaviv_iommu_context_put(ctx->mmu); |
---|
84 | 101 | |
---|
85 | 102 | kfree(ctx); |
---|
86 | 103 | } |
---|
.. | .. |
---|
113 | 130 | static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m) |
---|
114 | 131 | { |
---|
115 | 132 | struct drm_printer p = drm_seq_file_printer(m); |
---|
| 133 | + struct etnaviv_iommu_context *mmu_context; |
---|
116 | 134 | |
---|
117 | 135 | seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev)); |
---|
118 | 136 | |
---|
119 | | - mutex_lock(&gpu->mmu->lock); |
---|
120 | | - drm_mm_print(&gpu->mmu->mm, &p); |
---|
121 | | - mutex_unlock(&gpu->mmu->lock); |
---|
| 137 | + /* |
---|
| 138 | + * Lock the GPU to avoid a MMU context switch just now and elevate |
---|
| 139 | + * the refcount of the current context to avoid it disappearing from |
---|
| 140 | + * under our feet. |
---|
| 141 | + */ |
---|
| 142 | + mutex_lock(&gpu->lock); |
---|
| 143 | + mmu_context = gpu->mmu_context; |
---|
| 144 | + if (mmu_context) |
---|
| 145 | + etnaviv_iommu_context_get(mmu_context); |
---|
| 146 | + mutex_unlock(&gpu->lock); |
---|
| 147 | + |
---|
| 148 | + if (!mmu_context) |
---|
| 149 | + return 0; |
---|
| 150 | + |
---|
| 151 | + mutex_lock(&mmu_context->lock); |
---|
| 152 | + drm_mm_print(&mmu_context->mm, &p); |
---|
| 153 | + mutex_unlock(&mmu_context->lock); |
---|
| 154 | + |
---|
| 155 | + etnaviv_iommu_context_put(mmu_context); |
---|
122 | 156 | |
---|
123 | 157 | return 0; |
---|
124 | 158 | } |
---|
.. | .. |
---|
197 | 231 | {"ring", show_each_gpu, 0, etnaviv_ring_show}, |
---|
198 | 232 | }; |
---|
199 | 233 | |
---|
200 | | -static int etnaviv_debugfs_init(struct drm_minor *minor) |
---|
| 234 | +static void etnaviv_debugfs_init(struct drm_minor *minor) |
---|
201 | 235 | { |
---|
202 | | - struct drm_device *dev = minor->dev; |
---|
203 | | - int ret; |
---|
204 | | - |
---|
205 | | - ret = drm_debugfs_create_files(etnaviv_debugfs_list, |
---|
206 | | - ARRAY_SIZE(etnaviv_debugfs_list), |
---|
207 | | - minor->debugfs_root, minor); |
---|
208 | | - |
---|
209 | | - if (ret) { |
---|
210 | | - dev_err(dev->dev, "could not install etnaviv_debugfs_list\n"); |
---|
211 | | - return ret; |
---|
212 | | - } |
---|
213 | | - |
---|
214 | | - return ret; |
---|
| 236 | + drm_debugfs_create_files(etnaviv_debugfs_list, |
---|
| 237 | + ARRAY_SIZE(etnaviv_debugfs_list), |
---|
| 238 | + minor->debugfs_root, minor); |
---|
215 | 239 | } |
---|
216 | 240 | #endif |
---|
217 | 241 | |
---|
.. | .. |
---|
249 | 273 | args->flags, &args->handle); |
---|
250 | 274 | } |
---|
251 | 275 | |
---|
252 | | -#define TS(t) ((struct timespec){ \ |
---|
253 | | - .tv_sec = (t).tv_sec, \ |
---|
254 | | - .tv_nsec = (t).tv_nsec \ |
---|
255 | | -}) |
---|
256 | | - |
---|
257 | 276 | static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, |
---|
258 | 277 | struct drm_file *file) |
---|
259 | 278 | { |
---|
.. | .. |
---|
268 | 287 | if (!obj) |
---|
269 | 288 | return -ENOENT; |
---|
270 | 289 | |
---|
271 | | - ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout)); |
---|
| 290 | + ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout); |
---|
272 | 291 | |
---|
273 | | - drm_gem_object_put_unlocked(obj); |
---|
| 292 | + drm_gem_object_put(obj); |
---|
274 | 293 | |
---|
275 | 294 | return ret; |
---|
276 | 295 | } |
---|
.. | .. |
---|
291 | 310 | |
---|
292 | 311 | ret = etnaviv_gem_cpu_fini(obj); |
---|
293 | 312 | |
---|
294 | | - drm_gem_object_put_unlocked(obj); |
---|
| 313 | + drm_gem_object_put(obj); |
---|
295 | 314 | |
---|
296 | 315 | return ret; |
---|
297 | 316 | } |
---|
.. | .. |
---|
311 | 330 | return -ENOENT; |
---|
312 | 331 | |
---|
313 | 332 | ret = etnaviv_gem_mmap_offset(obj, &args->offset); |
---|
314 | | - drm_gem_object_put_unlocked(obj); |
---|
| 333 | + drm_gem_object_put(obj); |
---|
315 | 334 | |
---|
316 | 335 | return ret; |
---|
317 | 336 | } |
---|
.. | .. |
---|
321 | 340 | { |
---|
322 | 341 | struct drm_etnaviv_wait_fence *args = data; |
---|
323 | 342 | struct etnaviv_drm_private *priv = dev->dev_private; |
---|
324 | | - struct timespec *timeout = &TS(args->timeout); |
---|
| 343 | + struct drm_etnaviv_timespec *timeout = &args->timeout; |
---|
325 | 344 | struct etnaviv_gpu *gpu; |
---|
326 | 345 | |
---|
327 | 346 | if (args->flags & ~(ETNA_WAIT_NONBLOCK)) |
---|
.. | .. |
---|
345 | 364 | struct drm_file *file) |
---|
346 | 365 | { |
---|
347 | 366 | struct drm_etnaviv_gem_userptr *args = data; |
---|
348 | | - int access; |
---|
349 | 367 | |
---|
350 | 368 | if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) || |
---|
351 | 369 | args->flags == 0) |
---|
.. | .. |
---|
357 | 375 | args->user_ptr & ~PAGE_MASK) |
---|
358 | 376 | return -EINVAL; |
---|
359 | 377 | |
---|
360 | | - if (args->flags & ETNA_USERPTR_WRITE) |
---|
361 | | - access = VERIFY_WRITE; |
---|
362 | | - else |
---|
363 | | - access = VERIFY_READ; |
---|
364 | | - |
---|
365 | | - if (!access_ok(access, (void __user *)(unsigned long)args->user_ptr, |
---|
| 378 | + if (!access_ok((void __user *)(unsigned long)args->user_ptr, |
---|
366 | 379 | args->user_size)) |
---|
367 | 380 | return -EFAULT; |
---|
368 | 381 | |
---|
.. | .. |
---|
376 | 389 | { |
---|
377 | 390 | struct etnaviv_drm_private *priv = dev->dev_private; |
---|
378 | 391 | struct drm_etnaviv_gem_wait *args = data; |
---|
379 | | - struct timespec *timeout = &TS(args->timeout); |
---|
| 392 | + struct drm_etnaviv_timespec *timeout = &args->timeout; |
---|
380 | 393 | struct drm_gem_object *obj; |
---|
381 | 394 | struct etnaviv_gpu *gpu; |
---|
382 | 395 | int ret; |
---|
.. | .. |
---|
400 | 413 | |
---|
401 | 414 | ret = etnaviv_gem_wait_bo(gpu, obj, timeout); |
---|
402 | 415 | |
---|
403 | | - drm_gem_object_put_unlocked(obj); |
---|
| 416 | + drm_gem_object_put(obj); |
---|
404 | 417 | |
---|
405 | 418 | return ret; |
---|
406 | 419 | } |
---|
.. | .. |
---|
442 | 455 | static const struct drm_ioctl_desc etnaviv_ioctls[] = { |
---|
443 | 456 | #define ETNA_IOCTL(n, func, flags) \ |
---|
444 | 457 | DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags) |
---|
445 | | - ETNA_IOCTL(GET_PARAM, get_param, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
446 | | - ETNA_IOCTL(GEM_NEW, gem_new, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
447 | | - ETNA_IOCTL(GEM_INFO, gem_info, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
448 | | - ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
449 | | - ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
450 | | - ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
451 | | - ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
452 | | - ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
453 | | - ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
454 | | - ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
455 | | - ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_AUTH|DRM_RENDER_ALLOW), |
---|
| 458 | + ETNA_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), |
---|
| 459 | + ETNA_IOCTL(GEM_NEW, gem_new, DRM_RENDER_ALLOW), |
---|
| 460 | + ETNA_IOCTL(GEM_INFO, gem_info, DRM_RENDER_ALLOW), |
---|
| 461 | + ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW), |
---|
| 462 | + ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW), |
---|
| 463 | + ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_RENDER_ALLOW), |
---|
| 464 | + ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_RENDER_ALLOW), |
---|
| 465 | + ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_RENDER_ALLOW), |
---|
| 466 | + ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_RENDER_ALLOW), |
---|
| 467 | + ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW), |
---|
| 468 | + ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), |
---|
456 | 469 | }; |
---|
457 | 470 | |
---|
458 | 471 | static const struct vm_operations_struct vm_ops = { |
---|
.. | .. |
---|
474 | 487 | }; |
---|
475 | 488 | |
---|
476 | 489 | static struct drm_driver etnaviv_drm_driver = { |
---|
477 | | - .driver_features = DRIVER_GEM | |
---|
478 | | - DRIVER_PRIME | |
---|
479 | | - DRIVER_RENDER, |
---|
| 490 | + .driver_features = DRIVER_GEM | DRIVER_RENDER, |
---|
480 | 491 | .open = etnaviv_open, |
---|
481 | 492 | .postclose = etnaviv_postclose, |
---|
482 | 493 | .gem_free_object_unlocked = etnaviv_gem_free_object, |
---|
483 | 494 | .gem_vm_ops = &vm_ops, |
---|
484 | 495 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
---|
485 | 496 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
---|
486 | | - .gem_prime_export = drm_gem_prime_export, |
---|
487 | | - .gem_prime_import = drm_gem_prime_import, |
---|
488 | | - .gem_prime_res_obj = etnaviv_gem_prime_res_obj, |
---|
489 | 497 | .gem_prime_pin = etnaviv_gem_prime_pin, |
---|
490 | 498 | .gem_prime_unpin = etnaviv_gem_prime_unpin, |
---|
491 | 499 | .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table, |
---|
.. | .. |
---|
503 | 511 | .desc = "etnaviv DRM", |
---|
504 | 512 | .date = "20151214", |
---|
505 | 513 | .major = 1, |
---|
506 | | - .minor = 2, |
---|
| 514 | + .minor = 3, |
---|
507 | 515 | }; |
---|
508 | 516 | |
---|
509 | 517 | /* |
---|
.. | .. |
---|
523 | 531 | if (!priv) { |
---|
524 | 532 | dev_err(dev, "failed to allocate private data\n"); |
---|
525 | 533 | ret = -ENOMEM; |
---|
526 | | - goto out_unref; |
---|
| 534 | + goto out_put; |
---|
527 | 535 | } |
---|
528 | 536 | drm->dev_private = priv; |
---|
529 | 537 | |
---|
.. | .. |
---|
533 | 541 | mutex_init(&priv->gem_lock); |
---|
534 | 542 | INIT_LIST_HEAD(&priv->gem_list); |
---|
535 | 543 | priv->num_gpus = 0; |
---|
| 544 | + priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN; |
---|
| 545 | + |
---|
| 546 | + priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev); |
---|
| 547 | + if (IS_ERR(priv->cmdbuf_suballoc)) { |
---|
| 548 | + dev_err(drm->dev, "Failed to create cmdbuf suballocator\n"); |
---|
| 549 | + ret = PTR_ERR(priv->cmdbuf_suballoc); |
---|
| 550 | + goto out_free_priv; |
---|
| 551 | + } |
---|
536 | 552 | |
---|
537 | 553 | dev_set_drvdata(dev, drm); |
---|
538 | 554 | |
---|
539 | 555 | ret = component_bind_all(dev, drm); |
---|
540 | 556 | if (ret < 0) |
---|
541 | | - goto out_bind; |
---|
| 557 | + goto out_destroy_suballoc; |
---|
542 | 558 | |
---|
543 | 559 | load_gpu(drm); |
---|
544 | 560 | |
---|
545 | 561 | ret = drm_dev_register(drm, 0); |
---|
546 | 562 | if (ret) |
---|
547 | | - goto out_register; |
---|
| 563 | + goto out_unbind; |
---|
548 | 564 | |
---|
549 | 565 | return 0; |
---|
550 | 566 | |
---|
551 | | -out_register: |
---|
| 567 | +out_unbind: |
---|
552 | 568 | component_unbind_all(dev, drm); |
---|
553 | | -out_bind: |
---|
| 569 | +out_destroy_suballoc: |
---|
| 570 | + etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); |
---|
| 571 | +out_free_priv: |
---|
554 | 572 | kfree(priv); |
---|
555 | | -out_unref: |
---|
556 | | - drm_dev_unref(drm); |
---|
| 573 | +out_put: |
---|
| 574 | + drm_dev_put(drm); |
---|
557 | 575 | |
---|
558 | 576 | return ret; |
---|
559 | 577 | } |
---|
.. | .. |
---|
569 | 587 | |
---|
570 | 588 | dev->dma_parms = NULL; |
---|
571 | 589 | |
---|
| 590 | + etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); |
---|
| 591 | + |
---|
572 | 592 | drm->dev_private = NULL; |
---|
573 | 593 | kfree(priv); |
---|
574 | 594 | |
---|
575 | | - drm_dev_unref(drm); |
---|
| 595 | + drm_dev_put(drm); |
---|
576 | 596 | } |
---|
577 | 597 | |
---|
578 | 598 | static const struct component_master_ops etnaviv_master_ops = { |
---|
.. | .. |
---|
706 | 726 | module_exit(etnaviv_exit); |
---|
707 | 727 | |
---|
708 | 728 | MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); |
---|
709 | | -MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); |
---|
| 729 | +MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>"); |
---|
710 | 730 | MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>"); |
---|
711 | 731 | MODULE_DESCRIPTION("etnaviv DRM Driver"); |
---|
712 | 732 | MODULE_LICENSE("GPL v2"); |
---|