soc: qcom: hgsl: Clean up timelines in release

Applications have no chance to destroy timelines if crash. This change
could clean isolated timelines.

Change-Id: If15a5b8f5f45c6c6b051fcaea81bf51c2bc7aa64
Signed-off-by: Kasin Li <donglil@codeaurora.org>
This commit is contained in:
Kasin Li 2021-03-18 20:13:34 +08:00
commit e056dc2591
3 changed files with 41 additions and 14 deletions

View file

@ -1297,6 +1297,8 @@ static int hgsl_release(struct inode *inodep, struct file *filep)
}
}
hgsl_isync_fini(priv);
kfree(priv);
return 0;
}

View file

@ -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,

View file

@ -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;
}