diff options
| author | Karthikeyan Ramasubramanian <kramasub@codeaurora.org> | 2016-01-13 13:52:18 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:17:21 -0700 |
| commit | f1308d5f84b31a44b9c4af003bd34236ab8ca7c3 (patch) | |
| tree | f3e42e0562ea0d50a2d3c1908a43526e9afb993d | |
| parent | 8957b9e33d29145ab17ec78d47fe5cd60295052d (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.c | 35 |
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; } } |
