summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@codeaurora.org>2016-04-15 13:58:28 -0600
committerJeevan Shriram <jshriram@codeaurora.org>2016-04-22 11:57:50 -0700
commit2eabbd25b651db053c68cbab6a7fc091a49fe877 (patch)
tree9ed56f678fd0793ae1d8f8304034c8b4a2fe633d /drivers/soc
parent1071415ec45bbb04016b8da428d4d39befa6e813 (diff)
soc: qcom: glink_smd_xprt: Defer channel close ACK operation
Depending on the timing of two competing transport registration with G-Link core, a channel gets opened on one transport and then immediately migrated to another transport. This channel migration happens in the context of glink_open() operation itself and causes a re-lock attempt on an already locked mutex. Defer the channel close ACK operation so that channel migration does not hit the deadlock. CRs-Fixed: 1004150 Change-Id: I188846b95369b674830bc01ddeca764ad6d4d391 Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/qcom/glink_smd_xprt.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/soc/qcom/glink_smd_xprt.c b/drivers/soc/qcom/glink_smd_xprt.c
index 9936dc22400c..c0ed33ed2845 100644
--- a/drivers/soc/qcom/glink_smd_xprt.c
+++ b/drivers/soc/qcom/glink_smd_xprt.c
@@ -558,6 +558,24 @@ static void ssr_work_func(struct work_struct *work)
}
/**
+ * deferred_close_ack() - Generate a deferred channel close ack
+ * @work: The channel close ack work to generate.
+ */
+static void deferred_close_ack(struct work_struct *work)
+{
+ struct channel_work *ch_work;
+ struct channel *ch;
+
+ ch_work = container_of(work, struct channel_work, work);
+ ch = ch_work->ch;
+ mutex_lock(&ch->edge->rx_cmd_lock);
+ ch->edge->xprt_if.glink_core_if_ptr->rx_cmd_ch_close_ack(
+ &ch->edge->xprt_if, ch->lcid);
+ mutex_unlock(&ch->edge->rx_cmd_lock);
+ kfree(ch_work);
+}
+
+/**
* process_tx_done() - process a tx done task
* @work: The tx done task to process.
*/
@@ -899,6 +917,7 @@ static void smd_data_ch_close(struct channel *ch)
{
struct intent_info *intent;
unsigned long flags;
+ struct channel_work *ch_work;
SMDXPRT_INFO(ch->edge, "%s Closing SMD channel lcid %u\n",
__func__, ch->lcid);
@@ -919,11 +938,12 @@ static void smd_data_ch_close(struct channel *ch)
smd_close(ch->smd_ch);
ch->smd_ch = NULL;
} else if (ch->local_legacy) {
- mutex_lock(&ch->edge->rx_cmd_lock);
- ch->edge->xprt_if.glink_core_if_ptr->rx_cmd_ch_close_ack(
- &ch->edge->xprt_if,
- ch->lcid);
- mutex_unlock(&ch->edge->rx_cmd_lock);
+ ch_work = kzalloc(sizeof(*ch_work), GFP_KERNEL);
+ if (ch_work) {
+ ch_work->ch = ch;
+ INIT_WORK(&ch_work->work, deferred_close_ack);
+ queue_work(ch->wq, &ch_work->work);
+ }
}
mutex_unlock(&ch->ch_probe_lock);