On 1.02.2023 11:15, Johan Hovold wrote:
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:
of_icc_xlate_onecell: invalid index 0 cpu cpu0: error -EINVAL: error finding src node cpu cpu0: dev_pm_opp_of_find_icc_paths: Unable to get path0: -22 qcom-cpufreq-hw: probe of 18591000.cpufreq failed with error -22
Switch to using the new API where the provider is not registered until after it has been fully initialised.
Fixes: 5bc9900addaf ("interconnect: qcom: Add OSM L3 interconnect provider support") Cc: stable@vger.kernel.org # 5.7 Signed-off-by: Johan Hovold johan+linaro@kernel.org
Reviewed-by: Konrad Dybcio konrad.dybcio@linaro.org
Konrad
drivers/interconnect/qcom/osm-l3.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index 5fa171087425..3a1cbfe3e481 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -158,8 +158,8 @@ static int qcom_osm_l3_remove(struct platform_device *pdev) { struct qcom_osm_l3_icc_provider *qp = platform_get_drvdata(pdev);
- icc_provider_deregister(&qp->provider); icc_nodes_remove(&qp->provider);
- icc_provider_del(&qp->provider);
return 0; } @@ -245,14 +245,9 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) provider->set = qcom_osm_l3_set; provider->aggregate = icc_std_aggregate; provider->xlate = of_icc_xlate_onecell;
- INIT_LIST_HEAD(&provider->nodes); provider->data = data;
- ret = icc_provider_add(provider);
- if (ret) {
dev_err(&pdev->dev, "error adding interconnect provider\n");
return ret;
- }
- icc_provider_init(provider);
for (i = 0; i < num_nodes; i++) { size_t j; @@ -275,12 +270,15 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) } data->num_nodes = num_nodes;
- ret = icc_provider_register(provider);
- if (ret)
goto err;
- platform_set_drvdata(pdev, qp);
return 0; err: icc_nodes_remove(provider);
- icc_provider_del(provider);
return ret; }