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 @@
 
 /* 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 @@
 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 @@
 	}
 	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 @@
 			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 @@
 {
 	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 @@
 	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 @@
 		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 @@
 
 		/* Init MU */
 		MU_Init(mu_base_virtaddr);
+		MU_EnableRxFullInt(mu_base_virtaddr, 0);
 
 #if 1
 		/* Enable all RX interrupts */
@@ -364,6 +385,7 @@
 #endif
 		gIPCport = scu_mu_id;
 		scu_mu_init = true;
+		init_completion(&rx_completion);
 	}
 
 	sciErr = sc_ipc_open(&mu_ipcHandle, scu_mu_id);