165 lines
4.8 KiB
Diff
165 lines
4.8 KiB
Diff
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
|
|
index 350ad08..44f981c 100644
|
|
--- a/drivers/gpu/msm/kgsl.c
|
|
+++ b/drivers/gpu/msm/kgsl.c
|
|
@@ -1609,6 +1609,7 @@
|
|
struct kgsl_device *device;
|
|
struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data;
|
|
struct kgsl_cmdbatch_sync_event *event;
|
|
+ unsigned long flags;
|
|
|
|
if (cmdbatch == NULL || cmdbatch->context == NULL)
|
|
return;
|
|
@@ -1623,14 +1624,14 @@
|
|
kgsl_context_dump(cmdbatch->context);
|
|
clear_bit(CMDBATCH_FLAG_FENCE_LOG, &cmdbatch->priv);
|
|
|
|
- spin_lock(&cmdbatch->lock);
|
|
+ spin_lock_irqsave(&cmdbatch->lock, flags);
|
|
/* Print all the fences */
|
|
list_for_each_entry(event, &cmdbatch->synclist, node) {
|
|
if (KGSL_CMD_SYNCPOINT_TYPE_FENCE == event->type &&
|
|
event->handle && event->handle->fence)
|
|
kgsl_sync_fence_log(event->handle->fence);
|
|
}
|
|
- spin_unlock(&cmdbatch->lock);
|
|
+ spin_unlock_irqrestore(&cmdbatch->lock, flags);
|
|
dev_err(device->dev, "--gpu syncpoint deadlock print end--\n");
|
|
}
|
|
/**
|
|
@@ -1685,15 +1686,16 @@
|
|
struct kgsl_cmdbatch_sync_event *event)
|
|
{
|
|
struct kgsl_cmdbatch_sync_event *e, *tmp;
|
|
+ unsigned long flags;
|
|
int sched = 0;
|
|
int removed = 0;
|
|
|
|
/*
|
|
- * We may have cmdbatch timer running, which also uses same lock,
|
|
- * take a lock with software interrupt disabled (bh) to avoid
|
|
- * spin lock recursion.
|
|
+ * cmdbatch timer or event callback might run at
|
|
+ * this time in interrupt context and uses same lock.
|
|
+ * So use irq-save version of spin lock.
|
|
*/
|
|
- spin_lock_bh(&event->cmdbatch->lock);
|
|
+ spin_lock_irqsave(&event->cmdbatch->lock, flags);
|
|
|
|
/*
|
|
* sync events that are contained by a cmdbatch which has been
|
|
@@ -1708,8 +1710,9 @@
|
|
}
|
|
}
|
|
|
|
+ event->handle = NULL;
|
|
sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
|
|
- spin_unlock_bh(&event->cmdbatch->lock);
|
|
+ spin_unlock_irqrestore(&event->cmdbatch->lock, flags);
|
|
|
|
/* If the list is empty delete the canary timer */
|
|
if (sched)
|
|
@@ -1771,16 +1774,20 @@
|
|
struct kgsl_cmdbatch_sync_event *event, *tmpsync;
|
|
LIST_HEAD(cancel_synclist);
|
|
int sched = 0;
|
|
+ unsigned long flags;
|
|
|
|
/* Zap the canary timer */
|
|
del_timer_sync(&cmdbatch->timer);
|
|
|
|
- /* non-bh because we just destroyed timer */
|
|
- spin_lock(&cmdbatch->lock);
|
|
+ /*
|
|
+ * callback might run in interrupt context
|
|
+ * so need to use irqsave version of spinlocks.
|
|
+ */
|
|
+ spin_lock_irqsave(&cmdbatch->lock, flags);
|
|
|
|
/* Empty the synclist before canceling events */
|
|
list_splice_init(&cmdbatch->synclist, &cancel_synclist);
|
|
- spin_unlock(&cmdbatch->lock);
|
|
+ spin_unlock_irqrestore(&cmdbatch->lock, flags);
|
|
|
|
/*
|
|
* Finish canceling events outside the cmdbatch spinlock and
|
|
@@ -1802,8 +1809,15 @@
|
|
kgsl_cmdbatch_sync_func, event);
|
|
} else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
|
|
/* Put events that are successfully canceled */
|
|
- if (kgsl_sync_fence_async_cancel(event->handle))
|
|
+ spin_lock_irqsave(&cmdbatch->lock, flags);
|
|
+
|
|
+ if (kgsl_sync_fence_async_cancel(event->handle)) {
|
|
+ event->handle = NULL;
|
|
+ spin_unlock_irqrestore(&cmdbatch->lock, flags);
|
|
kgsl_cmdbatch_sync_event_put(event);
|
|
+ } else {
|
|
+ spin_unlock_irqrestore(&cmdbatch->lock, flags);
|
|
+ }
|
|
}
|
|
|
|
/* Put events that have been removed from the synclist */
|
|
@@ -1864,6 +1878,7 @@
|
|
{
|
|
struct kgsl_cmd_syncpoint_fence *sync = priv;
|
|
struct kgsl_cmdbatch_sync_event *event;
|
|
+ unsigned long flags;
|
|
|
|
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
|
|
|
@@ -1892,11 +1907,6 @@
|
|
|
|
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);
|
|
-
|
|
/*
|
|
* Increment the reference count for the async callback.
|
|
* Decrement when the callback is successfully canceled, when
|
|
@@ -1904,6 +1914,10 @@
|
|
*/
|
|
|
|
kref_get(&event->refcount);
|
|
+
|
|
+ spin_lock_irqsave(&cmdbatch->lock, flags);
|
|
+ list_add(&event->node, &cmdbatch->synclist);
|
|
+
|
|
event->handle = kgsl_sync_fence_async_wait(sync->fd,
|
|
kgsl_cmdbatch_sync_fence_func, event);
|
|
|
|
@@ -1911,17 +1925,14 @@
|
|
int ret = PTR_ERR(event->handle);
|
|
|
|
event->handle = NULL;
|
|
-
|
|
- /* Failed to add the event to the async callback */
|
|
- kgsl_cmdbatch_sync_event_put(event);
|
|
-
|
|
/* Remove event from the synclist */
|
|
- spin_lock(&cmdbatch->lock);
|
|
list_del(&event->node);
|
|
- spin_unlock(&cmdbatch->lock);
|
|
+ spin_unlock_irqrestore(&cmdbatch->lock, flags);
|
|
+ /* Put for event removal from the synclist */
|
|
kgsl_cmdbatch_sync_event_put(event);
|
|
-
|
|
- /* Event no longer needed by this function */
|
|
+ /* Unable to add event to the async callback so a put */
|
|
+ kgsl_cmdbatch_sync_event_put(event);
|
|
+ /* Put since event no longer needed by this function */
|
|
kgsl_cmdbatch_sync_event_put(event);
|
|
|
|
/*
|
|
@@ -1935,6 +1946,7 @@
|
|
}
|
|
|
|
trace_syncpoint_fence(cmdbatch, event->handle->name);
|
|
+ spin_unlock_irqrestore(&cmdbatch->lock, flags);
|
|
|
|
/*
|
|
* Event was successfully added to the synclist, the async
|