Every available DT child node gets an extra reference taken with of_node_get() for the corresponding master adapter's of_node, but this reference is only released when i2c_add_adapter() fails or on the success path via cci_remove(). All probe failures before the adapters are registered, memory mapping, clock setup, interrupt and reset/init errors, return without releasing the references. Drop the node reference taken for each configured master on the common probe error paths and release the remaining references in the error_i2c path via the shared cleanup label. Fixes: 02a4a69667a2 ("i2c: qcom-cci: don't put a device tree node before i2c_add_adapter()") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang --- drivers/i2c/busses/i2c-qcom-cci.c | 32 ++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index f3ccfbbc4bea..295d5029bd68 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -575,21 +575,26 @@ static int cci_probe(struct platform_device *pdev) /* Memory */ cci->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); - if (IS_ERR(cci->base)) - return PTR_ERR(cci->base); + if (IS_ERR(cci->base)) { + ret = PTR_ERR(cci->base); + goto err_of_node; + } /* Clocks */ ret = devm_clk_bulk_get_all(dev, &cci->clocks); - if (ret < 0) - return dev_err_probe(dev, ret, "failed to get clocks\n"); - else if (!ret) - return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); + if (ret < 0) { + ret = dev_err_probe(dev, ret, "failed to get clocks\n"); + goto err_of_node; + } else if (!ret) { + ret = dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); + goto err_of_node; + } cci->nclocks = ret; ret = cci_enable_clocks(cci); if (ret < 0) - return ret; + goto err_of_node; /* Interrupt */ @@ -625,10 +630,8 @@ static int cci_probe(struct platform_device *pdev) continue; ret = i2c_add_adapter(&cci->master[i].adap); - if (ret < 0) { - of_node_put(cci->master[i].adap.dev.of_node); + if (ret < 0) goto error_i2c; - } } return 0; @@ -638,15 +641,18 @@ static int cci_probe(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(dev); for (--i ; i >= 0; i--) { - if (cci->master[i].cci) { + if (cci->master[i].cci) i2c_del_adapter(&cci->master[i].adap); - of_node_put(cci->master[i].adap.dev.of_node); - } } error: disable_irq(cci->irq); disable_clocks: cci_disable_clocks(cci); +err_of_node: + for (i = 0; i < cci->data->num_masters; i++) { + if (cci->master[i].cci) + of_node_put(cci->master[i].adap.dev.of_node); + } return ret; } -- 2.34.1