vc4_v3d_get_bin_slot() waits for a render job to retire when every binner
slot is in use, and the wait has no timeout. That suits its caller in
vc4_validate.c, which runs in a user task and already handles -EINTR and
-ERESTARTSYS, but vc4_overflow_mem_work() calls it from a kworker, where
an interruptible wait cannot be broken by a signal.

vc4_reset() cannot get past that. It reaches cancel_work_sync() through
vc4_irq_disable() before it calls vc4_irq_reset(), and
vc4_irq_finish_render_job() is the only place that advances
finished_seqno and wakes the queue. Once the render job being waited on is
itself hung, the work never returns, cancel_work_sync() never completes,
and the reset that would have freed the job never runs.

Pass the timeout in from the caller and give the overflow work a second.
vc4_overflow_mem_work() already handles a failed allocation by leaving the
binner stalled for the hangcheck to reset, and that reset now completes.

Assisted-by: Claude:claude-opus-5
Fixes: 553c942f8b2c ("drm/vc4: Allow using more than 256MB of CMA memory.")
Signed-off-by: Maíra Canal <[email protected]>
---
 drivers/gpu/drm/vc4/vc4_drv.h      | 2 +-
 drivers/gpu/drm/vc4/vc4_irq.c      | 4 +++-
 drivers/gpu/drm/vc4/vc4_v3d.c      | 4 ++--
 drivers/gpu/drm/vc4/vc4_validate.c | 2 +-
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 86e0e7c12901..35b9b574671b 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -1053,7 +1053,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
 /* vc4_v3d.c */
 extern struct platform_driver vc4_v3d_driver;
 extern const struct of_device_id vc4_v3d_dt_match[];
-int vc4_v3d_get_bin_slot(struct vc4_dev *vc4);
+int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, uint64_t timeout_ns);
 int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used);
 void vc4_v3d_bin_bo_put(struct vc4_dev *vc4);
 int vc4_v3d_pm_get(struct vc4_dev *vc4);
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 90c5194a1c93..95b1a8ad848b 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -57,6 +57,8 @@
                         V3D_INT_FLDONE | \
                         V3D_INT_FRDONE)
 
+#define VC4_OVERFLOW_SLOT_TIMEOUT_NS   NSEC_PER_SEC
+
 static void
 vc4_overflow_mem_work(struct work_struct *work)
 {
@@ -74,7 +76,7 @@ vc4_overflow_mem_work(struct work_struct *work)
 
        bo = vc4->bin_bo;
 
-       bin_bo_slot = vc4_v3d_get_bin_slot(vc4);
+       bin_bo_slot = vc4_v3d_get_bin_slot(vc4, VC4_OVERFLOW_SLOT_TIMEOUT_NS);
        if (bin_bo_slot < 0) {
                drm_err(&vc4->base, "Couldn't allocate binner overflow mem\n");
                goto complete;
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index d2da8d2f8eeb..b943a003bcbc 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -152,7 +152,7 @@ void vc4_v3d_init_hw(struct drm_device *dev)
        V3D_WRITE(V3D_VPMBASE, 0);
 }
 
-int vc4_v3d_get_bin_slot(struct vc4_dev *vc4)
+int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, uint64_t timeout_ns)
 {
        struct drm_device *dev = &vc4->base;
        unsigned long irqflags;
@@ -183,7 +183,7 @@ int vc4_v3d_get_bin_slot(struct vc4_dev *vc4)
        spin_unlock_irqrestore(&vc4->job_lock, irqflags);
 
        if (seqno) {
-               int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true);
+               int ret = vc4_wait_for_seqno(dev, seqno, timeout_ns, true);
 
                if (ret == 0)
                        goto try_again;
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c 
b/drivers/gpu/drm/vc4/vc4_validate.c
index 7f2fadfde7a8..a7add99a65a2 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -385,7 +385,7 @@ validate_tile_binning_config(VALIDATE_ARGS)
                return -EINVAL;
        }
 
-       bin_slot = vc4_v3d_get_bin_slot(vc4);
+       bin_slot = vc4_v3d_get_bin_slot(vc4, ~0ull);
        if (bin_slot < 0) {
                if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
                        drm_err(dev, "Failed to allocate binner memory: %d\n",

-- 
2.55.0

Reply via email to