| From c2b77e459a257940883f3b01f5ac127811cc5784 Mon Sep 17 00:00:00 2001 |
| From: Andy Gross <andy.gross@linaro.org> |
| Date: Wed, 1 Feb 2017 11:28:27 -0600 |
| Subject: [PATCH] arm: kernel: Add SMC structure parameter |
| |
| commit 680a0873e193bae666439f4b5e32c758e68f114c upstream. |
| |
| This patch adds a quirk parameter to the arm_smccc_(smc/hvc) calls. |
| The quirk structure allows for specialized SMC operations due to SoC |
| specific requirements. The current arm_smccc_(smc/hvc) is renamed and |
| macros are used instead to specify the standard arm_smccc_(smc/hvc) or |
| the arm_smccc_(smc/hvc)_quirk function. |
| |
| This patch and partial implementation was suggested by Will Deacon. |
| |
| Signed-off-by: Andy Gross <andy.gross@linaro.org> |
| Reviewed-by: Will Deacon <will.deacon@arm.com> |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c |
| index 7e45f69a0ddc..8e8d20cdbce7 100644 |
| --- a/arch/arm/kernel/armksyms.c |
| +++ b/arch/arm/kernel/armksyms.c |
| @@ -178,6 +178,6 @@ EXPORT_SYMBOL(__pv_offset); |
| #endif |
| |
| #ifdef CONFIG_HAVE_ARM_SMCCC |
| -EXPORT_SYMBOL(arm_smccc_smc); |
| -EXPORT_SYMBOL(arm_smccc_hvc); |
| +EXPORT_SYMBOL(__arm_smccc_smc); |
| +EXPORT_SYMBOL(__arm_smccc_hvc); |
| #endif |
| diff --git a/arch/arm/kernel/smccc-call.S b/arch/arm/kernel/smccc-call.S |
| index 2e48b674aab1..e5d43066b889 100644 |
| --- a/arch/arm/kernel/smccc-call.S |
| +++ b/arch/arm/kernel/smccc-call.S |
| @@ -46,17 +46,19 @@ UNWIND( .fnend) |
| /* |
| * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, |
| * unsigned long a3, unsigned long a4, unsigned long a5, |
| - * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) |
| + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
| + * struct arm_smccc_quirk *quirk) |
| */ |
| -ENTRY(arm_smccc_smc) |
| +ENTRY(__arm_smccc_smc) |
| SMCCC SMCCC_SMC |
| -ENDPROC(arm_smccc_smc) |
| +ENDPROC(__arm_smccc_smc) |
| |
| /* |
| * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, |
| * unsigned long a3, unsigned long a4, unsigned long a5, |
| - * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) |
| + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
| + * struct arm_smccc_quirk *quirk) |
| */ |
| -ENTRY(arm_smccc_hvc) |
| +ENTRY(__arm_smccc_hvc) |
| SMCCC SMCCC_HVC |
| -ENDPROC(arm_smccc_hvc) |
| +ENDPROC(__arm_smccc_hvc) |
| diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c |
| index 78f368039c79..e9c4dc9e0ada 100644 |
| --- a/arch/arm64/kernel/arm64ksyms.c |
| +++ b/arch/arm64/kernel/arm64ksyms.c |
| @@ -73,5 +73,5 @@ NOKPROBE_SYMBOL(_mcount); |
| #endif |
| |
| /* arm-smccc */ |
| -EXPORT_SYMBOL(arm_smccc_smc); |
| -EXPORT_SYMBOL(arm_smccc_hvc); |
| +EXPORT_SYMBOL(__arm_smccc_smc); |
| +EXPORT_SYMBOL(__arm_smccc_hvc); |
| diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c |
| index 05070b72fc28..ad0e126317ae 100644 |
| --- a/arch/arm64/kernel/asm-offsets.c |
| +++ b/arch/arm64/kernel/asm-offsets.c |
| @@ -139,8 +139,11 @@ int main(void) |
| DEFINE(SLEEP_STACK_DATA_SYSTEM_REGS, offsetof(struct sleep_stack_data, system_regs)); |
| DEFINE(SLEEP_STACK_DATA_CALLEE_REGS, offsetof(struct sleep_stack_data, callee_saved_regs)); |
| #endif |
| - DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); |
| - DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); |
| + DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); |
| + DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); |
| + DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); |
| + DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); |
| + |
| BLANK(); |
| DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); |
| DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address)); |
| diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S |
| index ae0496fa4235..ba60a8cb07d2 100644 |
| --- a/arch/arm64/kernel/smccc-call.S |
| +++ b/arch/arm64/kernel/smccc-call.S |
| @@ -27,17 +27,19 @@ |
| /* |
| * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, |
| * unsigned long a3, unsigned long a4, unsigned long a5, |
| - * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) |
| + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
| + * struct arm_smccc_quirk *quirk) |
| */ |
| -ENTRY(arm_smccc_smc) |
| +ENTRY(__arm_smccc_smc) |
| SMCCC smc |
| -ENDPROC(arm_smccc_smc) |
| +ENDPROC(__arm_smccc_smc) |
| |
| /* |
| * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, |
| * unsigned long a3, unsigned long a4, unsigned long a5, |
| - * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) |
| + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
| + * struct arm_smccc_quirk *quirk) |
| */ |
| -ENTRY(arm_smccc_hvc) |
| +ENTRY(__arm_smccc_hvc) |
| SMCCC hvc |
| -ENDPROC(arm_smccc_hvc) |
| +ENDPROC(__arm_smccc_hvc) |
| diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h |
| index b5abfda80465..c66f8ae94b5a 100644 |
| --- a/include/linux/arm-smccc.h |
| +++ b/include/linux/arm-smccc.h |
| @@ -72,33 +72,57 @@ struct arm_smccc_res { |
| }; |
| |
| /** |
| - * arm_smccc_smc() - make SMC calls |
| + * struct arm_smccc_quirk - Contains quirk information |
| + * @id: quirk identification |
| + * @state: quirk specific information |
| + * @a6: Qualcomm quirk entry for returning post-smc call contents of a6 |
| + */ |
| +struct arm_smccc_quirk { |
| + int id; |
| + union { |
| + unsigned long a6; |
| + } state; |
| +}; |
| + |
| +/** |
| + * __arm_smccc_smc() - make SMC calls |
| * @a0-a7: arguments passed in registers 0 to 7 |
| * @res: result values from registers 0 to 3 |
| + * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required. |
| * |
| * This function is used to make SMC calls following SMC Calling Convention. |
| * The content of the supplied param are copied to registers 0 to 7 prior |
| * to the SMC instruction. The return values are updated with the content |
| - * from register 0 to 3 on return from the SMC instruction. |
| + * from register 0 to 3 on return from the SMC instruction. An optional |
| + * quirk structure provides vendor specific behavior. |
| */ |
| -asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1, |
| +asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1, |
| unsigned long a2, unsigned long a3, unsigned long a4, |
| unsigned long a5, unsigned long a6, unsigned long a7, |
| - struct arm_smccc_res *res); |
| + struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); |
| |
| /** |
| - * arm_smccc_hvc() - make HVC calls |
| + * __arm_smccc_hvc() - make HVC calls |
| * @a0-a7: arguments passed in registers 0 to 7 |
| * @res: result values from registers 0 to 3 |
| * |
| * This function is used to make HVC calls following SMC Calling |
| * Convention. The content of the supplied param are copied to registers 0 |
| * to 7 prior to the HVC instruction. The return values are updated with |
| - * the content from register 0 to 3 on return from the HVC instruction. |
| + * the content from register 0 to 3 on return from the HVC instruction. An |
| + * optional quirk structure provides vendor specific behavior. |
| */ |
| -asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1, |
| +asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, |
| unsigned long a2, unsigned long a3, unsigned long a4, |
| unsigned long a5, unsigned long a6, unsigned long a7, |
| - struct arm_smccc_res *res); |
| + struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); |
| + |
| +#define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL) |
| + |
| +#define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__) |
| + |
| +#define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL) |
| + |
| +#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__) |
| |
| #endif /*__LINUX_ARM_SMCCC_H*/ |
| -- |
| 2.12.0 |
| |