summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@codeaurora.org>2016-01-13 13:52:18 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:17:21 -0700
commitf1308d5f84b31a44b9c4af003bd34236ab8ca7c3 (patch)
treef3e42e0562ea0d50a2d3c1908a43526e9afb993d
parent8957b9e33d29145ab17ec78d47fe5cd60295052d (diff)
soc: qcom: glink_smd_xprt: Resume RX operation during intent re-use
G-Link SMD Transitional XPRT resumes RX operation only when a receive intent is queued. This leads to a communication stall if the receive intents get re-used and is not queued. Resume the RX operation in G-Link SMD Transitional XPRT if a receive intent is re-used. Also access the intent_req flag exclusively to avoid any race condition. CRs-Fixed: 938394 Change-Id: I5a1fdc7ee35070a42659c8e701d73ee2de8d6d05 Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
-rw-r--r--drivers/soc/qcom/glink_smd_xprt.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/drivers/soc/qcom/glink_smd_xprt.c b/drivers/soc/qcom/glink_smd_xprt.c
index bfe6bfe77a4f..a591fa4e5982 100644
--- a/drivers/soc/qcom/glink_smd_xprt.c
+++ b/drivers/soc/qcom/glink_smd_xprt.c
@@ -153,6 +153,7 @@ struct channel {
bool is_closing;
bool local_legacy;
bool remote_legacy;
+ size_t intent_req_size;
spinlock_t rx_data_lock;
bool streaming_ch;
bool tx_resume_needed;
@@ -726,10 +727,13 @@ static void process_data_event(struct work_struct *work)
ch->rcid);
if (!ch->cur_intent && !einfo->intentless) {
spin_lock_irqsave(&ch->intents_lock, intents_flags);
+ ch->intent_req = true;
+ ch->intent_req_size = pkt_remaining;
list_for_each_entry(i, &ch->intents, node) {
if (i->size >= pkt_remaining) {
list_del(&i->node);
ch->cur_intent = i;
+ ch->intent_req = false;
break;
}
}
@@ -742,7 +746,6 @@ static void process_data_event(struct work_struct *work)
"%s Reqesting intent '%s' %u:%u\n",
__func__, ch->name,
ch->lcid, ch->rcid);
- ch->intent_req = true;
einfo->xprt_if.glink_core_if_ptr->
rx_cmd_remote_rx_intent_req(
&einfo->xprt_if,
@@ -1534,6 +1537,24 @@ static int deallocate_rx_intent(struct glink_transport_if *if_ptr,
}
/**
+ * check_and_resume_rx() - Check the RX state and resume it
+ * @ch: Channel which needs to be checked.
+ * @intent_size: Intent size being queued.
+ *
+ * This function checks if a receive intent is requested in the
+ * channel and resumes the RX if the queued receive intent satisifes
+ * the requested receive intent. This function must be called with
+ * ch->intents_lock locked.
+ */
+static void check_and_resume_rx(struct channel *ch, size_t intent_size)
+{
+ if (ch->intent_req && ch->intent_req_size <= intent_size) {
+ ch->intent_req = false;
+ queue_work(ch->wq, &ch->work);
+ }
+}
+
+/**
* tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
* transmit
* @if_ptr: The transport to transmit on.
@@ -1578,13 +1599,9 @@ static int tx_cmd_local_rx_intent(struct glink_transport_if *if_ptr,
intent->size = size;
spin_lock_irqsave(&ch->intents_lock, flags);
list_add_tail(&intent->node, &ch->intents);
+ check_and_resume_rx(ch, size);
spin_unlock_irqrestore(&ch->intents_lock, flags);
- if (ch->intent_req) {
- ch->intent_req = false;
- queue_work(ch->wq, &ch->work);
- }
-
srcu_read_unlock(&einfo->ssr_sync, rcu_id);
return 0;
}
@@ -1615,10 +1632,12 @@ static void tx_cmd_local_rx_done(struct glink_transport_if *if_ptr,
list_for_each_entry(i, &ch->used_intents, node) {
if (i->liid == liid) {
list_del(&i->node);
- if (reuse)
+ if (reuse) {
list_add_tail(&i->node, &ch->intents);
- else
+ check_and_resume_rx(ch, i->size);
+ } else {
kfree(i);
+ }
break;
}
}