6.16-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski bartosz.golaszewski@linaro.org
commit 7ab36b51c6bee56e1a1939063dd10d602fe49d13 upstream.
There's a subtle race in the SCM driver: we assign the __scm pointer before requesting the waitqueue interrupt. Assigning __scm marks the SCM API as ready to accept calls. It's possible that a user makes a call right after we set __scm and the firmware raises an interrupt before the driver's ready to service it. Move the __scm assignment after we request the interrupt.
This has the added benefit of allowing us to drop the goto label.
Reviewed-by: Konrad Dybcio konrad.dybcio@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski bartosz.golaszewski@linaro.org Link: https://lore.kernel.org/r/20250630-qcom-scm-race-v2-4-fa3851c98611@linaro.or... Signed-off-by: Bjorn Andersson andersson@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/firmware/qcom/qcom_scm.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-)
--- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -2276,29 +2276,27 @@ static int qcom_scm_probe(struct platfor return dev_err_probe(scm->dev, PTR_ERR(scm->mempool), "Failed to create the SCM memory pool\n");
+ irq = platform_get_irq_optional(pdev, 0); + if (irq < 0) { + if (irq != -ENXIO) + return irq; + } else { + ret = devm_request_threaded_irq(scm->dev, irq, NULL, qcom_scm_irq_handler, + IRQF_ONESHOT, "qcom-scm", scm); + if (ret < 0) + return dev_err_probe(scm->dev, ret, + "Failed to request qcom-scm irq\n"); + } + /* * Paired with smp_load_acquire() in qcom_scm_is_available(). * * This marks the SCM API as ready to accept user calls and can only - * be called after the TrustZone memory pool is initialized. + * be called after the TrustZone memory pool is initialized and the + * waitqueue interrupt requested. */ smp_store_release(&__scm, scm);
- irq = platform_get_irq_optional(pdev, 0); - if (irq < 0) { - if (irq != -ENXIO) { - ret = irq; - goto err; - } - } else { - ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler, - IRQF_ONESHOT, "qcom-scm", __scm); - if (ret < 0) { - dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n"); - goto err; - } - } - __get_convention();
/* @@ -2328,12 +2326,6 @@ static int qcom_scm_probe(struct platfor WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
return 0; - -err: - /* Paired with smp_load_acquire() in qcom_scm_is_available(). */ - smp_store_release(&__scm, NULL); - - return ret; }
static void qcom_scm_shutdown(struct platform_device *pdev)