summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
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);