Commit ecfb888a authored by Mikko Perttunen's avatar Mikko Perttunen Committed by Thierry Reding
Browse files

gpu: host1x: Remove cancelled waiters immediately



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: default avatarMikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 49a5fb16
Loading
Loading
Loading
Loading
+17 −6
Original line number Diff line number Diff line
@@ -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);
}
+3 −1
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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;