summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/msm/kgsl_drawobj.c43
1 files changed, 27 insertions, 16 deletions
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c
index fba18231cb72..4e3788b4fed6 100644
--- a/drivers/gpu/msm/kgsl_drawobj.c
+++ b/drivers/gpu/msm/kgsl_drawobj.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017,2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -173,8 +173,11 @@ static void syncobj_timer(unsigned long data)
/*
* a generic function to retire a pending sync event and (possibly)
* kick the dispatcher
+ * Returns false if the event was already marked for cancellation in another
+ * thread. This function should return true if this thread is responsible for
+ * freeing up the memory, and the event will not be cancelled.
*/
-static void drawobj_sync_expire(struct kgsl_device *device,
+static bool drawobj_sync_expire(struct kgsl_device *device,
struct kgsl_drawobj_sync_event *event)
{
struct kgsl_drawobj_sync *syncobj = event->syncobj;
@@ -183,7 +186,7 @@ static void drawobj_sync_expire(struct kgsl_device *device,
* leave without doing anything useful
*/
if (!test_and_clear_bit(event->id, &syncobj->pending))
- return;
+ return false;
/*
* If no more pending events, delete the timer and schedule the command
@@ -196,6 +199,7 @@ static void drawobj_sync_expire(struct kgsl_device *device,
device->ftbl->drawctxt_sched(device,
event->syncobj->base.context);
}
+ return true;
}
/*
@@ -210,8 +214,13 @@ static void drawobj_sync_func(struct kgsl_device *device,
trace_syncpoint_timestamp_expire(event->syncobj,
event->context, event->timestamp);
- drawobj_sync_expire(device, event);
- kgsl_context_put(event->context);
+ /*
+ * Put down the context ref count only if
+ * this thread successfully clears the pending bit mask.
+ */
+ if (drawobj_sync_expire(device, event))
+ kgsl_context_put(event->context);
+
drawobj_put(&event->syncobj->base);
}
@@ -241,28 +250,25 @@ static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj)
static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
{
struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
- unsigned long pending, flags;
+ unsigned long flags;
unsigned int i;
/* Zap the canary timer */
del_timer_sync(&syncobj->timer);
/*
- * Copy off the pending list and clear all pending events - this will
- * render any subsequent asynchronous callback harmless
- */
- bitmap_copy(&pending, &syncobj->pending, KGSL_MAX_SYNCPOINTS);
- bitmap_zero(&syncobj->pending, KGSL_MAX_SYNCPOINTS);
-
- /*
* Clear all pending events - this will render any subsequent async
* callbacks harmless
*/
for (i = 0; i < syncobj->numsyncs; i++) {
struct kgsl_drawobj_sync_event *event = &syncobj->synclist[i];
- /* Don't do anything if the event has already expired */
- if (!test_bit(i, &pending))
+ /*
+ * Don't do anything if the event has already expired.
+ * If this thread clears the pending bit mask then it is
+ * responsible for doing context put.
+ */
+ if (!test_and_clear_bit(i, &syncobj->pending))
continue;
switch (event->type) {
@@ -270,6 +276,11 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
kgsl_cancel_event(drawobj->device,
&event->context->events, event->timestamp,
drawobj_sync_func, event);
+ /*
+ * Do context put here to make sure the context is alive
+ * till this thread cancels kgsl event.
+ */
+ kgsl_context_put(event->context);
break;
case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
spin_lock_irqsave(&event->handle_lock, flags);
@@ -291,7 +302,7 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
* If we cancelled an event, there's a good chance that the context is
* on a dispatcher queue, so schedule to get it removed.
*/
- if (!bitmap_empty(&pending, KGSL_MAX_SYNCPOINTS) &&
+ if (!bitmap_empty(&syncobj->pending, KGSL_MAX_SYNCPOINTS) &&
drawobj->device->ftbl->drawctxt_sched)
drawobj->device->ftbl->drawctxt_sched(drawobj->device,
drawobj->context);