Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Mikko Perttunen and committed by
Thierry Reding
ecfb888a 49a5fb16

+21 -8
+17 -6
drivers/gpu/host1x/intr.c
··· 242 242 return 0; 243 243 } 244 244 245 - void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref) 245 + void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref, 246 + bool flush) 246 247 { 247 248 struct host1x_waitlist *waiter = ref; 248 249 struct host1x_syncpt *syncpt; 249 250 250 - while (atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED) == 251 - WLS_REMOVED) 252 - schedule(); 251 + atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED); 253 252 254 253 syncpt = host->syncpt + id; 255 - (void)process_wait_list(host, syncpt, 256 - host1x_syncpt_load(host->syncpt + id)); 254 + 255 + spin_lock(&syncpt->intr.lock); 256 + if (atomic_cmpxchg(&waiter->state, WLS_CANCELLED, WLS_HANDLED) == 257 + WLS_CANCELLED) { 258 + list_del(&waiter->list); 259 + kref_put(&waiter->refcount, waiter_release); 260 + } 261 + spin_unlock(&syncpt->intr.lock); 262 + 263 + if (flush) { 264 + /* Wait until any concurrently executing handler has finished. */ 265 + while (atomic_read(&waiter->state) != WLS_HANDLED) 266 + schedule(); 267 + } 257 268 258 269 kref_put(&waiter->refcount, waiter_release); 259 270 }
+3 -1
drivers/gpu/host1x/intr.h
··· 74 74 * Unreference an action submitted to host1x_intr_add_action(). 75 75 * You must call this if you passed non-NULL as ref. 76 76 * @ref the ref returned from host1x_intr_add_action() 77 + * @flush wait until any pending handlers have completed before returning. 77 78 */ 78 - void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref); 79 + void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref, 80 + bool flush); 79 81 80 82 /* Initialize host1x sync point interrupt */ 81 83 int host1x_intr_init(struct host1x *host, unsigned int irq_sync);
+1 -1
drivers/gpu/host1x/syncpt.c
··· 308 308 } 309 309 } 310 310 311 - host1x_intr_put_ref(sp->host, sp->id, ref); 311 + host1x_intr_put_ref(sp->host, sp->id, ref, true); 312 312 313 313 done: 314 314 return err;