mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 16:53:20 -04:00
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>
This commit is contained in:
committed by
Bjorn Andersson
parent
bc3c98b776
commit
d9603a7790
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user