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
Unified · Split
| @@ -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 let | 2878 | /* 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 | ||
| 2933 | out_unlock: | 2950 | out_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, |
| @@ -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 command | 825 | * ensure the GPU doesn't get garbage when reading the indirect command |
| 823 | * stream buffers. If you want the cache flush to happen | 826 | * 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 | ||