vc4_job_handle_completed() drops and retakes job_lock around every job it
completes, so a batch of N finished jobs costs N + 1 acquisitions of a
lock the interrupt handler takes on every bin and render done. Each retake
can contend with the handler.

Splice job_done_list onto a local list under a single acquisition and
complete the jobs from there. Jobs finishing meanwhile requeue the done
work, which picks them up on its next run.

Signed-off-by: Maíra Canal <[email protected]>
---
 drivers/gpu/drm/vc4/vc4_gem.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index b65b3f62b098..b61f9b0a7c09 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -908,24 +908,19 @@ vc4_exec_put(struct vc4_exec_info *exec)
 void
 vc4_job_handle_completed(struct vc4_dev *vc4)
 {
-       unsigned long irqflags;
+       struct vc4_exec_info *exec, *next;
+       LIST_HEAD(done);
 
        if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
                return;
 
-       spin_lock_irqsave(&vc4->job_lock, irqflags);
-       while (!list_empty(&vc4->job_done_list)) {
-               struct vc4_exec_info *exec =
-                       list_first_entry(&vc4->job_done_list,
-                                        struct vc4_exec_info, head);
+       scoped_guard(spinlock_irqsave, &vc4->job_lock)
+               list_splice_init(&vc4->job_done_list, &done);
+
+       list_for_each_entry_safe(exec, next, &done, head) {
                list_del(&exec->head);
-
-               spin_unlock_irqrestore(&vc4->job_lock, irqflags);
                vc4_exec_put(exec);
-               spin_lock_irqsave(&vc4->job_lock, irqflags);
        }
-
-       spin_unlock_irqrestore(&vc4->job_lock, irqflags);
 }
 
 /* Scheduled when any job has been completed, this walks the list of

-- 
2.55.0

Reply via email to