History

drm/panthor: Fix sync-only jobs

A sync-only job is meant to provide a synchronization point on a queue, so we can't return a NULL fence there, we have to add a signal operation to the command stream which executes after all other previously submitted jobs are done. v2: - Fixed a UAF bug - Added R-bs

Boris Brezillon committed 2 years ago

Commit 7b6f9ec1 parent 1a9a7142 files · +38 −11Browse files

Unified · Split

2 files
  1. drivers/gpu/drm/panthor/panthor_sched.c +33 −11
  2. include/uapi/drm/panthor_drm.h +5 −0
drivers/gpu/drm/panthor/panthor_sched.c+33−11
@@ -458,6 +458,16 @@ struct panthor_queue { · 457 unmodified lines
458 /** @seqno: Sequence number of the last initialized fence. */458 /** @seqno: Sequence number of the last initialized fence. */
459 atomic64_t seqno;459 atomic64_t seqno;
460 460
461 /**
462 * @last_fence: Fence of the last submitted job.
463 *
464 * We return this fence when we get an empty command stream.
465 * This way, we are guaranteed that all earlier jobs have completed
466 * when drm_sched_job::s_fence::finished without having to feed
467 * the CS ring buffer with a dummy job that only signals the fence.
468 */
469 struct dma_fence *last_fence;
470
461 /**471 /**
462 * @in_flight_jobs: List containing all in-flight jobs.472 * @in_flight_jobs: List containing all in-flight jobs.
463 *473 *
@@ -829,6 +839,9 @@ static void group_free_queue(struct panthor_group *group, struct panthor_queue * · 365 unmodified lines
829 panthor_kernel_bo_destroy(queue->ringbuf);839 panthor_kernel_bo_destroy(queue->ringbuf);
830 panthor_kernel_bo_destroy(queue->iface.mem);840 panthor_kernel_bo_destroy(queue->iface.mem);
831 841
842 /* Release the last_fence we were holding, if any. */
843 dma_fence_put(queue->fence_ctx.last_fence);
844
832 kfree(queue);845 kfree(queue);
833}846}
834 847
@@ -2784,9 +2797,6 @@ static void group_sync_upd_work(struct work_struct *work) · 1949 unmodified lines
2784 2797
2785 spin_lock(&queue->fence_ctx.lock);2798 spin_lock(&queue->fence_ctx.lock);
2786 list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {2799 list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
2787 if (!job->call_info.size)
2788 continue;
2789
2790 if (syncobj->seqno < job->done_fence->seqno)2800 if (syncobj->seqno < job->done_fence->seqno)
2791 break;2801 break;
2792 2802
@@ -2865,11 +2875,14 @@ queue_run_job(struct drm_sched_job *sched_job) · 72 unmodified lines
2865 static_assert(sizeof(call_instrs) % 64 == 0,2875 static_assert(sizeof(call_instrs) % 64 == 0,
2866 "call_instrs is not aligned on a cacheline");2876 "call_instrs is not aligned on a cacheline");
2867 2877
2868 /* Stream size is zero, nothing to do => return a NULL fence and let2878 /* Stream size is zero, nothing to do except making sure all previously
2869 * drm_sched signal the parent.2879 * submitted jobs are done before we signal the
2880 * drm_sched_job::s_fence::finished fence.
2870 */2881 */
2871 if (!job->call_info.size)2882 if (!job->call_info.size) {
2872 return NULL;2883 job->done_fence = dma_fence_get(queue->fence_ctx.last_fence);
2884 return dma_fence_get(job->done_fence);
2885 }
2873 2886
2874 ret = pm_runtime_resume_and_get(ptdev->base.dev);2887 ret = pm_runtime_resume_and_get(ptdev->base.dev);
2875 if (drm_WARN_ON(&ptdev->base, ret))2888 if (drm_WARN_ON(&ptdev->base, ret))
@@ -2928,6 +2941,10 @@ queue_run_job(struct drm_sched_job *sched_job) · 52 unmodified lines
2928 }2941 }
2929 }2942 }
2930 2943
2944 /* Update the last fence. */
2945 dma_fence_put(queue->fence_ctx.last_fence);
2946 queue->fence_ctx.last_fence = dma_fence_get(job->done_fence);
2947
2931 done_fence = dma_fence_get(job->done_fence);2948 done_fence = dma_fence_get(job->done_fence);
2932 2949
2933out_unlock:2950out_unlock:
@@ -3378,10 +3395,15 @@ panthor_job_create(struct panthor_file *pfile, · 444 unmodified lines
3378 goto err_put_job;3395 goto err_put_job;
3379 }3396 }
3380 3397
3381 job->done_fence = kzalloc(sizeof(*job->done_fence), GFP_KERNEL);3398 /* Empty command streams don't need a fence, they'll pick the one from
3382 if (!job->done_fence) {3399 * the previously submitted job.
3383 ret = -ENOMEM;3400 */
3384 goto err_put_job;3401 if (job->call_info.size) {
3402 job->done_fence = kzalloc(sizeof(*job->done_fence), GFP_KERNEL);
3403 if (!job->done_fence) {
3404 ret = -ENOMEM;
3405 goto err_put_job;
3406 }
3385 }3407 }
3386 3408
3387 ret = drm_sched_job_init(&job->base,3409 ret = drm_sched_job_init(&job->base,
include/uapi/drm/panthor_drm.h+5−0
@@ -802,6 +802,9 @@ struct drm_panthor_queue_submit { · 801 unmodified lines
802 * Must be 64-bit/8-byte aligned (the size of a CS instruction)802 * Must be 64-bit/8-byte aligned (the size of a CS instruction)
803 *803 *
804 * Can be zero if stream_addr is zero too.804 * Can be zero if stream_addr is zero too.
805 *
806 * When the stream size is zero, the queue submit serves as a
807 * synchronization point.
805 */808 */
806 __u32 stream_size;809 __u32 stream_size;
807 810
@@ -822,6 +825,8 @@ struct drm_panthor_queue_submit { · 14 unmodified lines
822 * ensure the GPU doesn't get garbage when reading the indirect command825 * ensure the GPU doesn't get garbage when reading the indirect command
823 * stream buffers. If you want the cache flush to happen826 * stream buffers. If you want the cache flush to happen
824 * unconditionally, pass a zero here.827 * unconditionally, pass a zero here.
828 *
829 * Ignored when stream_size is zero.
825 */830 */
826 __u32 latest_flush;831 __u32 latest_flush;
827 832