Merge "msm: kgsl: Fix spinlock recursion issues"
This commit is contained in:
commit
24c4201353
@ -14,8 +14,6 @@
|
|||||||
#include "kgsl_timeline.h"
|
#include "kgsl_timeline.h"
|
||||||
#include "kgsl_trace.h"
|
#include "kgsl_trace.h"
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(fence_lock);
|
|
||||||
|
|
||||||
struct kgsl_timeline_fence {
|
struct kgsl_timeline_fence {
|
||||||
struct dma_fence base;
|
struct dma_fence base;
|
||||||
struct kgsl_timeline *timeline;
|
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);
|
trace_kgsl_timeline_alloc(id, initial);
|
||||||
|
|
||||||
spin_lock_init(&timeline->lock);
|
spin_lock_init(&timeline->lock);
|
||||||
|
spin_lock_init(&timeline->fence_lock);
|
||||||
|
|
||||||
kref_init(&timeline->ref);
|
kref_init(&timeline->ref);
|
||||||
|
|
||||||
@ -170,8 +169,7 @@ static void timeline_fence_release(struct dma_fence *fence)
|
|||||||
struct kgsl_timeline_fence *cur, *temp;
|
struct kgsl_timeline_fence *cur, *temp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&timeline->lock, flags);
|
spin_lock_irqsave(&timeline->fence_lock, flags);
|
||||||
spin_lock(&fence_lock);
|
|
||||||
|
|
||||||
/* If the fence is still on the active list, remove it */
|
/* If the fence is still on the active list, remove it */
|
||||||
list_for_each_entry_safe(cur, temp, &timeline->fences, node) {
|
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);
|
list_del_init(&f->node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock(&fence_lock);
|
spin_unlock_irqrestore(&timeline->fence_lock, flags);
|
||||||
spin_unlock_irqrestore(&timeline->lock, flags);
|
|
||||||
trace_kgsl_timeline_fence_release(f->timeline->id, fence->seqno);
|
trace_kgsl_timeline_fence_release(f->timeline->id, fence->seqno);
|
||||||
|
|
||||||
kgsl_timeline_put(f->timeline);
|
kgsl_timeline_put(f->timeline);
|
||||||
@ -243,17 +240,17 @@ static void kgsl_timeline_add_fence(struct kgsl_timeline *timeline,
|
|||||||
struct kgsl_timeline_fence *entry;
|
struct kgsl_timeline_fence *entry;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&fence_lock, flags);
|
spin_lock_irqsave(&timeline->fence_lock, flags);
|
||||||
list_for_each_entry(entry, &timeline->fences, node) {
|
list_for_each_entry(entry, &timeline->fences, node) {
|
||||||
if (fence->base.seqno < entry->base.seqno) {
|
if (fence->base.seqno < entry->base.seqno) {
|
||||||
list_add_tail(&fence->node, &entry->node);
|
list_add_tail(&fence->node, &entry->node);
|
||||||
spin_unlock_irqrestore(&fence_lock, flags);
|
spin_unlock_irqrestore(&timeline->fence_lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&fence->node, &timeline->fences);
|
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)
|
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;
|
timeline->value = seqno;
|
||||||
|
|
||||||
/* Copy the list out so we can walk it without holding the lock */
|
spin_lock(&timeline->fence_lock);
|
||||||
spin_lock(&fence_lock);
|
list_for_each_entry_safe(fence, tmp, &timeline->fences, node) {
|
||||||
list_replace_init(&timeline->fences, &temp);
|
|
||||||
spin_unlock(&fence_lock);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(fence, tmp, &temp, node) {
|
|
||||||
if (timeline_fence_signaled(&fence->base)) {
|
if (timeline_fence_signaled(&fence->base)) {
|
||||||
list_del_init(&fence->node);
|
dma_fence_get(&fence->base);
|
||||||
dma_fence_signal_locked(&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_for_each_entry_safe(fence, tmp, &temp, node) {
|
||||||
list_del_init(&fence->node);
|
dma_fence_signal_locked(&fence->base);
|
||||||
kgsl_timeline_add_fence(timeline, fence);
|
dma_fence_put(&fence->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
@ -553,33 +546,19 @@ long kgsl_ioctl_timeline_destroy(struct kgsl_device_private *dev_priv,
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&temp);
|
INIT_LIST_HEAD(&temp);
|
||||||
|
|
||||||
spin_lock_irq(&timeline->lock);
|
spin_lock(&timeline->fence_lock);
|
||||||
|
list_for_each_entry_safe(fence, tmp, &timeline->fences, node)
|
||||||
/* Copy any still pending fences to a temporary list */
|
|
||||||
spin_lock(&fence_lock);
|
|
||||||
list_replace_init(&timeline->fences, &temp);
|
|
||||||
spin_unlock(&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.
|
|
||||||
*/
|
|
||||||
list_for_each_entry_safe(fence, tmp, &temp, node) {
|
|
||||||
dma_fence_get(&fence->base);
|
dma_fence_get(&fence->base);
|
||||||
|
list_replace_init(&timeline->fences, &temp);
|
||||||
|
spin_unlock(&timeline->fence_lock);
|
||||||
|
|
||||||
|
spin_lock_irq(&timeline->lock);
|
||||||
|
list_for_each_entry_safe(fence, tmp, &temp, node) {
|
||||||
dma_fence_set_error(&fence->base, -ENOENT);
|
dma_fence_set_error(&fence->base, -ENOENT);
|
||||||
dma_fence_signal_locked(&fence->base);
|
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);
|
dma_fence_put(&fence->base);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irq(&timeline->lock);
|
||||||
|
|
||||||
kgsl_timeline_put(timeline);
|
kgsl_timeline_put(timeline);
|
||||||
|
|
||||||
|
@ -16,7 +16,9 @@ struct kgsl_timeline {
|
|||||||
int id;
|
int id;
|
||||||
/** @value: Current value of the timeline */
|
/** @value: Current value of the timeline */
|
||||||
u64 value;
|
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;
|
spinlock_t lock;
|
||||||
/** @ref: Reference count for the struct */
|
/** @ref: Reference count for the struct */
|
||||||
struct kref ref;
|
struct kref ref;
|
||||||
|
Loading…
Reference in New Issue
Block a user