aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMukesh Ojha <mukesh.ojha@oss.qualcomm.com>2026-06-25 00:38:14 +0530
committerBjorn Andersson <andersson@kernel.org>2026-07-13 09:43:13 -0500
commitd9603a7790d164657a51997d7265ca845bee78bf (patch)
tree770d66eef670636105a44e2c0a86d8283923b9ac
parentdt-bindings: firmware: qcom,scm: Add minidump SRAM property (diff)
firmware: qcom: scm: Fix missing smp_load_acquire()
__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@oss.qualcomm.com> Link: https://lore.kernel.org/r/20260624190830.3131112-4-mukesh.ojha@oss.qualcomm.com Signed-off-by: Bjorn Andersson <andersson@kernel.org>
-rw-r--r--drivers/firmware/qcom/qcom_scm.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index bfc5e6723eb9..2abac54ed1f3 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -534,23 +534,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);
}
struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
@@ -2673,6 +2673,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;
@@ -2688,8 +2689,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;
}
@@ -2815,7 +2818,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.
@@ -2848,7 +2851,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);
qcom_pas_ops_unregister();
}