diff options
author | Andy Gross <andy.gross@linaro.org> | 2017-04-04 15:32:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-12 06:41:21 -0400 |
commit | 007f0a2f2c0fcfa9ecef016c0910aebd0b784fdd (patch) | |
tree | 9b5ec2f51c3f7b6c3ecdd587da358d77de6d2bac | |
parent | 703f48a1c302f66e686535355092116ebaeccaad (diff) |
arm: kernel: Add SMC structure parameter
[ Upstream commit 680a0873e193bae666439f4b5e32c758e68f114c ]
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: Sasha Levin <alexander.levin@verizon.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | arch/arm/kernel/armksyms.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/smccc-call.S | 14 | ||||
-rw-r--r-- | arch/arm64/kernel/arm64ksyms.c | 4 | ||||
-rw-r--r-- | arch/arm64/kernel/asm-offsets.c | 7 | ||||
-rw-r--r-- | arch/arm64/kernel/smccc-call.S | 14 | ||||
-rw-r--r-- | include/linux/arm-smccc.h | 40 |
6 files changed, 57 insertions, 26 deletions
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); | |||
178 | #endif | 178 | #endif |
179 | 179 | ||
180 | #ifdef CONFIG_HAVE_ARM_SMCCC | 180 | #ifdef CONFIG_HAVE_ARM_SMCCC |
181 | EXPORT_SYMBOL(arm_smccc_smc); | 181 | EXPORT_SYMBOL(__arm_smccc_smc); |
182 | EXPORT_SYMBOL(arm_smccc_hvc); | 182 | EXPORT_SYMBOL(__arm_smccc_hvc); |
183 | #endif | 183 | #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) | |||
46 | /* | 46 | /* |
47 | * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, | 47 | * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, |
48 | * unsigned long a3, unsigned long a4, unsigned long a5, | 48 | * unsigned long a3, unsigned long a4, unsigned long a5, |
49 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) | 49 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
50 | * struct arm_smccc_quirk *quirk) | ||
50 | */ | 51 | */ |
51 | ENTRY(arm_smccc_smc) | 52 | ENTRY(__arm_smccc_smc) |
52 | SMCCC SMCCC_SMC | 53 | SMCCC SMCCC_SMC |
53 | ENDPROC(arm_smccc_smc) | 54 | ENDPROC(__arm_smccc_smc) |
54 | 55 | ||
55 | /* | 56 | /* |
56 | * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, | 57 | * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, |
57 | * unsigned long a3, unsigned long a4, unsigned long a5, | 58 | * unsigned long a3, unsigned long a4, unsigned long a5, |
58 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) | 59 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
60 | * struct arm_smccc_quirk *quirk) | ||
59 | */ | 61 | */ |
60 | ENTRY(arm_smccc_hvc) | 62 | ENTRY(__arm_smccc_hvc) |
61 | SMCCC SMCCC_HVC | 63 | SMCCC SMCCC_HVC |
62 | ENDPROC(arm_smccc_hvc) | 64 | 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); | |||
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | /* arm-smccc */ | 75 | /* arm-smccc */ |
76 | EXPORT_SYMBOL(arm_smccc_smc); | 76 | EXPORT_SYMBOL(__arm_smccc_smc); |
77 | EXPORT_SYMBOL(arm_smccc_hvc); | 77 | EXPORT_SYMBOL(__arm_smccc_hvc); |
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 4a2f0f0fef32..c58ddf8c4062 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c | |||
@@ -140,8 +140,11 @@ int main(void) | |||
140 | DEFINE(SLEEP_STACK_DATA_SYSTEM_REGS, offsetof(struct sleep_stack_data, system_regs)); | 140 | DEFINE(SLEEP_STACK_DATA_SYSTEM_REGS, offsetof(struct sleep_stack_data, system_regs)); |
141 | DEFINE(SLEEP_STACK_DATA_CALLEE_REGS, offsetof(struct sleep_stack_data, callee_saved_regs)); | 141 | DEFINE(SLEEP_STACK_DATA_CALLEE_REGS, offsetof(struct sleep_stack_data, callee_saved_regs)); |
142 | #endif | 142 | #endif |
143 | DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); | 143 | DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); |
144 | DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); | 144 | DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); |
145 | DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); | ||
146 | DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); | ||
147 | |||
145 | BLANK(); | 148 | BLANK(); |
146 | DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); | 149 | DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); |
147 | DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address)); | 150 | 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 @@ | |||
27 | /* | 27 | /* |
28 | * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, | 28 | * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, |
29 | * unsigned long a3, unsigned long a4, unsigned long a5, | 29 | * unsigned long a3, unsigned long a4, unsigned long a5, |
30 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) | 30 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
31 | * struct arm_smccc_quirk *quirk) | ||
31 | */ | 32 | */ |
32 | ENTRY(arm_smccc_smc) | 33 | ENTRY(__arm_smccc_smc) |
33 | SMCCC smc | 34 | SMCCC smc |
34 | ENDPROC(arm_smccc_smc) | 35 | ENDPROC(__arm_smccc_smc) |
35 | 36 | ||
36 | /* | 37 | /* |
37 | * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, | 38 | * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, |
38 | * unsigned long a3, unsigned long a4, unsigned long a5, | 39 | * unsigned long a3, unsigned long a4, unsigned long a5, |
39 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) | 40 | * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, |
41 | * struct arm_smccc_quirk *quirk) | ||
40 | */ | 42 | */ |
41 | ENTRY(arm_smccc_hvc) | 43 | ENTRY(__arm_smccc_hvc) |
42 | SMCCC hvc | 44 | SMCCC hvc |
43 | ENDPROC(arm_smccc_hvc) | 45 | 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 { | |||
72 | }; | 72 | }; |
73 | 73 | ||
74 | /** | 74 | /** |
75 | * arm_smccc_smc() - make SMC calls | 75 | * struct arm_smccc_quirk - Contains quirk information |
76 | * @id: quirk identification | ||
77 | * @state: quirk specific information | ||
78 | * @a6: Qualcomm quirk entry for returning post-smc call contents of a6 | ||
79 | */ | ||
80 | struct arm_smccc_quirk { | ||
81 | int id; | ||
82 | union { | ||
83 | unsigned long a6; | ||
84 | } state; | ||
85 | }; | ||
86 | |||
87 | /** | ||
88 | * __arm_smccc_smc() - make SMC calls | ||
76 | * @a0-a7: arguments passed in registers 0 to 7 | 89 | * @a0-a7: arguments passed in registers 0 to 7 |
77 | * @res: result values from registers 0 to 3 | 90 | * @res: result values from registers 0 to 3 |
91 | * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required. | ||
78 | * | 92 | * |
79 | * This function is used to make SMC calls following SMC Calling Convention. | 93 | * This function is used to make SMC calls following SMC Calling Convention. |
80 | * The content of the supplied param are copied to registers 0 to 7 prior | 94 | * The content of the supplied param are copied to registers 0 to 7 prior |
81 | * to the SMC instruction. The return values are updated with the content | 95 | * to the SMC instruction. The return values are updated with the content |
82 | * from register 0 to 3 on return from the SMC instruction. | 96 | * from register 0 to 3 on return from the SMC instruction. An optional |
97 | * quirk structure provides vendor specific behavior. | ||
83 | */ | 98 | */ |
84 | asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1, | 99 | asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1, |
85 | unsigned long a2, unsigned long a3, unsigned long a4, | 100 | unsigned long a2, unsigned long a3, unsigned long a4, |
86 | unsigned long a5, unsigned long a6, unsigned long a7, | 101 | unsigned long a5, unsigned long a6, unsigned long a7, |
87 | struct arm_smccc_res *res); | 102 | struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); |
88 | 103 | ||
89 | /** | 104 | /** |
90 | * arm_smccc_hvc() - make HVC calls | 105 | * __arm_smccc_hvc() - make HVC calls |
91 | * @a0-a7: arguments passed in registers 0 to 7 | 106 | * @a0-a7: arguments passed in registers 0 to 7 |
92 | * @res: result values from registers 0 to 3 | 107 | * @res: result values from registers 0 to 3 |
93 | * | 108 | * |
94 | * This function is used to make HVC calls following SMC Calling | 109 | * This function is used to make HVC calls following SMC Calling |
95 | * Convention. The content of the supplied param are copied to registers 0 | 110 | * Convention. The content of the supplied param are copied to registers 0 |
96 | * to 7 prior to the HVC instruction. The return values are updated with | 111 | * to 7 prior to the HVC instruction. The return values are updated with |
97 | * the content from register 0 to 3 on return from the HVC instruction. | 112 | * the content from register 0 to 3 on return from the HVC instruction. An |
113 | * optional quirk structure provides vendor specific behavior. | ||
98 | */ | 114 | */ |
99 | asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1, | 115 | asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, |
100 | unsigned long a2, unsigned long a3, unsigned long a4, | 116 | unsigned long a2, unsigned long a3, unsigned long a4, |
101 | unsigned long a5, unsigned long a6, unsigned long a7, | 117 | unsigned long a5, unsigned long a6, unsigned long a7, |
102 | struct arm_smccc_res *res); | 118 | struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); |
119 | |||
120 | #define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL) | ||
121 | |||
122 | #define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__) | ||
123 | |||
124 | #define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL) | ||
125 | |||
126 | #define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__) | ||
103 | 127 | ||
104 | #endif /*__LINUX_ARM_SMCCC_H*/ | 128 | #endif /*__LINUX_ARM_SMCCC_H*/ |