aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgi Djakov <georgi.djakov@linaro.org>2019-11-18 16:20:10 +0200
committerGeorgi Djakov <georgi.djakov@linaro.org>2019-11-18 17:35:08 +0200
commit71cf50f05ee39c8300b847faea22eaf7ecb7f18b (patch)
tree11646079a0c9a39e0ad8ad12873451a18bf02531
parent33c717d7f3e6b9839ab4f4b0d5bdb8679888c6b7 (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.c37
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 },