gpu: host1x: Remove cancelled waiters immediately
authorMikko Perttunen <mperttunen@nvidia.com>
Mon, 29 Mar 2021 13:38:30 +0000 (16:38 +0300)
committerThierry Reding <treding@nvidia.com>
Tue, 30 Mar 2021 17:53:24 +0000 (19:53 +0200)
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 <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/host1x/intr.c
drivers/gpu/host1x/intr.h
drivers/gpu/host1x/syncpt.c

index 9245add23b5dd231a82ce26570ad7d66086d87a4..69b0e8e41466cba1a343cf78190d5b1131c71133 100644 (file)
@@ -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)
+                       schedule();
+       }
 
        kref_put(&waiter->refcount, waiter_release);
 }
index aac38194398fb0f2ecb2aa69c46ffa2349228e05..6ea55e615e3aed40c5af6ff95f2bf7e5a5530d51 100644 (file)
@@ -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);
index 9a113016d482c8480d8a620371c84375df2cf53f..f061dfd5bbc78ed188fd5583926b8f253a1dd64e 100644 (file)
@@ -308,7 +308,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;