From 1f2cb1a4a4d4340bb9fcd2a71415144334d89caf Mon Sep 17 00:00:00 2001 From: Josh Kirsch Date: Fri, 15 Apr 2016 14:05:05 -0700 Subject: [PATCH] drivers: soc: Add intent notification callback for APR Glink APR is required not to send any packet until the far end queues at least one intent. Add the wait during client registration time. Change-Id: Ie29ddda4527ae7a70afff2c595d6e3c76500a8af Signed-off-by: Deven Patel Signed-off-by: Josh Kirsch --- drivers/soc/qcom/qdsp6v2/apr_tal_glink.c | 30 ++++++++++++++++++++++++ include/linux/qdsp6v2/apr_tal.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index 653f665b6e5d..14e46b38c6df 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -210,6 +210,25 @@ bool apr_tal_notify_rx_intent_req(void *handle, const void *priv, return false; } +static void apr_tal_notify_remote_rx_intent(void *handle, const void *priv, + size_t size) +{ + struct apr_svc_ch_dev *apr_ch = (struct apr_svc_ch_dev *)priv; + + if (!apr_ch) { + pr_err("%s: Invalid apr_ch\n", __func__); + return; + } + /* + * This is to make sure that the far end has queued at least one intent + * before we attmpt any IPC. A simple bool flag is used here instead of + * a counter, as the far end is required to guarantee intent + * availability for all use cases once the channel is fully opened. + */ + pr_debug("%s: remote queued an intent\n", __func__); + apr_ch->if_remote_intent_ready = true; +} + void apr_tal_notify_state(void *handle, const void *priv, unsigned event) { struct apr_svc_ch_dev *apr_ch = (struct apr_svc_ch_dev *)priv; @@ -295,6 +314,7 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl, open_cfg.notify_tx_done = apr_tal_notify_tx_done; open_cfg.notify_state = apr_tal_notify_state; open_cfg.notify_rx_intent_req = apr_tal_notify_rx_intent_req; + open_cfg.notify_remote_rx_intent = apr_tal_notify_remote_rx_intent; open_cfg.priv = apr_ch; /* * The transport name "smd_trans" is required if far end is using SMD. @@ -321,6 +341,15 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl, goto close_link; } + /* + * Remote intent is not required for GLINK <--> SMD IPC, so this is + * designed not to fail the open call. + */ + rc = wait_event_timeout(apr_ch->wait, + apr_ch->if_remote_intent_ready, 5 * HZ); + if (rc == 0) + pr_err("%s: TIMEOUT for remote intent readiness\n", __func__); + rc = apr_tal_rx_intents_config(apr_ch, APR_DEFAULT_NUM_OF_INTENTS, APR_MAX_BUF); if (rc) { @@ -356,6 +385,7 @@ int apr_tal_close(struct apr_svc_ch_dev *apr_ch) apr_ch->handle = NULL; apr_ch->func = NULL; apr_ch->priv = NULL; + apr_ch->if_remote_intent_ready = false; mutex_unlock(&apr_ch->m_lock); exit: return rc; diff --git a/include/linux/qdsp6v2/apr_tal.h b/include/linux/qdsp6v2/apr_tal.h index eeb6ede976ad..ee8b2f5a8b5b 100644 --- a/include/linux/qdsp6v2/apr_tal.h +++ b/include/linux/qdsp6v2/apr_tal.h @@ -87,6 +87,7 @@ struct apr_svc_ch_dev { wait_queue_head_t wait; void *priv; unsigned channel_state; + bool if_remote_intent_ready; }; #else struct apr_svc_ch_dev {