diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 820d22be303d..43afd29e82ee 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -158,8 +158,10 @@ enum { * @open_req: completed once open-request has been received * @intent_req_lock: Synchronises multiple intent requests * @intent_req_result: Result of intent request - * @intent_req_comp: Status of intent request completion - * @intent_req_event: Waitqueue for @intent_req_comp + * @intent_req_acked: Status of intent request acknowledgment + * @intent_req_completed: Status of intent request completion + * @intent_req_ack: Waitqueue for @intent_req_acked + * @intent_req_comp: Waitqueue for @intent_req_completed */ struct glink_channel { struct rpmsg_endpoint ept; @@ -191,8 +193,10 @@ struct glink_channel { struct mutex intent_req_lock; bool intent_req_result; bool channel_ready; - atomic_t intent_req_comp; - wait_queue_head_t intent_req_event; + atomic_t intent_req_acked; + atomic_t intent_req_completed; + wait_queue_head_t intent_req_ack; + wait_queue_head_t intent_req_comp; }; #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) @@ -237,8 +241,10 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(&channel->open_req); init_completion(&channel->open_ack); - atomic_set(&channel->intent_req_comp, 0); - init_waitqueue_head(&channel->intent_req_event); + atomic_set(&channel->intent_req_acked, 0); + atomic_set(&channel->intent_req_completed, 0); + init_waitqueue_head(&channel->intent_req_ack); + init_waitqueue_head(&channel->intent_req_comp); INIT_LIST_HEAD(&channel->done_intents); INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work); @@ -260,9 +266,11 @@ static void qcom_glink_channel_release(struct kref *ref) int iid; channel->intent_req_result = false; - atomic_inc(&channel->intent_req_comp); + atomic_inc(&channel->intent_req_acked); + wake_up(&channel->intent_req_ack); + atomic_inc(&channel->intent_req_completed); + wake_up(&channel->intent_req_comp); - wake_up(&channel->intent_req_event); /* cancel pending rx_done work */ cancel_work_sync(&channel->intent_work); @@ -437,8 +445,8 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink, } channel->intent_req_result = granted; - atomic_inc(&channel->intent_req_comp); - wake_up(&channel->intent_req_event); + atomic_inc(&channel->intent_req_acked); + wake_up(&channel->intent_req_ack); } /** @@ -1049,6 +1057,9 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink, dev_err(glink->dev, "failed to store remote intent\n"); } + atomic_inc(&channel->intent_req_completed); + wake_up(&channel->intent_req_comp); + kfree(msg); qcom_glink_rx_advance(glink, ALIGN(msglen, 8)); } @@ -1352,7 +1363,8 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, mutex_lock(&channel->intent_req_lock); - atomic_set(&channel->intent_req_comp, 0); + atomic_set(&channel->intent_req_acked, 0); + atomic_set(&channel->intent_req_completed, 0); cmd.id = RPM_CMD_RX_INTENT_REQ; cmd.cid = channel->lcid; @@ -1362,11 +1374,11 @@ static int qcom_glink_request_intent(struct qcom_glink *glink, if (ret) goto unlock; - ret = wait_event_timeout(channel->intent_req_event, - atomic_read(&channel->intent_req_comp) || + ret = wait_event_timeout(channel->intent_req_ack, + atomic_read(&channel->intent_req_acked) || atomic_read(&glink->in_reset), 10 * HZ); if (!ret) { - dev_err(glink->dev, "intent request timed out\n"); + dev_err(glink->dev, "intent request ack timed out\n"); ret = -ETIMEDOUT; } else if (atomic_read(&glink->in_reset)) { ret = -ECONNRESET; @@ -1426,6 +1438,24 @@ static int __qcom_glink_send(struct glink_channel *channel, ret = qcom_glink_request_intent(glink, channel, len); if (ret < 0) return ret; + + /*Wait for intents to arrive*/ + ret = wait_event_timeout(channel->intent_req_comp, + atomic_read(&channel->intent_req_completed) || + atomic_read(&glink->in_reset), 10 * HZ); + + if (!ret) { + dev_err(glink->dev, + "intent request completion timed out\n"); + ret = -ETIMEDOUT; + } else if (atomic_read(&glink->in_reset)) { + ret = -ECONNRESET; + } else { + ret = channel->intent_req_result ? 0 : -ECANCELED; + } + + if (ret < 0) + return ret; } iid = intent->id; @@ -1910,7 +1940,8 @@ void qcom_glink_native_remove(struct qcom_glink *glink) /* Signal all threads to cancel tx */ spin_lock_irqsave(&glink->idr_lock, flags); idr_for_each_entry(&glink->lcids, channel, cid) { - wake_up(&channel->intent_req_event); + wake_up(&channel->intent_req_ack); + wake_up(&channel->intent_req_comp); } spin_unlock_irqrestore(&glink->idr_lock, flags);