firmware: qcom: scm: Fix __scm and waitq completion variable initialization
authorMukesh Ojha <quic_mojha@quicinc.com>
Thu, 21 Mar 2024 15:24:02 +0000 (20:54 +0530)
committerBjorn Andersson <andersson@kernel.org>
Sun, 21 Apr 2024 17:08:06 +0000 (12:08 -0500)
It is possible qcom_scm_is_available() gives wrong indication that
if __scm is initialized while __scm->dev is not and similar issue
is also possible with __scm->waitq_comp.

Fix this appropriately by the use of release barrier and read barrier
that will make sure if __scm is initialized so, is all of its field
variable.

Fixes: d0f6fa7ba2d6 ("firmware: qcom: scm: Convert SCM to platform driver")
Fixes: 6bf325992236 ("firmware: qcom: scm: Add wait-queue handling logic")
Signed-off-by: Mukesh Ojha <quic_mojha@quicinc.com>
Link: https://lore.kernel.org/r/1711034642-22860-4-git-send-email-quic_mojha@quicinc.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
drivers/firmware/qcom/qcom_scm.c

index d9cee441d81c1322b81442d535ba61ec359ae628..84aa30b5a19e652582657b223f48eac137490223 100644 (file)
@@ -1737,7 +1737,7 @@ static int qcom_scm_qseecom_init(struct qcom_scm *scm)
  */
 bool qcom_scm_is_available(void)
 {
-       return !!__scm;
+       return !!READ_ONCE(__scm);
 }
 EXPORT_SYMBOL_GPL(qcom_scm_is_available);
 
@@ -1818,10 +1818,12 @@ static int qcom_scm_probe(struct platform_device *pdev)
        if (!scm)
                return -ENOMEM;
 
+       scm->dev = &pdev->dev;
        ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr);
        if (ret < 0)
                return ret;
 
+       init_completion(&scm->waitq_comp);
        mutex_init(&scm->scm_bw_lock);
 
        scm->path = devm_of_icc_get(&pdev->dev, NULL);
@@ -1853,10 +1855,8 @@ static int qcom_scm_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       __scm = scm;
-       __scm->dev = &pdev->dev;
-
-       init_completion(&__scm->waitq_comp);
+       /* Let all above stores be available after this */
+       smp_store_release(&__scm, scm);
 
        irq = platform_get_irq_optional(pdev, 0);
        if (irq < 0) {