| .. | .. |
|---|
| 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"); |
|---|