diff options
author | Georgi Djakov <georgi.djakov@linaro.org> | 2019-11-18 16:20:10 +0200 |
---|---|---|
committer | Georgi Djakov <georgi.djakov@linaro.org> | 2019-11-18 17:35:08 +0200 |
commit | 71cf50f05ee39c8300b847faea22eaf7ecb7f18b (patch) | |
tree | 11646079a0c9a39e0ad8ad12873451a18bf02531 | |
parent | 33c717d7f3e6b9839ab4f4b0d5bdb8679888c6b7 (diff) |
interconnect: qcom: qcs404: Walk the list safely on node removal
As we will remove items off the list using list_del(), we need to use a safe
version of the list_for_each_entry().
In addition to the above, instead of duplicating the code, call qnoc_remove()
directly from the probe function error path.
Fixes: 5e4e6c4d3ae0 ("interconnect: qcom: Add QCS404 interconnect provider driver")
Reported-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
Cc: stable@vger.kernel.org # v5.4
-rw-r--r-- | drivers/interconnect/qcom/qcs404.c | 37 |
1 files changed, 16 insertions, 21 deletions
diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c index b4966d8f3348..c6008281380f 100644 --- a/drivers/interconnect/qcom/qcs404.c +++ b/drivers/interconnect/qcom/qcs404.c @@ -406,6 +406,21 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) return 0; } +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + struct icc_provider *provider = &qp->provider; + struct icc_node *n, *tmp; + + list_for_each_entry_safe_reverse(n, tmp, &provider->nodes, node_list) { + icc_node_del(n); + icc_node_destroy(n->id); + } + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + + return icc_provider_del(provider); +} + static int qnoc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -494,31 +509,11 @@ static int qnoc_probe(struct platform_device *pdev) return 0; err: - list_for_each_entry(node, &provider->nodes, node_list) { - icc_node_del(node); - icc_node_destroy(node->id); - } - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); - icc_provider_del(provider); + qnoc_remove(pdev); return ret; } -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - struct icc_provider *provider = &qp->provider; - struct icc_node *n; - - list_for_each_entry(n, &provider->nodes, node_list) { - icc_node_del(n); - icc_node_destroy(n->id); - } - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); - - return icc_provider_del(provider); -} - static const struct of_device_id qcs404_noc_of_match[] = { { .compatible = "qcom,qcs404-bimc", .data = &qcs404_bimc }, { .compatible = "qcom,qcs404-pcnoc", .data = &qcs404_pcnoc }, |