summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/hab
diff options
context:
space:
mode:
authorYong Ding <yongding@codeaurora.org>2018-11-01 15:59:49 +0800
committerYong Ding <yongding@codeaurora.org>2018-11-01 17:37:29 +0800
commitcf41f3e0d3c2e5025f401a61cfaa7a79d27cc586 (patch)
tree5acba8bc863f07e48e501022e51bf5a5e3aafec8 /drivers/soc/qcom/hab
parent67b38b0496484ac2b862c9514cff40b82a92a622 (diff)
soc: qcom: hab: refine hab virtual channel's resource free
Whenever a vchan is locally closed in hab_vchan_close or hab_free, 4 actions should be taken immediately, including, - remove it from the local hab context - mark its local closed flag - notify remote side and unblock local blocking calls over it - decrease the refcnt on the vchan Change-Id: I3fbde9464f6405b6dadac248768a5fd857a29128 Signed-off-by: Yong Ding <yongding@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom/hab')
-rw-r--r--drivers/soc/qcom/hab/hab.c33
-rw-r--r--drivers/soc/qcom/hab/hab_vchan.c40
2 files changed, 17 insertions, 56 deletions
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c
index 7d53e6162172..24461d2c957b 100644
--- a/drivers/soc/qcom/hab/hab.c
+++ b/drivers/soc/qcom/hab/hab.c
@@ -720,11 +720,18 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid)
write_lock(&ctx->ctx_lock);
list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
if (vchan->id == vcid) {
+ /* local close starts */
vchan->closed = 1;
- write_unlock(&ctx->ctx_lock);
+
+ /* vchan is not in this ctx anymore */
+ list_del(&vchan->node);
+ ctx->vcnt--;
+
pr_debug("vcid %x remote %x session %d refcnt %d\n",
vchan->id, vchan->otherend_id,
vchan->session_id, get_refcnt(vchan->refcount));
+
+ write_unlock(&ctx->ctx_lock);
/* unblocking blocked in-calls */
hab_vchan_stop_notify(vchan);
hab_vchan_put(vchan); /* there is a lock inside */
@@ -1069,28 +1076,14 @@ static int hab_release(struct inode *inodep, struct file *filep)
write_lock(&ctx->ctx_lock);
/* notify remote side on vchan closing */
list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
- list_del(&vchan->node); /* vchan is not in this ctx anymore */
+ /* local close starts */
+ vchan->closed = 1;
- if (!vchan->closed) { /* locally hasn't closed yet */
- if (!kref_get_unless_zero(&vchan->refcount)) {
- pr_err("vchan %x %x refcnt %d mismanaged closed %d remote closed %d\n",
- vchan->id,
- vchan->otherend_id,
- get_refcnt(vchan->refcount),
- vchan->closed, vchan->otherend_closed);
- continue; /* vchan is already being freed */
- } else {
- write_unlock(&ctx->ctx_lock);
- hab_vchan_stop_notify(vchan);
- /* put for notify. shouldn't cause free */
- hab_vchan_put(vchan);
- write_lock(&ctx->ctx_lock);
- }
- } else
- continue;
+ list_del(&vchan->node); /* vchan is not in this ctx anymore */
+ ctx->vcnt--;
- /* for the missing local vchan close */
write_unlock(&ctx->ctx_lock);
+ hab_vchan_stop_notify(vchan);
hab_vchan_put(vchan); /* there is a lock inside */
write_lock(&ctx->ctx_lock);
}
diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c
index 770c6ba3dadd..a95d6c7451c9 100644
--- a/drivers/soc/qcom/hab/hab_vchan.c
+++ b/drivers/soc/qcom/hab/hab_vchan.c
@@ -85,9 +85,6 @@ hab_vchan_free(struct kref *ref)
}
spin_unlock_bh(&vchan->rx_lock);
- /* the release vchan from ctx was done earlier in vchan close() */
- hab_ctx_put(ctx); /* now ctx is not needed from this vchan's view */
-
/* release vchan from pchan. no more msg for this vchan */
write_lock_bh(&pchan->vchans_lock);
list_for_each_entry_safe(vc, vc_tmp, &pchan->vchannels, pnode) {
@@ -100,6 +97,9 @@ hab_vchan_free(struct kref *ref)
}
write_unlock_bh(&pchan->vchans_lock);
+ /* the release vchan from ctx was done earlier in vchan close() */
+ hab_ctx_put(ctx); /* now ctx is not needed from this vchan's view */
+
/* release idr at the last so same idr will not be used early */
spin_lock_bh(&pchan->vid_lock);
idr_remove(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan->id));
@@ -274,42 +274,10 @@ int hab_vchan_find_domid(struct virtual_channel *vchan)
return vchan ? vchan->pchan->dom_id : -1;
}
-/* this sould be only called once after refcnt is zero */
-static void hab_vchan_schedule_free(struct kref *ref)
-{
- struct virtual_channel *vchanin =
- container_of(ref, struct virtual_channel, refcount);
- struct uhab_context *ctx = vchanin->ctx;
- struct virtual_channel *vchan, *tmp;
- int bnotify = 0;
-
- /*
- * similar logic is in ctx free. if ctx free runs first,
- * this is skipped
- */
- write_lock_bh(&ctx->ctx_lock);
- list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
- if (vchan == vchanin) {
- pr_debug("vchan free refcnt = %d\n",
- get_refcnt(vchan->refcount));
- ctx->vcnt--;
- list_del(&vchan->node);
- bnotify = 1;
- break;
- }
- }
- write_unlock_bh(&ctx->ctx_lock);
-
- if (bnotify)
- hab_vchan_stop_notify(vchan);
-
- hab_vchan_free(ref);
-}
-
void hab_vchan_put(struct virtual_channel *vchan)
{
if (vchan)
- kref_put(&vchan->refcount, hab_vchan_schedule_free);
+ kref_put(&vchan->refcount, hab_vchan_free);
}
int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids,