Loading drivers/soc/qcom/hab/hab.c +21 −41 Original line number Diff line number Diff line Loading @@ -209,14 +209,15 @@ void hab_ctx_free(struct kref *ref) * the local ioctl access based on ctx */ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct uhab_context *ctx) struct uhab_context *ctx, int ignore_remote) { struct virtual_channel *vchan; read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { if (vcid == vchan->id) { if (vchan->otherend_closed || vchan->closed || if ((ignore_remote ? 0 : vchan->otherend_closed) || vchan->closed || !kref_get_unless_zero(&vchan->refcount)) { pr_debug("failed to inc vcid %x remote %x session %d refcnt %d close_flg remote %d local %d\n", vchan->id, vchan->otherend_id, Loading Loading @@ -550,7 +551,7 @@ long hab_vchan_send(struct uhab_context *ctx, return -EINVAL; } vchan = hab_get_vchan_fromvcid(vcid, ctx); vchan = hab_get_vchan_fromvcid(vcid, ctx, 0); if (!vchan || vchan->otherend_closed) { ret = -ENODEV; goto err; Loading Loading @@ -597,7 +598,7 @@ int hab_vchan_recv(struct uhab_context *ctx, int ret = 0; int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING; vchan = hab_get_vchan_fromvcid(vcid, ctx); vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); if (!vchan) { pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx); return -ENODEV; Loading Loading @@ -719,24 +720,20 @@ 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) { write_unlock(&ctx->ctx_lock); /* local close starts */ vchan->closed = 1; /* 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)); /* * only set when vc close is called locally by user * explicity. Used to block remote msg. if forked once * before, this local close is skipped due to child * usage. if forked but not closed locally, the local * context could NOT be closed, vchan can be prolonged * by arrived remote msgs */ if (vchan->forked) vchan->forked = 0; else { vchan->closed = 1; write_unlock(&ctx->ctx_lock); /* unblocking blocked in-calls */ hab_vchan_stop_notify(vchan); } hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); break; Loading Loading @@ -1079,25 +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 { hab_vchan_stop_notify(vchan); /* put for notify. shouldn't cause free */ hab_vchan_put(vchan); } } else continue; list_del(&vchan->node); /* vchan is not in this ctx anymore */ ctx->vcnt--; write_unlock(&ctx->ctx_lock); hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); } Loading @@ -1117,12 +1103,6 @@ static int hab_release(struct inode *inodep, struct file *filep) hab_ctx_put(ctx); filep->private_data = NULL; /* ctx leak check */ if (get_refcnt(ctx->refcount)) pr_warn("pending ctx release owner %d refcnt %d total %d\n", ctx->owner, get_refcnt(ctx->refcount), hab_driver.ctx_cnt); return 0; } Loading drivers/soc/qcom/hab/hab.h +1 −1 Original line number Diff line number Diff line Loading @@ -494,7 +494,7 @@ struct virtual_channel *hab_vchan_get(struct physical_channel *pchan, void hab_vchan_put(struct virtual_channel *vchan); struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct uhab_context *ctx); struct uhab_context *ctx, int ignore_remote); struct physical_channel *hab_pchan_alloc(struct hab_device *habdev, int otherend_id); struct physical_channel *hab_pchan_find_domid(struct hab_device *dev, Loading drivers/soc/qcom/hab/hab_mimex.c +4 −4 Original line number Diff line number Diff line Loading @@ -246,7 +246,7 @@ int hab_mem_export(struct uhab_context *ctx, if (!ctx || !param || !param->buffer) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err; Loading Loading @@ -313,7 +313,7 @@ int hab_mem_unexport(struct uhab_context *ctx, return -EINVAL; /* refcnt on the access */ vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err_novchan; Loading Loading @@ -360,7 +360,7 @@ int hab_mem_import(struct uhab_context *ctx, if (!ctx || !param) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err_imp; Loading Loading @@ -420,7 +420,7 @@ int hab_mem_unimport(struct uhab_context *ctx, if (!ctx || !param) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1); if (!vchan || !vchan->pchan) { if (vchan) hab_vchan_put(vchan); Loading drivers/soc/qcom/hab/hab_msg.c +23 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,12 @@ hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes) { struct hab_message *message; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s send size too large %zd\n", pchan->name, sizebytes); return NULL; } message = kzalloc(sizeof(*message) + sizebytes, GFP_ATOMIC); if (!message) return NULL; Loading Loading @@ -153,6 +159,12 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan, pr_err("exp ack size %zu is not as arrived %zu\n", sizeof(ack_recvd->ack), sizebytes); if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s read size too large %zd\n", pchan->name, sizebytes); return -EINVAL; } if (physical_channel_read(pchan, &ack_recvd->ack, sizebytes) != sizebytes) Loading @@ -169,6 +181,11 @@ static void hab_msg_drop(struct physical_channel *pchan, size_t sizebytes) { uint8_t *data = NULL; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("%s read size too large %zd\n", pchan->name, sizebytes); return; } data = kmalloc(sizebytes, GFP_ATOMIC); if (data == NULL) return; Loading Loading @@ -275,6 +292,12 @@ int hab_msg_recv(struct physical_channel *pchan, break; case HAB_PAYLOAD_TYPE_EXPORT: if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("%s exp size too large %zd\n", pchan->name, sizebytes); break; } exp_desc = kzalloc(sizebytes, GFP_ATOMIC); if (!exp_desc) break; Loading drivers/soc/qcom/hab/hab_open.c +12 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,12 @@ int hab_open_request_add(struct physical_channel *pchan, struct hab_open_request *request; struct timeval tv; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s request size too large %zd\n", pchan->name, sizebytes); return -EINVAL; } node = kzalloc(sizeof(*node), GFP_ATOMIC); if (!node) return -ENOMEM; Loading Loading @@ -187,6 +193,12 @@ int hab_open_receive_cancel(struct physical_channel *pchan, int bfound = 0; struct timeval tv; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s cancel size too large %zd\n", pchan->name, sizebytes); return -EINVAL; } if (physical_channel_read(pchan, &data, sizebytes) != sizebytes) return -EIO; Loading Loading
drivers/soc/qcom/hab/hab.c +21 −41 Original line number Diff line number Diff line Loading @@ -209,14 +209,15 @@ void hab_ctx_free(struct kref *ref) * the local ioctl access based on ctx */ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct uhab_context *ctx) struct uhab_context *ctx, int ignore_remote) { struct virtual_channel *vchan; read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { if (vcid == vchan->id) { if (vchan->otherend_closed || vchan->closed || if ((ignore_remote ? 0 : vchan->otherend_closed) || vchan->closed || !kref_get_unless_zero(&vchan->refcount)) { pr_debug("failed to inc vcid %x remote %x session %d refcnt %d close_flg remote %d local %d\n", vchan->id, vchan->otherend_id, Loading Loading @@ -550,7 +551,7 @@ long hab_vchan_send(struct uhab_context *ctx, return -EINVAL; } vchan = hab_get_vchan_fromvcid(vcid, ctx); vchan = hab_get_vchan_fromvcid(vcid, ctx, 0); if (!vchan || vchan->otherend_closed) { ret = -ENODEV; goto err; Loading Loading @@ -597,7 +598,7 @@ int hab_vchan_recv(struct uhab_context *ctx, int ret = 0; int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING; vchan = hab_get_vchan_fromvcid(vcid, ctx); vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); if (!vchan) { pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx); return -ENODEV; Loading Loading @@ -719,24 +720,20 @@ 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) { write_unlock(&ctx->ctx_lock); /* local close starts */ vchan->closed = 1; /* 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)); /* * only set when vc close is called locally by user * explicity. Used to block remote msg. if forked once * before, this local close is skipped due to child * usage. if forked but not closed locally, the local * context could NOT be closed, vchan can be prolonged * by arrived remote msgs */ if (vchan->forked) vchan->forked = 0; else { vchan->closed = 1; write_unlock(&ctx->ctx_lock); /* unblocking blocked in-calls */ hab_vchan_stop_notify(vchan); } hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); break; Loading Loading @@ -1079,25 +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 { hab_vchan_stop_notify(vchan); /* put for notify. shouldn't cause free */ hab_vchan_put(vchan); } } else continue; list_del(&vchan->node); /* vchan is not in this ctx anymore */ ctx->vcnt--; write_unlock(&ctx->ctx_lock); hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); } Loading @@ -1117,12 +1103,6 @@ static int hab_release(struct inode *inodep, struct file *filep) hab_ctx_put(ctx); filep->private_data = NULL; /* ctx leak check */ if (get_refcnt(ctx->refcount)) pr_warn("pending ctx release owner %d refcnt %d total %d\n", ctx->owner, get_refcnt(ctx->refcount), hab_driver.ctx_cnt); return 0; } Loading
drivers/soc/qcom/hab/hab.h +1 −1 Original line number Diff line number Diff line Loading @@ -494,7 +494,7 @@ struct virtual_channel *hab_vchan_get(struct physical_channel *pchan, void hab_vchan_put(struct virtual_channel *vchan); struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, struct uhab_context *ctx); struct uhab_context *ctx, int ignore_remote); struct physical_channel *hab_pchan_alloc(struct hab_device *habdev, int otherend_id); struct physical_channel *hab_pchan_find_domid(struct hab_device *dev, Loading
drivers/soc/qcom/hab/hab_mimex.c +4 −4 Original line number Diff line number Diff line Loading @@ -246,7 +246,7 @@ int hab_mem_export(struct uhab_context *ctx, if (!ctx || !param || !param->buffer) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err; Loading Loading @@ -313,7 +313,7 @@ int hab_mem_unexport(struct uhab_context *ctx, return -EINVAL; /* refcnt on the access */ vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err_novchan; Loading Loading @@ -360,7 +360,7 @@ int hab_mem_import(struct uhab_context *ctx, if (!ctx || !param) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err_imp; Loading Loading @@ -420,7 +420,7 @@ int hab_mem_unimport(struct uhab_context *ctx, if (!ctx || !param) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx); vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1); if (!vchan || !vchan->pchan) { if (vchan) hab_vchan_put(vchan); Loading
drivers/soc/qcom/hab/hab_msg.c +23 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,12 @@ hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes) { struct hab_message *message; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s send size too large %zd\n", pchan->name, sizebytes); return NULL; } message = kzalloc(sizeof(*message) + sizebytes, GFP_ATOMIC); if (!message) return NULL; Loading Loading @@ -153,6 +159,12 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan, pr_err("exp ack size %zu is not as arrived %zu\n", sizeof(ack_recvd->ack), sizebytes); if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s read size too large %zd\n", pchan->name, sizebytes); return -EINVAL; } if (physical_channel_read(pchan, &ack_recvd->ack, sizebytes) != sizebytes) Loading @@ -169,6 +181,11 @@ static void hab_msg_drop(struct physical_channel *pchan, size_t sizebytes) { uint8_t *data = NULL; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("%s read size too large %zd\n", pchan->name, sizebytes); return; } data = kmalloc(sizebytes, GFP_ATOMIC); if (data == NULL) return; Loading Loading @@ -275,6 +292,12 @@ int hab_msg_recv(struct physical_channel *pchan, break; case HAB_PAYLOAD_TYPE_EXPORT: if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("%s exp size too large %zd\n", pchan->name, sizebytes); break; } exp_desc = kzalloc(sizebytes, GFP_ATOMIC); if (!exp_desc) break; Loading
drivers/soc/qcom/hab/hab_open.c +12 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,12 @@ int hab_open_request_add(struct physical_channel *pchan, struct hab_open_request *request; struct timeval tv; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s request size too large %zd\n", pchan->name, sizebytes); return -EINVAL; } node = kzalloc(sizeof(*node), GFP_ATOMIC); if (!node) return -ENOMEM; Loading Loading @@ -187,6 +193,12 @@ int hab_open_receive_cancel(struct physical_channel *pchan, int bfound = 0; struct timeval tv; if (sizebytes > HAB_HEADER_SIZE_MASK) { pr_err("pchan %s cancel size too large %zd\n", pchan->name, sizebytes); return -EINVAL; } if (physical_channel_read(pchan, &data, sizebytes) != sizebytes) return -EIO; Loading