提交 f76c6916 编写于 作者: S Stephen Boyd 提交者: Kumar Gala

ARM: qcom: scm: Fix incorrect cache invalidation

The cache invalidation in scm_call() correctly rounds down the start
address to invalidate the beginning of the cacheline but doesn't properly
round up the 'end' address to make it aligned.  The last chunk of the
buffer won't be invalidated when 'end' is not cacheline size aligned so
make sure to invalidate the last few bytes in such situations. It also
doesn't do anything about outer caches so make sure to invalidate and flush
those as well.
Signed-off-by: NStephen Boyd <sboyd@codeaurora.org>
Signed-off-by: NKumar Gala <galak@codeaurora.org>
上级 e5ca0feb
......@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <asm/outercache.h>
#include <asm/cacheflush.h>
#include "scm.h"
......@@ -203,6 +204,7 @@ static int __scm_call(const struct scm_command *cmd)
* side in the buffer.
*/
flush_cache_all();
outer_flush_all();
ret = smc(cmd_addr);
if (ret < 0)
ret = scm_remap_error(ret);
......@@ -210,6 +212,20 @@ static int __scm_call(const struct scm_command *cmd)
return ret;
}
static void scm_inv_range(unsigned long start, unsigned long end)
{
start = round_down(start, CACHELINESIZE);
end = round_up(end, CACHELINESIZE);
outer_inv_range(start, end);
while (start < end) {
asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
: "memory");
start += CACHELINESIZE;
}
dsb();
isb();
}
/**
* scm_call() - Send an SCM command
* @svc_id: service identifier
......@@ -227,6 +243,7 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
int ret;
struct scm_command *cmd;
struct scm_response *rsp;
unsigned long start, end;
cmd = alloc_scm_command(cmd_len, resp_len);
if (!cmd)
......@@ -243,17 +260,15 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
goto out;
rsp = scm_command_to_response(cmd);
start = (unsigned long)rsp;
do {
u32 start = (u32)rsp;
u32 end = (u32)scm_get_response_buffer(rsp) + resp_len;
start &= ~(CACHELINESIZE - 1);
while (start < end) {
asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
: "memory");
start += CACHELINESIZE;
}
scm_inv_range(start, start + sizeof(*rsp));
} while (!rsp->is_complete);
end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
scm_inv_range(start, end);
if (resp_buf)
memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
out:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册