diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index a725b0148305..c7171a9366fc 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -198,8 +198,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 * @lsigs: local side signals * @rsigs: remote side signals */ @@ -233,8 +235,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; unsigned int lsigs; unsigned int rsigs; @@ -288,8 +292,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); kthread_init_work(&channel->intent_work, qcom_glink_rx_done_work); @@ -312,8 +318,10 @@ static void qcom_glink_channel_release(struct kref *ref) CH_INFO(channel, "\n"); channel->intent_req_result = false; - atomic_inc(&channel->intent_req_comp); - wake_up(&channel->intent_req_event); + atomic_inc(&channel->intent_req_acked); + wake_up(&channel->intent_req_ack); + atomic_inc(&channel->intent_req_completed); + wake_up(&channel->intent_req_comp); /* cancel pending rx_done work */ kthread_cancel_work_sync(&channel->intent_work); @@ -504,8 +512,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); CH_INFO(channel, "\n"); } @@ -1144,6 +1152,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)); } @@ -1537,7 +1548,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; @@ -1549,11 +1561,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)) { CH_INFO(channel, "ssr detected\n"); @@ -1614,6 +1626,25 @@ 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)) { + CH_INFO(channel, "ssr detected\n"); + ret = -ECONNRESET; + } else { + ret = channel->intent_req_result ? 0 : -ECANCELED; + } + + if (ret < 0) + return ret; } iid = intent->id; @@ -2041,7 +2072,8 @@ static void qcom_glink_notif_reset(void *data) 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); }