Before this patch, cancelled waiters would only be cleaned up
once their threshold value was reached. Make host1x_intr_put_ref
process the cancellation immediately to fix this.

Signed-off-by: Mikko Perttunen <mperttu...@nvidia.com>
---
v5:
* Add parameter to flush, i.e. wait for all pending waiters to
  complete before returning. The reason this is not always true
  is that the pending waiter might be the place that is calling
  the put_ref.
---
 drivers/gpu/host1x/intr.c   | 23 +++++++++++++++++------
 drivers/gpu/host1x/intr.h   |  4 +++-
 drivers/gpu/host1x/syncpt.c |  2 +-
 3 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c
index 9245add23b5d..70e1096a4fe9 100644
--- a/drivers/gpu/host1x/intr.c
+++ b/drivers/gpu/host1x/intr.c
@@ -242,18 +242,29 @@ int host1x_intr_add_action(struct host1x *host, struct 
host1x_syncpt *syncpt,
        return 0;
 }
 
-void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref)
+void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref,
+                        bool flush)
 {
        struct host1x_waitlist *waiter = ref;
        struct host1x_syncpt *syncpt;
 
-       while (atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED) ==
-              WLS_REMOVED)
-               schedule();
+       atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED);
 
        syncpt = host->syncpt + id;
-       (void)process_wait_list(host, syncpt,
-                               host1x_syncpt_load(host->syncpt + id));
+
+       spin_lock(&syncpt->intr.lock);
+       if (atomic_cmpxchg(&waiter->state, WLS_CANCELLED, WLS_HANDLED) ==
+           WLS_CANCELLED) {
+               list_del(&waiter->list);
+               kref_put(&waiter->refcount, waiter_release);
+       }
+       spin_unlock(&syncpt->intr.lock);
+
+       if (flush) {
+               /* Wait until any concurrently executing handler has finished. 
*/
+               while (atomic_read(&waiter->state) != WLS_HANDLED)
+                       cpu_relax();
+       }
 
        kref_put(&waiter->refcount, waiter_release);
 }
diff --git a/drivers/gpu/host1x/intr.h b/drivers/gpu/host1x/intr.h
index aac38194398f..6ea55e615e3a 100644
--- a/drivers/gpu/host1x/intr.h
+++ b/drivers/gpu/host1x/intr.h
@@ -74,8 +74,10 @@ int host1x_intr_add_action(struct host1x *host, struct 
host1x_syncpt *syncpt,
  * Unreference an action submitted to host1x_intr_add_action().
  * You must call this if you passed non-NULL as ref.
  * @ref the ref returned from host1x_intr_add_action()
+ * @flush wait until any pending handlers have completed before returning.
  */
-void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref);
+void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref,
+                        bool flush);
 
 /* Initialize host1x sync point interrupt */
 int host1x_intr_init(struct host1x *host, unsigned int irq_sync);
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index 5982fdf64e1c..e48b4595cf53 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -293,7 +293,7 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 
thresh, long timeout,
                }
        }
 
-       host1x_intr_put_ref(sp->host, sp->id, ref);
+       host1x_intr_put_ref(sp->host, sp->id, ref, true);
 
 done:
        return err;
-- 
2.30.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to