msm: ADSPRPC: Flush un-aligned buffers before remote invocation

Output buffers that are not aligned on cache line boundaries need to
be flushed before the remote invocation since the invalidate that
happens later could result in a flush of an un-aligned buffer,
overwriting the remote end results.

Change-Id: I2e7b4c33ccd29413b0e5d2abe47cd069e08e8c80
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 719a06f..e98fff2 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -56,6 +56,8 @@
 		} while (0)
 
 
+#define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
+
 static inline uint32_t buf_page_start(void *buf)
 {
 	uint32_t start = (uint32_t) buf & PAGE_MASK;
@@ -517,6 +519,28 @@
 	return err;
 }
 
+static void inv_args_pre(uint32_t sc, remote_arg_t *rpra)
+{
+	int i, inbufs, outbufs;
+	uint32_t end;
+
+	inbufs = REMOTE_SCALARS_INBUFS(sc);
+	outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+	for (i = inbufs; i < inbufs + outbufs; ++i) {
+		if (!rpra[i].buf.len)
+			continue;
+		if (buf_page_start(rpra) == buf_page_start(rpra[i].buf.pv))
+			continue;
+		if (!IS_CACHE_ALIGNED((uint32_t)rpra[i].buf.pv))
+			dmac_flush_range(rpra[i].buf.pv,
+				(char *)rpra[i].buf.pv + 1);
+		end = (uint32_t)rpra[i].buf.pv + rpra[i].buf.len;
+		if (!IS_CACHE_ALIGNED(end))
+			dmac_flush_range((char *)end,
+				(char *)end + 1);
+	}
+}
+
 static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
 {
 	int i, inbufs, outbufs;
@@ -780,6 +804,7 @@
 	}
 
 	context_list_alloc_ctx(&me->clst, &ctx);
+	inv_args_pre(sc, rpra);
 	VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
 						ctx, &obuf));
 	if (err)