Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some more Panthor fixes #210

Merged
merged 4 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions drivers/gpu/drm/panthor/panthor_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride,
int ret = 0;
void *out_alloc;

if (!in->count)
return NULL;

/* User stride must be at least the minimum object size, otherwise it might
* lack useful information.
*/
if (in->stride < min_stride)
return ERR_PTR(-EINVAL);

if (!in->count)
return NULL;

out_alloc = kvmalloc_array(in->count, obj_size, GFP_KERNEL);
if (!out_alloc)
return ERR_PTR(-ENOMEM);
Expand Down
8 changes: 7 additions & 1 deletion drivers/gpu/drm/panthor/panthor_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,12 @@ int panthor_fw_post_reset(struct panthor_device *ptdev)
panthor_fw_stop(ptdev);
ptdev->fw->fast_reset = false;
drm_err(&ptdev->base, "FW fast reset failed, trying a slow reset");

ret = panthor_vm_flush_all(ptdev->fw->vm);
if (ret) {
drm_err(&ptdev->base, "FW slow reset failed (couldn't flush FW's AS l2cache)");
return ret;
}
}

/* Reload all sections, including RO ones. We're not supposed
Expand All @@ -1099,7 +1105,7 @@ int panthor_fw_post_reset(struct panthor_device *ptdev)

ret = panthor_fw_start(ptdev);
if (ret) {
drm_err(&ptdev->base, "FW slow reset failed");
drm_err(&ptdev->base, "FW slow reset failed (couldn't start the FW )");
return ret;
}

Expand Down
19 changes: 16 additions & 3 deletions drivers/gpu/drm/panthor/panthor_mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,14 +873,27 @@ static int panthor_vm_flush_range(struct panthor_vm *vm, u64 iova, u64 size)
if (!drm_dev_enter(&ptdev->base, &cookie))
return 0;

/* Flush the PTs only if we're already awake */
if (pm_runtime_active(ptdev->base.dev))
ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT);
/*
* If we made it this far, that means the device is awake, because
* upon device suspension, all active VMs are given an AS id of -1
*/
ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT);

drm_dev_exit(cookie);
return ret;
}

/**
* panthor_vm_flush_all() - Flush L2 caches for the entirety of a VM's AS
* @vm: VM whose cache to flush
*
* Return: 0 on success, a negative error code if flush failed.
*/
int panthor_vm_flush_all(struct panthor_vm *vm)
{
return panthor_vm_flush_range(vm, vm->base.mm_start, vm->base.mm_range);
}

static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
{
struct panthor_device *ptdev = vm->ptdev;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/panthor/panthor_mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 va, u64 *bo_offset);
int panthor_vm_active(struct panthor_vm *vm);
void panthor_vm_idle(struct panthor_vm *vm);
int panthor_vm_as(struct panthor_vm *vm);
int panthor_vm_flush_all(struct panthor_vm *vm);

struct panthor_heap_pool *
panthor_vm_get_heap_pool(struct panthor_vm *vm, bool create);
Expand Down
45 changes: 34 additions & 11 deletions drivers/gpu/drm/panthor/panthor_sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@ struct panthor_queue {
/** @seqno: Sequence number of the last initialized fence. */
atomic64_t seqno;

/**
* @last_fence: Fence of the last submitted job.
*
* We return this fence when we get an empty command stream.
* This way, we are guaranteed that all earlier jobs have completed
* when drm_sched_job::s_fence::finished without having to feed
* the CS ring buffer with a dummy job that only signals the fence.
*/
struct dma_fence *last_fence;

/**
* @in_flight_jobs: List containing all in-flight jobs.
*
Expand Down Expand Up @@ -829,6 +839,9 @@ static void group_free_queue(struct panthor_group *group, struct panthor_queue *
panthor_kernel_bo_destroy(queue->ringbuf);
panthor_kernel_bo_destroy(queue->iface.mem);

/* Release the last_fence we were holding, if any. */
dma_fence_put(queue->fence_ctx.last_fence);

kfree(queue);
}

Expand Down Expand Up @@ -2784,9 +2797,6 @@ static void group_sync_upd_work(struct work_struct *work)

spin_lock(&queue->fence_ctx.lock);
list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
if (!job->call_info.size)
continue;

if (syncobj->seqno < job->done_fence->seqno)
break;

Expand Down Expand Up @@ -2865,11 +2875,14 @@ queue_run_job(struct drm_sched_job *sched_job)
static_assert(sizeof(call_instrs) % 64 == 0,
"call_instrs is not aligned on a cacheline");

/* Stream size is zero, nothing to do => return a NULL fence and let
* drm_sched signal the parent.
/* Stream size is zero, nothing to do except making sure all previously
* submitted jobs are done before we signal the
* drm_sched_job::s_fence::finished fence.
*/
if (!job->call_info.size)
return NULL;
if (!job->call_info.size) {
job->done_fence = dma_fence_get(queue->fence_ctx.last_fence);
return dma_fence_get(job->done_fence);
}

ret = pm_runtime_resume_and_get(ptdev->base.dev);
if (drm_WARN_ON(&ptdev->base, ret))
Expand Down Expand Up @@ -2926,8 +2939,13 @@ queue_run_job(struct drm_sched_job *sched_job)
pm_runtime_get(ptdev->base.dev);
sched->pm.has_ref = true;
}
panthor_devfreq_record_busy(sched->ptdev);
}

/* Update the last fence. */
dma_fence_put(queue->fence_ctx.last_fence);
queue->fence_ctx.last_fence = dma_fence_get(job->done_fence);

done_fence = dma_fence_get(job->done_fence);

out_unlock:
Expand Down Expand Up @@ -3378,10 +3396,15 @@ panthor_job_create(struct panthor_file *pfile,
goto err_put_job;
}

job->done_fence = kzalloc(sizeof(*job->done_fence), GFP_KERNEL);
if (!job->done_fence) {
ret = -ENOMEM;
goto err_put_job;
/* Empty command streams don't need a fence, they'll pick the one from
* the previously submitted job.
*/
if (job->call_info.size) {
job->done_fence = kzalloc(sizeof(*job->done_fence), GFP_KERNEL);
if (!job->done_fence) {
ret = -ENOMEM;
goto err_put_job;
}
}

ret = drm_sched_job_init(&job->base,
Expand Down
Loading