Skip to content

Commit 82bcd08

Browse files
Andy Grosswildea01
authored andcommitted
firmware: qcom: scm: Fix interrupted SCM calls
This patch adds a Qualcomm specific quirk to the arm_smccc_smc call. On Qualcomm ARM64 platforms, the SMC call can return before it has completed. If this occurs, the call can be restarted, but it requires using the returned session ID value from the interrupted SMC call. The quirk stores off the session ID from the interrupted call in the quirk structure so that it can be used by the caller. This patch folds in a fix given by Sricharan R: https://lkml.org/lkml/2016/9/28/272 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>
1 parent 680a087 commit 82bcd08

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

arch/arm64/kernel/smccc-call.S

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*
1313
*/
1414
#include <linux/linkage.h>
15+
#include <linux/arm-smccc.h>
1516
#include <asm/asm-offsets.h>
1617

1718
.macro SMCCC instr
@@ -20,7 +21,13 @@
2021
ldr x4, [sp]
2122
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
2223
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
23-
ret
24+
ldr x4, [sp, #8]
25+
cbz x4, 1f /* no quirk structure */
26+
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
27+
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
28+
b.ne 1f
29+
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
30+
1: ret
2431
.cfi_endproc
2532
.endm
2633

drivers/firmware/qcom_scm-64.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
9191
dma_addr_t args_phys = 0;
9292
void *args_virt = NULL;
9393
size_t alloc_len;
94+
struct arm_smccc_quirk quirk = {.id = ARM_SMCCC_QUIRK_QCOM_A6};
9495

9596
if (unlikely(arglen > N_REGISTER_ARGS)) {
9697
alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
@@ -131,10 +132,16 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
131132
qcom_smccc_convention,
132133
ARM_SMCCC_OWNER_SIP, fn_id);
133134

135+
quirk.state.a6 = 0;
136+
134137
do {
135-
arm_smccc_smc(cmd, desc->arginfo, desc->args[0],
136-
desc->args[1], desc->args[2], x5, 0, 0,
137-
res);
138+
arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
139+
desc->args[1], desc->args[2], x5,
140+
quirk.state.a6, 0, res, &quirk);
141+
142+
if (res->a0 == QCOM_SCM_INTERRUPTED)
143+
cmd = res->a0;
144+
138145
} while (res->a0 == QCOM_SCM_INTERRUPTED);
139146

140147
mutex_unlock(&qcom_scm_lock);

include/linux/arm-smccc.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@
1414
#ifndef __LINUX_ARM_SMCCC_H
1515
#define __LINUX_ARM_SMCCC_H
1616

17-
#include <linux/linkage.h>
18-
#include <linux/types.h>
19-
2017
/*
2118
* This file provides common defines for ARM SMC Calling Convention as
2219
* specified in
@@ -60,6 +57,13 @@
6057
#define ARM_SMCCC_OWNER_TRUSTED_OS 50
6158
#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
6259

60+
#define ARM_SMCCC_QUIRK_NONE 0
61+
#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */
62+
63+
#ifndef __ASSEMBLY__
64+
65+
#include <linux/linkage.h>
66+
#include <linux/types.h>
6367
/**
6468
* struct arm_smccc_res - Result from SMC/HVC call
6569
* @a0-a3 result values from registers 0 to 3
@@ -125,4 +129,5 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
125129

126130
#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
127131

132+
#endif /*__ASSEMBLY__*/
128133
#endif /*__LINUX_ARM_SMCCC_H*/

0 commit comments

Comments
 (0)