MLK-21078-3 soc: imx: enable RX interrupt for IPC response

For IPC communication, CPU will be busy polling MU RX channel
after sending IPC message if IPC response is needed, such
mechanism wastes too much CPU resource if SCU takes long time
to finish the IPC request, so now enable RX interrupt for IPC
response.

Change-Id: I6e29f9fb611518bfb12cbce3228d3d0f436dc98b
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Bai Ping <ping.bai@nxp.com>
Signed-off-by: Leonid Lobachev <leonidl@google.com>
diff --git a/drivers/soc/imx/sc/main/ipc.c b/drivers/soc/imx/sc/main/ipc.c
index 68ad92c..be1e265 100644
--- a/drivers/soc/imx/sc/main/ipc.c
+++ b/drivers/soc/imx/sc/main/ipc.c
@@ -7,6 +7,7 @@
 
 /* Includes */
 #include <linux/arm-smccc.h>
+#include <linux/completion.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
@@ -18,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/mx8_mu.h>
 #include <linux/syscore_ops.h>
+#include <linux/suspend.h>
 
 #include <soc/imx/fsl_hvc.h>
 #include <soc/imx8/sc/svc/irq/api.h>
@@ -39,7 +41,9 @@ static sc_ipc_t mu_ipcHandle;
 
 /* Local variables */
 static uint32_t gIPCport;
+static sc_rpc_msg_t *rx_msg;
 static bool scu_mu_init;
+struct completion rx_completion;
 
 DEFINE_MUTEX(scu_mu_mutex);
 
@@ -57,6 +61,7 @@ EXPORT_SYMBOL(sc_pm_set_clock_rate);
 void sc_call_rpc(sc_ipc_t handle, sc_rpc_msg_t *msg, sc_bool_t no_resp)
 {
 	struct arm_smccc_res res;
+	unsigned long timeout;
 
 	if (in_interrupt()) {
 		pr_warn("Cannot make SC IPC calls from an interrupt context\n");
@@ -65,6 +70,8 @@ void sc_call_rpc(sc_ipc_t handle, sc_rpc_msg_t *msg, sc_bool_t no_resp)
 	}
 	mutex_lock(&scu_mu_mutex);
 
+	reinit_completion(&rx_completion);
+	rx_msg = msg;
 	if (xen_initial_domain()) {
 		arm_smccc_hvc(FSL_HVC_SC, (uint64_t)msg, no_resp, 0, 0, 0, 0,
 			      0, &res);
@@ -72,8 +79,14 @@ void sc_call_rpc(sc_ipc_t handle, sc_rpc_msg_t *msg, sc_bool_t no_resp)
 			printk("Error FSL_HVC_SC %ld\n", res.a0);
 	} else {
 		sc_ipc_write(handle, msg);
-		if (!no_resp)
-			sc_ipc_read(handle, msg);
+		if (!no_resp) {
+			timeout = wait_for_completion_timeout(&rx_completion, HZ / 10);
+			if (!timeout) {
+				pr_err("Timeout for IPC response!\n");
+				mutex_unlock(&scu_mu_mutex);
+				return;
+			}
+		}
 	}
 
 	mutex_unlock(&scu_mu_mutex);
@@ -285,6 +298,12 @@ static irqreturn_t imx8_scu_mu_isr(int irq, void *param)
 {
 	u32 irqs;
 
+	irqs = (readl_relaxed(mu_base_virtaddr + 0x20) & (0xf << 24));
+	if (irqs) {
+		sc_ipc_read(mu_ipcHandle, rx_msg);
+		complete(&rx_completion);
+	}
+
 	irqs = (readl_relaxed(mu_base_virtaddr + 0x20) & (0xf << 28));
 	if (irqs) {
 		/* Clear the General Interrupt */
@@ -301,6 +320,7 @@ static void imx8_mu_resume(void)
 	int i;
 
 	MU_Init(mu_base_virtaddr);
+	MU_EnableRxFullInt(mu_base_virtaddr, 0);
 	for (i = 0; i < MU_RR_COUNT; i++)
 		MU_EnableGeneralInt(mu_base_virtaddr, i);
 }
@@ -339,7 +359,7 @@ int __init imx8_mu_init(void)
 		pr_warn("imx8_mu_init: no irq: %d\n", irq);
 	} else {
 		err = request_irq(irq, imx8_scu_mu_isr,
-				  IRQF_EARLY_RESUME, "imx8_mu_isr", NULL);
+				  IRQF_NO_SUSPEND, "imx8_mu_isr", NULL);
 		if (err) {
 			pr_err("imx8_mu_init: request_irq %d failed: %d\n",
 					irq, err);
@@ -356,6 +376,7 @@ int __init imx8_mu_init(void)
 
 		/* Init MU */
 		MU_Init(mu_base_virtaddr);
+		MU_EnableRxFullInt(mu_base_virtaddr, 0);
 
 #if 1
 		/* Enable all RX interrupts */
@@ -364,6 +385,7 @@ int __init imx8_mu_init(void)
 #endif
 		gIPCport = scu_mu_id;
 		scu_mu_init = true;
+		init_completion(&rx_completion);
 	}
 
 	sciErr = sc_ipc_open(&mu_ipcHandle, scu_mu_id);