diff --git a/drivers/soc/qcom/msm_glink_ssr.c b/drivers/soc/qcom/msm_glink_ssr.c index 491c2105adfd..b64496b24d1a 100644 --- a/drivers/soc/qcom/msm_glink_ssr.c +++ b/drivers/soc/qcom/msm_glink_ssr.c @@ -64,8 +64,21 @@ struct glink_ssr { u32 seq_num; struct completion completion; struct work_struct unreg_work; + struct kref refcount; }; +static void glink_ssr_release(struct kref *ref) +{ + struct glink_ssr *ssr = container_of(ref, struct glink_ssr, + refcount); + struct glink_ssr_nb *nb, *tmp; + + list_for_each_entry_safe(nb, tmp, &ssr->notify_list, list) + kfree(nb); + + kfree(ssr); +} + static void glink_ssr_ssr_unreg_work(struct work_struct *work) { struct glink_ssr *ssr = container_of(work, struct glink_ssr, @@ -75,9 +88,8 @@ static void glink_ssr_ssr_unreg_work(struct work_struct *work) list_for_each_entry_safe(nb, tmp, &ssr->notify_list, list) { subsys_notif_unregister_notifier(nb->ssr_register_handle, &nb->nb); - kfree(nb); } - kfree(ssr); + kref_put(&ssr->refcount, glink_ssr_release); } static int glink_ssr_ssr_cb(struct notifier_block *this, @@ -92,6 +104,8 @@ static int glink_ssr_ssr_cb(struct notifier_block *this, if (!dev || !ssr->ept) return NOTIFY_DONE; + kref_get(&ssr->refcount); + if (code == SUBSYS_AFTER_SHUTDOWN || code == SUBSYS_POWERUP_FAILURE) { ssr->seq_num++; reinit_completion(&ssr->completion); @@ -110,6 +124,7 @@ static int glink_ssr_ssr_cb(struct notifier_block *this, if (ret) { MSM_SSR_ERR(dev, "fail to send do cleanup to %s %d\n", nb->ssr_label, ret); + kref_put(&ssr->refcount, glink_ssr_release); return NOTIFY_DONE; } @@ -117,6 +132,7 @@ static int glink_ssr_ssr_cb(struct notifier_block *this, if (!ret) MSM_SSR_ERR(dev, "timeout waiting for cleanup resp\n"); } + kref_put(&ssr->refcount, glink_ssr_release); return NOTIFY_DONE; } @@ -217,6 +233,7 @@ static int glink_ssr_probe(struct rpmsg_device *rpdev) INIT_LIST_HEAD(&ssr->notify_list); init_completion(&ssr->completion); INIT_WORK(&ssr->unreg_work, glink_ssr_ssr_unreg_work); + kref_init(&ssr->refcount); ssr->dev = &rpdev->dev; ssr->ept = rpdev->ept;