From e5ca0feb860baacd635aa684c72821e640a1dfa6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 22 Sep 2014 14:42:39 -0700 Subject: ARM: qcom: Select ARCH_SUPPORTS_BIG_ENDIAN We can run qcom platforms in big-endian mode. Select the option. Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index ee5697ba05bc..29aa8e1970b0 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -1,6 +1,7 @@ menuconfig ARCH_QCOM bool "Qualcomm Support" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB + select ARCH_SUPPORTS_BIG_ENDIAN select ARM_GIC select ARM_AMBA select CLKSRC_OF -- cgit From f76c6916570d8d24a622f2107ef747531148046e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 4 Aug 2014 18:31:43 -0700 Subject: 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: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c index c536fd6bf827..820c72165e19 100644 --- a/arch/arm/mach-qcom/scm.c +++ b/arch/arm/mach-qcom/scm.c @@ -22,6 +22,7 @@ #include #include +#include #include #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: -- cgit From 30cbb0c01bc98a2372966b8c5ac0ce1421cd933c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 4 Aug 2014 18:31:44 -0700 Subject: ARM: qcom: scm: Get cacheline size from CTR Instead of hardcoding the cacheline size as 32, get the cacheline size from the CTR register. Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c index 820c72165e19..c08786ebf116 100644 --- a/arch/arm/mach-qcom/scm.c +++ b/arch/arm/mach-qcom/scm.c @@ -27,9 +27,6 @@ #include "scm.h" -/* Cache line size for msm8x60 */ -#define CACHELINESIZE 32 - #define SCM_ENOMEM -5 #define SCM_EOPNOTSUPP -4 #define SCM_EINVAL_ADDR -3 @@ -214,13 +211,18 @@ static int __scm_call(const struct scm_command *cmd) static void scm_inv_range(unsigned long start, unsigned long end) { - start = round_down(start, CACHELINESIZE); - end = round_up(end, CACHELINESIZE); + u32 cacheline_size, ctr; + + asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); + cacheline_size = 4 << ((ctr >> 16) & 0xf); + + start = round_down(start, cacheline_size); + end = round_up(end, cacheline_size); outer_inv_range(start, end); while (start < end) { asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) : "memory"); - start += CACHELINESIZE; + start += cacheline_size; } dsb(); isb(); -- cgit From 404b5a97f5a2a718bb0feccc3712b1ab88f073d5 Mon Sep 17 00:00:00 2001 From: Vikram Mulukutla Date: Mon, 4 Aug 2014 18:31:45 -0700 Subject: ARM: qcom: scm: Flush the command buffer only instead of the entire cache scm_call flushes the entire cache before calling into the secure world. This is both a performance penalty as well as insufficient on SMP systems where the CPUs possess a write-back L1 cache. Flush only the command and response buffers instead, moving the responsibility of flushing any other cached buffer (being passed to the secure world) to callers. Signed-off-by: Vikram Mulukutla Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c index c08786ebf116..ec37b037e69c 100644 --- a/arch/arm/mach-qcom/scm.c +++ b/arch/arm/mach-qcom/scm.c @@ -196,12 +196,12 @@ static int __scm_call(const struct scm_command *cmd) u32 cmd_addr = virt_to_phys(cmd); /* - * Flush the entire cache here so callers don't have to remember - * to flush the cache when passing physical addresses to the secure - * side in the buffer. + * Flush the command buffer so that the secure world sees + * the correct data. */ - flush_cache_all(); - outer_flush_all(); + __cpuc_flush_dcache_area((void *)cmd, cmd->len); + outer_flush_range(cmd_addr, cmd_addr + cmd->len); + ret = smc(cmd_addr); if (ret < 0) ret = scm_remap_error(ret); @@ -238,6 +238,13 @@ static void scm_inv_range(unsigned long start, unsigned long end) * @resp_len: length of the response buffer * * Sends a command to the SCM and waits for the command to finish processing. + * + * A note on cache maintenance: + * Note that any buffers that are expected to be accessed by the secure world + * must be flushed before invoking scm_call and invalidated in the cache + * immediately after scm_call returns. Cache maintenance on the command and + * response buffers is taken care of by scm_call; however, callers are + * responsible for any other cached buffers passed over to the secure world. */ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, void *resp_buf, size_t resp_len) -- cgit From 4139447035463a1ec96ceef268716dd5cec6373c Mon Sep 17 00:00:00 2001 From: Olav Haugan Date: Mon, 4 Aug 2014 18:31:49 -0700 Subject: ARM: qcom: scm: Add logging of actual return code from scm call When an error occurs during an scm call the error returned is remapped so we lose the original error code. This means that when an error occurs we have no idea what actually failed within the secure environment. Add a logging statement that will log the actual error code from scm call allowing us to easily determine what caused the error to occur. Signed-off-by: Olav Haugan Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c index ec37b037e69c..a77349d34e78 100644 --- a/arch/arm/mach-qcom/scm.c +++ b/arch/arm/mach-qcom/scm.c @@ -152,6 +152,7 @@ static inline void *scm_get_response_buffer(const struct scm_response *rsp) static int scm_remap_error(int err) { + pr_err("scm_call failed with error code %d\n", err); switch (err) { case SCM_ERROR: return -EIO; -- cgit From 0c2d96780da958d4d48d116c6daaa85d4495d282 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Thu, 4 Sep 2014 16:35:26 -0600 Subject: ARM: qcom: Add SCM warmboot flags for quad core targets. Quad core targets like APQ8074, APQ8064, APQ8084 need SCM support set up warm boot addresses in the Secure Monitor. Extend the SCM flags to support warmboot addresses for secondary cores. Signed-off-by: Lina Iyer Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm-boot.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h index 6aabb2428176..02b445c426ce 100644 --- a/arch/arm/mach-qcom/scm-boot.h +++ b/arch/arm/mach-qcom/scm-boot.h @@ -18,6 +18,8 @@ #define SCM_FLAG_COLDBOOT_CPU3 0x20 #define SCM_FLAG_WARMBOOT_CPU0 0x04 #define SCM_FLAG_WARMBOOT_CPU1 0x02 +#define SCM_FLAG_WARMBOOT_CPU2 0x10 +#define SCM_FLAG_WARMBOOT_CPU3 0x40 int scm_set_boot_addr(phys_addr_t addr, int flags); -- cgit From 65b4ab65538e0da8e03e05d137001f10c78273d0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 23 Oct 2014 17:35:07 -0700 Subject: ARM: qcom: scm: Clarify boot interface The secure world only knows about 32-bit wide physical addresses for the boot API. Clarify the kernel interface by explicitly stating a u32 instead of phys_addr_t which could be 32 or 64 bits depending on LPAE or not. Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm-boot.c | 4 ++-- arch/arm/mach-qcom/scm-boot.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c index 45cee3e469a5..f2fa32834631 100644 --- a/arch/arm/mach-qcom/scm-boot.c +++ b/arch/arm/mach-qcom/scm-boot.c @@ -24,11 +24,11 @@ /* * Set the cold/warm boot address for one of the CPU cores. */ -int scm_set_boot_addr(phys_addr_t addr, int flags) +int scm_set_boot_addr(u32 addr, int flags) { struct { unsigned int flags; - phys_addr_t addr; + u32 addr; } cmd; cmd.addr = addr; diff --git a/arch/arm/mach-qcom/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h index 02b445c426ce..3e210fb818bb 100644 --- a/arch/arm/mach-qcom/scm-boot.h +++ b/arch/arm/mach-qcom/scm-boot.h @@ -21,6 +21,6 @@ #define SCM_FLAG_WARMBOOT_CPU2 0x10 #define SCM_FLAG_WARMBOOT_CPU3 0x40 -int scm_set_boot_addr(phys_addr_t addr, int flags); +int scm_set_boot_addr(u32 addr, int flags); #endif -- cgit From 7279db9287f226fbb3f349c3244f8dc4b783e645 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 21 Jan 2015 11:21:15 -0800 Subject: ARM: qcom: Fix SCM interface for big-endian kernels The secure environment only runs in little-endian mode, so any buffers shared with the secure environment should have their contents converted to little-endian. We also mark such elements with __le32 to allow sparse to catch such problems. Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/scm-boot.c | 8 ++++---- arch/arm/mach-qcom/scm.c | 30 ++++++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c index f2fa32834631..e8ff7beb6218 100644 --- a/arch/arm/mach-qcom/scm-boot.c +++ b/arch/arm/mach-qcom/scm-boot.c @@ -27,12 +27,12 @@ int scm_set_boot_addr(u32 addr, int flags) { struct { - unsigned int flags; - u32 addr; + __le32 flags; + __le32 addr; } cmd; - cmd.addr = addr; - cmd.flags = flags; + cmd.addr = cpu_to_le32(addr); + cmd.flags = cpu_to_le32(flags); return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR, &cmd, sizeof(cmd), NULL, 0); } diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c index a77349d34e78..1d9cf18c7091 100644 --- a/arch/arm/mach-qcom/scm.c +++ b/arch/arm/mach-qcom/scm.c @@ -61,11 +61,11 @@ static DEFINE_MUTEX(scm_lock); * to access the buffers in a safe manner. */ struct scm_command { - u32 len; - u32 buf_offset; - u32 resp_hdr_offset; - u32 id; - u32 buf[0]; + __le32 len; + __le32 buf_offset; + __le32 resp_hdr_offset; + __le32 id; + __le32 buf[0]; }; /** @@ -75,9 +75,9 @@ struct scm_command { * @is_complete: indicates if the command has finished processing */ struct scm_response { - u32 len; - u32 buf_offset; - u32 is_complete; + __le32 len; + __le32 buf_offset; + __le32 is_complete; }; /** @@ -95,12 +95,14 @@ static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size) struct scm_command *cmd; size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size + resp_size; + u32 offset; cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); if (cmd) { - cmd->len = len; - cmd->buf_offset = offsetof(struct scm_command, buf); - cmd->resp_hdr_offset = cmd->buf_offset + cmd_size; + cmd->len = cpu_to_le32(len); + offset = offsetof(struct scm_command, buf); + cmd->buf_offset = cpu_to_le32(offset); + cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size); } return cmd; } @@ -125,7 +127,7 @@ static inline void free_scm_command(struct scm_command *cmd) static inline struct scm_response *scm_command_to_response( const struct scm_command *cmd) { - return (void *)cmd + cmd->resp_hdr_offset; + return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); } /** @@ -147,7 +149,7 @@ static inline void *scm_get_command_buffer(const struct scm_command *cmd) */ static inline void *scm_get_response_buffer(const struct scm_response *rsp) { - return (void *)rsp + rsp->buf_offset; + return (void *)rsp + le32_to_cpu(rsp->buf_offset); } static int scm_remap_error(int err) @@ -259,7 +261,7 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, if (!cmd) return -ENOMEM; - cmd->id = (svc_id << 10) | cmd_id; + cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); if (cmd_buf) memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len); -- cgit From 195b278dbd9d0d88ff3c743d55148022f5738b95 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 21 Jan 2015 11:22:09 -0800 Subject: ARM: qcom: Drop unnecessary selects from ARCH_QCOM We don't need to force gpiolib on everyone given that it isn't required to actually boot the device and the multiplatform Kconfig already selects ARCH_WANT_OPTIONAL_GPIOLIB. CLKSRC_OF is already selected by CONFIG_ARCH_MULTIPLATFORM too, so we can drop that here. Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/arm/mach-qcom') diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index 29aa8e1970b0..48003ea652b9 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -1,10 +1,8 @@ menuconfig ARCH_QCOM bool "Qualcomm Support" if ARCH_MULTI_V7 - select ARCH_REQUIRE_GPIOLIB select ARCH_SUPPORTS_BIG_ENDIAN select ARM_GIC select ARM_AMBA - select CLKSRC_OF select PINCTRL select QCOM_SCM if SMP help -- cgit