]> git.baikalelectronics.ru Git - kernel.git/commitdiff
interconnect: qcom: rpm: fix registration race
authorJohan Hovold <johan+linaro@kernel.org>
Mon, 6 Mar 2023 07:56:36 +0000 (08:56 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Mar 2023 12:33:57 +0000 (13:33 +0100)
commit 2163b134f5953f88cf75d179d88b3a33cf6ba233 upstream.

The current interconnect provider registration interface is inherently
racy as nodes are not added until the after adding the provider. This
can specifically cause racing DT lookups to fail.

Switch to using the new API where the provider is not registered until
after it has been fully initialised.

Fixes: 7834eb78d031 ("interconnect: qcom: Consolidate interconnect RPM support")
Fixes: d3a5d586798c ("interconnect: qcom: Add MSM8916 interconnect provider driver")
Cc: stable@vger.kernel.org # 5.7
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Reviewed-by: Jun Nie <jun.nie@linaro.org>
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
Link: https://lore.kernel.org/r/20230306075651.2449-9-johan+linaro@kernel.org
Signed-off-by: Georgi Djakov <djakov@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/interconnect/qcom/icc-rpm.c

index b00df2048b7f19c1aee993824869bf4e0b0767c5..6a9e6b563320bb02a49ef9a3eb23b1f28d97fb93 100644 (file)
@@ -506,7 +506,6 @@ regmap_done:
        }
 
        provider = &qp->provider;
-       INIT_LIST_HEAD(&provider->nodes);
        provider->dev = dev;
        provider->set = qcom_icc_set;
        provider->pre_aggregate = qcom_icc_pre_bw_aggregate;
@@ -514,12 +513,7 @@ regmap_done:
        provider->xlate_extended = qcom_icc_xlate_extended;
        provider->data = data;
 
-       ret = icc_provider_add(provider);
-       if (ret) {
-               dev_err(dev, "error adding interconnect provider: %d\n", ret);
-               clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-               return ret;
-       }
+       icc_provider_init(provider);
 
        for (i = 0; i < num_nodes; i++) {
                size_t j;
@@ -527,7 +521,7 @@ regmap_done:
                node = icc_node_create(qnodes[i]->id);
                if (IS_ERR(node)) {
                        ret = PTR_ERR(node);
-                       goto err;
+                       goto err_remove_nodes;
                }
 
                node->name = qnodes[i]->name;
@@ -541,20 +535,26 @@ regmap_done:
        }
        data->num_nodes = num_nodes;
 
+       ret = icc_provider_register(provider);
+       if (ret)
+               goto err_remove_nodes;
+
        platform_set_drvdata(pdev, qp);
 
        /* Populate child NoC devices if any */
        if (of_get_child_count(dev->of_node) > 0) {
                ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
                if (ret)
-                       goto err;
+                       goto err_deregister_provider;
        }
 
        return 0;
-err:
+
+err_deregister_provider:
+       icc_provider_deregister(provider);
+err_remove_nodes:
        icc_nodes_remove(provider);
        clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-       icc_provider_del(provider);
 
        return ret;
 }
@@ -564,9 +564,9 @@ int qnoc_remove(struct platform_device *pdev)
 {
        struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
 
+       icc_provider_deregister(&qp->provider);
        icc_nodes_remove(&qp->provider);
        clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-       icc_provider_del(&qp->provider);
 
        return 0;
 }