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