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

Commit 24c42013 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Fix spinlock recursion issues"

parents 53bb20e6 b6c5beaa
Loading
Loading
Loading
Loading
+19 −40
Original line number Diff line number Diff line
@@ -14,8 +14,6 @@
#include "kgsl_timeline.h"
#include "kgsl_trace.h"

static DEFINE_SPINLOCK(fence_lock);

struct kgsl_timeline_fence {
	struct dma_fence base;
	struct kgsl_timeline *timeline;
@@ -152,6 +150,7 @@ static struct kgsl_timeline *kgsl_timeline_alloc(struct kgsl_device_private *dev
	trace_kgsl_timeline_alloc(id, initial);

	spin_lock_init(&timeline->lock);
	spin_lock_init(&timeline->fence_lock);

	kref_init(&timeline->ref);

@@ -170,8 +169,7 @@ static void timeline_fence_release(struct dma_fence *fence)
	struct kgsl_timeline_fence *cur, *temp;
	unsigned long flags;

	spin_lock_irqsave(&timeline->lock, flags);
	spin_lock(&fence_lock);
	spin_lock_irqsave(&timeline->fence_lock, flags);

	/* If the fence is still on the active list, remove it */
	list_for_each_entry_safe(cur, temp, &timeline->fences, node) {
@@ -181,8 +179,7 @@ static void timeline_fence_release(struct dma_fence *fence)
		list_del_init(&f->node);
		break;
	}
	spin_unlock(&fence_lock);
	spin_unlock_irqrestore(&timeline->lock, flags);
	spin_unlock_irqrestore(&timeline->fence_lock, flags);
	trace_kgsl_timeline_fence_release(f->timeline->id, fence->seqno);

	kgsl_timeline_put(f->timeline);
@@ -243,17 +240,17 @@ static void kgsl_timeline_add_fence(struct kgsl_timeline *timeline,
	struct kgsl_timeline_fence *entry;
	unsigned long flags;

	spin_lock_irqsave(&fence_lock, flags);
	spin_lock_irqsave(&timeline->fence_lock, flags);
	list_for_each_entry(entry, &timeline->fences, node) {
		if (fence->base.seqno < entry->base.seqno) {
			list_add_tail(&fence->node, &entry->node);
			spin_unlock_irqrestore(&fence_lock, flags);
			spin_unlock_irqrestore(&timeline->fence_lock, flags);
			return;
		}
	}

	list_add_tail(&fence->node, &timeline->fences);
	spin_unlock_irqrestore(&fence_lock, flags);
	spin_unlock_irqrestore(&timeline->fence_lock, flags);
}

void kgsl_timeline_signal(struct kgsl_timeline *timeline, u64 seqno)
@@ -272,22 +269,18 @@ void kgsl_timeline_signal(struct kgsl_timeline *timeline, u64 seqno)

	timeline->value = seqno;

	/* Copy the list out so we can walk it without holding the lock */
	spin_lock(&fence_lock);
	list_replace_init(&timeline->fences, &temp);
	spin_unlock(&fence_lock);

	list_for_each_entry_safe(fence, tmp, &temp, node) {
	spin_lock(&timeline->fence_lock);
	list_for_each_entry_safe(fence, tmp, &timeline->fences, node) {
		if (timeline_fence_signaled(&fence->base)) {
			list_del_init(&fence->node);
			dma_fence_signal_locked(&fence->base);
			dma_fence_get(&fence->base);
			list_move(&fence->node, &temp);
		}
	}
	spin_unlock(&timeline->fence_lock);

	/* Put the active fences back in the timeline list */
	list_for_each_entry_safe(fence, tmp, &temp, node) {
		list_del_init(&fence->node);
		kgsl_timeline_add_fence(timeline, fence);
		dma_fence_signal_locked(&fence->base);
		dma_fence_put(&fence->base);
	}

unlock:
@@ -553,33 +546,19 @@ long kgsl_ioctl_timeline_destroy(struct kgsl_device_private *dev_priv,

	INIT_LIST_HEAD(&temp);

	spin_lock_irq(&timeline->lock);

	/* Copy any still pending fences to a temporary list */
	spin_lock(&fence_lock);
	spin_lock(&timeline->fence_lock);
	list_for_each_entry_safe(fence, tmp, &timeline->fences, node)
		dma_fence_get(&fence->base);
	list_replace_init(&timeline->fences, &temp);
	spin_unlock(&fence_lock);
	spin_unlock(&timeline->fence_lock);

	/*
	 * Set an error on each still pending fence and signal
	 * them to release any callbacks. Hold the refcount
	 * to avoid fence getting destroyed during signaling.
	 */
	spin_lock_irq(&timeline->lock);
	list_for_each_entry_safe(fence, tmp, &temp, node) {
		dma_fence_get(&fence->base);
		dma_fence_set_error(&fence->base, -ENOENT);
		dma_fence_signal_locked(&fence->base);
	}
	spin_unlock_irq(&timeline->lock);

	/*
	 * Put the fence refcount taken above outside lock
	 * to avoid spinlock recursion during fence release.
	 */
	list_for_each_entry_safe(fence, tmp, &temp, node) {
		list_del_init(&fence->node);
		dma_fence_put(&fence->base);
	}
	spin_unlock_irq(&timeline->lock);

	kgsl_timeline_put(timeline);

+3 −1
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@ struct kgsl_timeline {
	int id;
	/** @value: Current value of the timeline */
	u64 value;
	/** @lock: Lock to protect @fences */
	/** @fence_lock: Lock to protect @fences */
	spinlock_t fence_lock;
	/** @lock: Lock to use for locking each fence in @fences */
	spinlock_t lock;
	/** @ref: Reference count for the struct */
	struct kref ref;