diff options
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 60 | ||||
-rw-r--r-- | drivers/gpu/host1x/job.h | 7 | ||||
-rw-r--r-- | include/linux/host1x.h | 7 |
3 files changed, 63 insertions, 11 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 51e20e015053..0928f2bb4203 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -349,6 +349,36 @@ static int host1x_reloc_copy_from_user(struct host1x_reloc *dest, | |||
349 | return 0; | 349 | return 0; |
350 | } | 350 | } |
351 | 351 | ||
352 | static int host1x_waitchk_copy_from_user(struct host1x_waitchk *dest, | ||
353 | struct drm_tegra_waitchk __user *src, | ||
354 | struct drm_file *file) | ||
355 | { | ||
356 | u32 cmdbuf; | ||
357 | int err; | ||
358 | |||
359 | err = get_user(cmdbuf, &src->handle); | ||
360 | if (err < 0) | ||
361 | return err; | ||
362 | |||
363 | err = get_user(dest->offset, &src->offset); | ||
364 | if (err < 0) | ||
365 | return err; | ||
366 | |||
367 | err = get_user(dest->syncpt_id, &src->syncpt); | ||
368 | if (err < 0) | ||
369 | return err; | ||
370 | |||
371 | err = get_user(dest->thresh, &src->thresh); | ||
372 | if (err < 0) | ||
373 | return err; | ||
374 | |||
375 | dest->bo = host1x_bo_lookup(file, cmdbuf); | ||
376 | if (!dest->bo) | ||
377 | return -ENOENT; | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
352 | int tegra_drm_submit(struct tegra_drm_context *context, | 382 | int tegra_drm_submit(struct tegra_drm_context *context, |
353 | struct drm_tegra_submit *args, struct drm_device *drm, | 383 | struct drm_tegra_submit *args, struct drm_device *drm, |
354 | struct drm_file *file) | 384 | struct drm_file *file) |
@@ -370,6 +400,10 @@ int tegra_drm_submit(struct tegra_drm_context *context, | |||
370 | if (args->num_syncpts != 1) | 400 | if (args->num_syncpts != 1) |
371 | return -EINVAL; | 401 | return -EINVAL; |
372 | 402 | ||
403 | /* We don't yet support waitchks */ | ||
404 | if (args->num_waitchks != 0) | ||
405 | return -EINVAL; | ||
406 | |||
373 | job = host1x_job_alloc(context->channel, args->num_cmdbufs, | 407 | job = host1x_job_alloc(context->channel, args->num_cmdbufs, |
374 | args->num_relocs, args->num_waitchks); | 408 | args->num_relocs, args->num_waitchks); |
375 | if (!job) | 409 | if (!job) |
@@ -458,10 +492,28 @@ int tegra_drm_submit(struct tegra_drm_context *context, | |||
458 | } | 492 | } |
459 | } | 493 | } |
460 | 494 | ||
461 | if (copy_from_user(job->waitchk, waitchks, | 495 | /* copy and resolve waitchks from submit */ |
462 | sizeof(*waitchks) * num_waitchks)) { | 496 | while (num_waitchks--) { |
463 | err = -EFAULT; | 497 | struct host1x_waitchk *wait = &job->waitchk[num_waitchks]; |
464 | goto fail; | 498 | struct tegra_bo *obj; |
499 | |||
500 | err = host1x_waitchk_copy_from_user(wait, | ||
501 | &waitchks[num_waitchks], | ||
502 | file); | ||
503 | if (err < 0) | ||
504 | goto fail; | ||
505 | |||
506 | obj = host1x_to_tegra_bo(wait->bo); | ||
507 | |||
508 | /* | ||
509 | * The unaligned offset will cause an unaligned write during | ||
510 | * of the waitchks patching, corrupting the commands stream. | ||
511 | */ | ||
512 | if (wait->offset & 3 || | ||
513 | wait->offset >= obj->gem.size) { | ||
514 | err = -EINVAL; | ||
515 | goto fail; | ||
516 | } | ||
465 | } | 517 | } |
466 | 518 | ||
467 | if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts, | 519 | if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts, |
diff --git a/drivers/gpu/host1x/job.h b/drivers/gpu/host1x/job.h index 878239c476d2..0debd93a1849 100644 --- a/drivers/gpu/host1x/job.h +++ b/drivers/gpu/host1x/job.h | |||
@@ -34,13 +34,6 @@ struct host1x_cmdbuf { | |||
34 | u32 pad; | 34 | u32 pad; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct host1x_waitchk { | ||
38 | struct host1x_bo *bo; | ||
39 | u32 offset; | ||
40 | u32 syncpt_id; | ||
41 | u32 thresh; | ||
42 | }; | ||
43 | |||
44 | struct host1x_job_unpin_data { | 37 | struct host1x_job_unpin_data { |
45 | struct host1x_bo *bo; | 38 | struct host1x_bo *bo; |
46 | struct sg_table *sgt; | 39 | struct sg_table *sgt; |
diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 840a8ad627b2..ba0b245da732 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h | |||
@@ -193,6 +193,13 @@ struct host1x_reloc { | |||
193 | unsigned long shift; | 193 | unsigned long shift; |
194 | }; | 194 | }; |
195 | 195 | ||
196 | struct host1x_waitchk { | ||
197 | struct host1x_bo *bo; | ||
198 | u32 offset; | ||
199 | u32 syncpt_id; | ||
200 | u32 thresh; | ||
201 | }; | ||
202 | |||
196 | struct host1x_job { | 203 | struct host1x_job { |
197 | /* When refcount goes to zero, job can be freed */ | 204 | /* When refcount goes to zero, job can be freed */ |
198 | struct kref ref; | 205 | struct kref ref; |