[PATCH v4 03/19] firmware: qcom: scm: Fix missing smp_load_acquire()
From: Mukesh Ojha
Date: Wed Jun 24 2026 - 15:09:04 EST
__scm is published in qcom_scm_probe() with smp_store_release()
but qcom_scm_set_download_mode() reads it directly without
smp_load_acquire(), creating a potential ordering violation where a
CPU could observe a stale or partially initialised __scm pointer.
Use smp_load_acquire() to acquire __scm in the
qcom_scm_set_download_mode() function.
Signed-off-by: Mukesh Ojha <mukesh.ojha@xxxxxxxxxxxxxxxx>
---
drivers/firmware/qcom/qcom_scm.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 6b601a4b89db..b78da40a4d60 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -551,23 +551,23 @@ static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val
return qcom_scm_io_writel(addr, new);
}
-static void qcom_scm_set_download_mode(u32 dload_mode)
+static void qcom_scm_set_download_mode(struct qcom_scm *scm, u32 dload_mode)
{
int ret = 0;
- if (__scm->dload_mode_addr) {
- ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK,
+ if (scm->dload_mode_addr) {
+ ret = qcom_scm_io_rmw(scm->dload_mode_addr, QCOM_DLOAD_MASK,
FIELD_PREP(QCOM_DLOAD_MASK, dload_mode));
- } else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT,
+ } else if (__qcom_scm_is_call_available(scm->dev, QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_DLOAD_MODE)) {
- ret = __qcom_scm_set_dload_mode(__scm->dev, !!dload_mode);
+ ret = __qcom_scm_set_dload_mode(scm->dev, !!dload_mode);
} else if (dload_mode) {
- dev_err(__scm->dev,
+ dev_err(scm->dev,
"No available mechanism for setting download mode\n");
}
if (ret)
- dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
+ dev_err(scm->dev, "failed to set download mode: %d\n", ret);
}
/**
@@ -2705,6 +2705,7 @@ static int get_download_mode(char *buffer, const struct kernel_param *kp)
static int set_download_mode(const char *val, const struct kernel_param *kp)
{
+ struct qcom_scm *scm;
bool tmp;
int ret;
@@ -2720,8 +2721,10 @@ static int set_download_mode(const char *val, const struct kernel_param *kp)
}
download_mode = ret;
- if (__scm)
- qcom_scm_set_download_mode(download_mode);
+ /* Pairs with smp_store_release() in qcom_scm_probe(). */
+ scm = smp_load_acquire(&__scm);
+ if (scm)
+ qcom_scm_set_download_mode(scm, download_mode);
return 0;
}
@@ -2842,7 +2845,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
* will cause the boot stages to enter download mode, unless
* disabled below by a clean shutdown/reboot.
*/
- qcom_scm_set_download_mode(download_mode);
+ qcom_scm_set_download_mode(scm, download_mode);
/*
* Disable SDI if indicated by DT that it is enabled by default.
@@ -2875,7 +2878,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
static void qcom_scm_shutdown(struct platform_device *pdev)
{
/* Clean shutdown, disable download mode to allow normal restart */
- qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
+ qcom_scm_set_download_mode(__scm, QCOM_DLOAD_NODUMP);
}
static const struct of_device_id qcom_scm_dt_match[] = {
--
2.53.0