165 lines
4.8 KiB
Diff
Raw Normal View History

2017-11-25 19:39:02 -05:00
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