diff --git a/drivers/soc/qcom/hgsl/hgsl.c b/drivers/soc/qcom/hgsl/hgsl.c index 2cf0bfc23e69..ee15aaf9fb69 100644 --- a/drivers/soc/qcom/hgsl/hgsl.c +++ b/drivers/soc/qcom/hgsl/hgsl.c @@ -1297,6 +1297,8 @@ static int hgsl_release(struct inode *inodep, struct file *filep) } } + hgsl_isync_fini(priv); + kfree(priv); return 0; } diff --git a/drivers/soc/qcom/hgsl/hgsl.h b/drivers/soc/qcom/hgsl/hgsl.h index e15f9b8acc5e..d99b6587914f 100644 --- a/drivers/soc/qcom/hgsl/hgsl.h +++ b/drivers/soc/qcom/hgsl/hgsl.h @@ -95,6 +95,7 @@ struct hgsl_hsync_fence { struct hgsl_isync_timeline { struct kref kref; + struct list_head free_list; char name[HGSL_TIMELINE_NAME_LEN]; int id; struct hgsl_priv *priv; @@ -126,6 +127,7 @@ void hgsl_hsync_timeline_put(struct hgsl_hsync_timeline *timeline); int hgsl_isync_timeline_create(struct hgsl_priv *priv, uint32_t *timeline_id); int hgsl_isync_timeline_destroy(struct hgsl_priv *priv, uint32_t id); +void hgsl_isync_fini(struct hgsl_priv *priv); int hgsl_isync_fence_create(struct hgsl_priv *priv, uint32_t timeline_id, uint32_t ts, int *fence); int hgsl_isync_fence_signal(struct hgsl_priv *priv, uint32_t timeline_id, diff --git a/drivers/soc/qcom/hgsl/hgsl_sync.c b/drivers/soc/qcom/hgsl/hgsl_sync.c index 6549c0829b40..cc610922e4b8 100644 --- a/drivers/soc/qcom/hgsl/hgsl_sync.c +++ b/drivers/soc/qcom/hgsl/hgsl_sync.c @@ -231,12 +231,12 @@ hgsl_isync_timeline_get(struct hgsl_priv *priv, int id) struct hgsl_isync_timeline *timeline = NULL; spin_lock(&priv->isync_timeline_lock); - timeline = idr_find(&priv->isync_timeline_idr, id); + spin_unlock(&priv->isync_timeline_lock); + if (timeline) ret = kref_get_unless_zero(&timeline->kref); - spin_unlock(&priv->isync_timeline_lock); if (!ret) timeline = NULL; @@ -268,6 +268,7 @@ int hgsl_isync_timeline_create(struct hgsl_priv *priv, timeline->context = dma_fence_context_alloc(1); INIT_LIST_HEAD(&timeline->fence_list); spin_lock_init(&timeline->lock); + timeline->priv = priv; idr_preload(GFP_KERNEL); spin_lock(&priv->isync_timeline_lock); @@ -354,21 +355,25 @@ out: return ret; } -static void hgsl_isync_timeline_cleanup(struct hgsl_priv *priv, - struct hgsl_isync_timeline *timeline) +static int hgsl_isync_timeline_destruct(struct hgsl_priv *priv, + struct hgsl_isync_timeline *timeline) { struct hgsl_isync_fence *cur, *next; + if (timeline == NULL) + return -EINVAL; + spin_lock(&timeline->lock); list_for_each_entry_safe(cur, next, &timeline->fence_list, child_list) { dma_fence_signal_locked(&cur->fence); list_del_init(&cur->child_list); } - spin_unlock(&timeline->lock); hgsl_isync_timeline_put(timeline); + + return 0; } int hgsl_isync_timeline_destroy(struct hgsl_priv *priv, uint32_t id) @@ -377,34 +382,51 @@ int hgsl_isync_timeline_destroy(struct hgsl_priv *priv, uint32_t id) spin_lock(&priv->isync_timeline_lock); timeline = idr_find(&priv->isync_timeline_idr, id); + spin_unlock(&priv->isync_timeline_lock); - if (timeline == NULL) { - spin_unlock(&priv->isync_timeline_lock); - return -EINVAL; - } + if (timeline == NULL) + return 0; if (timeline->id > 0) { idr_remove(&priv->isync_timeline_idr, timeline->id); timeline->id = 0; } + + return hgsl_isync_timeline_destruct(priv, timeline); +} + +void hgsl_isync_fini(struct hgsl_priv *priv) +{ + LIST_HEAD(flist); + struct hgsl_isync_timeline *cur, *t; + uint32_t idr; + + spin_lock(&priv->isync_timeline_lock); + idr_for_each_entry(&priv->isync_timeline_idr, + cur, idr) { + idr_remove(&priv->isync_timeline_idr, idr); + list_add(&cur->free_list, &flist); + } spin_unlock(&priv->isync_timeline_lock); - hgsl_isync_timeline_cleanup(priv, timeline); + list_for_each_entry_safe(cur, t, &flist, free_list) { + list_del(&cur->free_list); + hgsl_isync_timeline_destruct(priv, cur); + } - return 0; + idr_destroy(&priv->isync_timeline_idr); } static int _isync_timeline_signal( struct hgsl_isync_timeline *timeline, struct dma_fence *fence) { - struct hgsl_isync_fence *cur, *next; int ret = -EINVAL; + struct hgsl_isync_fence *cur, *next; spin_lock(&timeline->lock); - list_for_each_entry_safe(cur, next, &timeline->fence_list, - child_list) { + child_list) { if (fence == &cur->fence) { dma_fence_signal_locked(fence); list_del_init(&cur->child_list); @@ -413,6 +435,7 @@ static int _isync_timeline_signal( } } spin_unlock(&timeline->lock); + return ret; }