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

Commit 5eeeb523 authored by Prakash Kamliya's avatar Prakash Kamliya Committed by Gerrit - the friendly Code Review server
Browse files

msm: kgsl: Use spin_lock_bh to avoid spinlock recursion



A sync fence timeout may lead to call adreno_drawctxt_dump()
for drawctxt sync pt dump, at the same time, its quite possible
that the cmdbatch timer expires on the *same* CPU, this will
also lead to call adreno_drawctx_dump(). This result into spin
lock recursion. Use spin_lock_bh instead of spin_lock to disable
soft irq (timer) while we are dumping the sync pt information.

Along with this change, few _irq are replaced with _bh, which
is enough to disable soft irq (timers).

Change-Id: I0d56601b81ded7c4821e2d9a837fb9e6b121ea8a
Signed-off-by: default avatarPrakash Kamliya <pkamliya@codeaurora.org>
parent 0bb9093c
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -112,10 +112,14 @@ static void print_flags(struct seq_file *s, const struct flag_entry *table,
static void cmdbatch_print(struct seq_file *s, struct kgsl_cmdbatch *cmdbatch)
{
	struct kgsl_cmdbatch_sync_event *sync_event;
	unsigned long flags;

	/* print fences first, since they block this cmdbatch */
	spin_lock_irqsave(&cmdbatch->lock, flags);
	/*
	 * print fences first, since they block this cmdbatch.
	 * We may have cmdbatch timer running, which also uses
	 * same lock, take a lock with software interrupt disabled (bh)
	 * to avoid spin lock recursion.
	 */
	spin_lock_bh(&cmdbatch->lock);

	list_for_each_entry(sync_event, &cmdbatch->synclist, node) {
		/*
@@ -128,7 +132,7 @@ static void cmdbatch_print(struct seq_file *s, struct kgsl_cmdbatch *cmdbatch)
		seq_puts(s, "\n");
	}

	spin_unlock_irqrestore(&cmdbatch->lock, flags);
	spin_unlock_bh(&cmdbatch->lock);

	/* if this flag is set, there won't be an IB */
	if (cmdbatch->flags & KGSL_CONTEXT_SYNC)
+7 −3
Original line number Diff line number Diff line
@@ -293,7 +293,6 @@ static struct kgsl_cmdbatch *_get_cmdbatch(struct adreno_context *drawctxt)
{
	struct kgsl_cmdbatch *cmdbatch = NULL;
	bool pending = false;
	unsigned long flags;

	if (drawctxt->cmdqueue_head == drawctxt->cmdqueue_tail)
		return NULL;
@@ -323,10 +322,15 @@ static struct kgsl_cmdbatch *_get_cmdbatch(struct adreno_context *drawctxt)
			pending = true;
	}

	spin_lock_irqsave(&cmdbatch->lock, flags);
	/*
	 * We may have cmdbatch timer running, which also uses same lock,
	 * take a lock with software interrupt disabled (bh) to avoid
	 * spin lock recursion.
	 */
	spin_lock_bh(&cmdbatch->lock);
	if (!list_empty(&cmdbatch->synclist))
		pending = true;
	spin_unlock_irqrestore(&cmdbatch->lock, flags);
	spin_unlock_bh(&cmdbatch->lock);

	/*
	 * If changes are pending and the canary timer hasn't been
+7 −2
Original line number Diff line number Diff line
@@ -84,7 +84,12 @@ void adreno_drawctxt_dump(struct kgsl_device *device,
			goto stats;
		}

		spin_lock(&cmdbatch->lock);
		/*
		 * We may have cmdbatch timer running, which also uses same
		 * lock, take a lock with software interrupt disabled (bh)
		 * to avoid spin lock recursion.
		 */
		spin_lock_bh(&cmdbatch->lock);

		if (!list_empty(&cmdbatch->synclist)) {
			dev_err(device->dev,
@@ -93,7 +98,7 @@ void adreno_drawctxt_dump(struct kgsl_device *device,

			kgsl_dump_syncpoints(device, cmdbatch);
		}
		spin_unlock(&cmdbatch->lock);
		spin_unlock_bh(&cmdbatch->lock);
	}

stats:
+16 −8
Original line number Diff line number Diff line
@@ -1600,6 +1600,7 @@ static void _kgsl_cmdbatch_timer(unsigned long data)
	if (cmdbatch == NULL || cmdbatch->context == NULL)
		return;

	/* We are in timer context, this can be non-bh */
	spin_lock(&cmdbatch->lock);
	if (list_empty(&cmdbatch->synclist))
		goto done;
@@ -1697,9 +1698,13 @@ static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
	struct kgsl_cmdbatch_sync_event *e, *tmp;
	int sched = 0;
	int removed = 0;
	unsigned long flags;

	spin_lock_irqsave(&event->cmdbatch->lock, flags);
	/*
	 * We may have cmdbatch timer running, which also uses same lock,
	 * take a lock with software interrupt disabled (bh) to avoid
	 * spin lock recursion.
	 */
	spin_lock_bh(&event->cmdbatch->lock);

	/*
	 * sync events that are contained by a cmdbatch which has been
@@ -1715,7 +1720,7 @@ static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
	}

	sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
	spin_unlock_irqrestore(&event->cmdbatch->lock, flags);
	spin_unlock_bh(&event->cmdbatch->lock);

	/* If the list is empty delete the canary timer */
	if (sched)
@@ -1781,6 +1786,7 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
	/* Zap the canary timer */
	del_timer_sync(&cmdbatch->timer);

	/* non-bh because we just destroyed timer */
	spin_lock(&cmdbatch->lock);

	/* Empty the synclist before canceling events */
@@ -1869,7 +1875,6 @@ static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
{
	struct kgsl_cmd_syncpoint_fence *sync = priv;
	struct kgsl_cmdbatch_sync_event *event;
	unsigned long flags;

	event = kzalloc(sizeof(*event), GFP_KERNEL);

@@ -1897,9 +1902,11 @@ static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
	 */

	kref_get(&event->refcount);
	spin_lock_irqsave(&cmdbatch->lock, flags);

	/* non-bh because, we haven't started cmdbatch timer yet */
	spin_lock(&cmdbatch->lock);
	list_add(&event->node, &cmdbatch->synclist);
	spin_unlock_irqrestore(&cmdbatch->lock, flags);
	spin_unlock(&cmdbatch->lock);

	/*
	 * Increment the reference count for the async callback.
@@ -1920,9 +1927,9 @@ static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
		kgsl_cmdbatch_sync_event_put(event);

		/* Remove event from the synclist */
		spin_lock_irqsave(&cmdbatch->lock, flags);
		spin_lock(&cmdbatch->lock);
		list_del(&event->node);
		spin_unlock_irqrestore(&cmdbatch->lock, flags);
		spin_unlock(&cmdbatch->lock);
		kgsl_cmdbatch_sync_event_put(event);

		/* Event no longer needed by this function */
@@ -2013,6 +2020,7 @@ static int kgsl_cmdbatch_add_sync_timestamp(struct kgsl_device *device,
	kref_init(&event->refcount);
	kref_get(&event->refcount);

	/* non-bh because, we haven't started cmdbatch timer yet */
	spin_lock(&cmdbatch->lock);
	list_add(&event->node, &cmdbatch->synclist);
	spin_unlock(&cmdbatch->lock);