Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3d94ed0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Fix race condition between drawobj and context destroy"

parents 0f6eb98b bf34371a
Loading
Loading
Loading
Loading
+27 −16
Original line number Original line Diff line number Diff line
/* 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
 * 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
 * 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)
 * a generic function to retire a pending sync event and (possibly)
 * kick the dispatcher
 * 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_event *event)
{
{
	struct kgsl_drawobj_sync *syncobj = event->syncobj;
	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
	 * leave without doing anything useful
	 */
	 */
	if (!test_and_clear_bit(event->id, &syncobj->pending))
	if (!test_and_clear_bit(event->id, &syncobj->pending))
		return;
		return false;


	/*
	/*
	 * If no more pending events, delete the timer and schedule the command
	 * 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,
			device->ftbl->drawctxt_sched(device,
				event->syncobj->base.context);
				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,
	trace_syncpoint_timestamp_expire(event->syncobj,
		event->context, event->timestamp);
		event->context, event->timestamp);


	drawobj_sync_expire(device, event);
	/*
	 * 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);
		kgsl_context_put(event->context);

	drawobj_put(&event->syncobj->base);
	drawobj_put(&event->syncobj->base);
}
}


@@ -241,19 +250,12 @@ static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj)
static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
{
{
	struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
	struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
	unsigned long pending, flags;
	unsigned long flags;
	unsigned int i;
	unsigned int i;


	/* Zap the canary timer */
	/* Zap the canary timer */
	del_timer_sync(&syncobj->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
	 * Clear all pending events - this will render any subsequent async
	 * callbacks harmless
	 * callbacks harmless
@@ -261,8 +263,12 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
	for (i = 0; i < syncobj->numsyncs; i++) {
	for (i = 0; i < syncobj->numsyncs; i++) {
		struct kgsl_drawobj_sync_event *event = &syncobj->synclist[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;
			continue;


		switch (event->type) {
		switch (event->type) {
@@ -270,6 +276,11 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
			kgsl_cancel_event(drawobj->device,
			kgsl_cancel_event(drawobj->device,
				&event->context->events, event->timestamp,
				&event->context->events, event->timestamp,
				drawobj_sync_func, event);
				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;
			break;
		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
			spin_lock_irqsave(&event->handle_lock, flags);
			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
	 * If we cancelled an event, there's a good chance that the context is
	 * on a dispatcher queue, so schedule to get it removed.
	 * 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->ftbl->drawctxt_sched(drawobj->device,
		drawobj->device->ftbl->drawctxt_sched(drawobj->device,
							drawobj->context);
							drawobj->context);