perf/imx_ddr: Fix cpu hotplug state cleanup
authorLeonard Crestez <leonard.crestez@nxp.com>
Tue, 14 Jan 2020 20:25:46 +0000 (22:25 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Feb 2020 07:36:49 +0000 (08:36 +0100)
[ Upstream commit 9ee68b314e9aa63ed11b98beb8a68810b8234dcf ]

This driver allocates a dynamic cpu hotplug state but never releases it.
If reloaded in a loop it will quickly trigger a WARN message:

"No more dynamic states available for CPU hotplug"

Fix by calling cpuhp_remove_multi_state on remove like several other
perf pmu drivers.

Also fix the cleanup logic on probe error paths: add the missing
cpuhp_remove_multi_state call and properly check the return value from
cpuhp_state_add_instant_nocalls.

Fixes: 9a66d36cc7ac ("drivers/perf: imx_ddr: Add DDR performance counter support to perf")
Acked-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/perf/fsl_imx8_ddr_perf.c

index 2a3966d..0e51baa 100644 (file)
@@ -572,13 +572,17 @@ static int ddr_perf_probe(struct platform_device *pdev)
 
        if (ret < 0) {
                dev_err(&pdev->dev, "cpuhp_setup_state_multi failed\n");
-               goto ddr_perf_err;
+               goto cpuhp_state_err;
        }
 
        pmu->cpuhp_state = ret;
 
        /* Register the pmu instance for cpu hotplug */
-       cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+       ret = cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+       if (ret) {
+               dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
+               goto cpuhp_instance_err;
+       }
 
        /* Request irq */
        irq = of_irq_get(np, 0);
@@ -612,9 +616,10 @@ static int ddr_perf_probe(struct platform_device *pdev)
        return 0;
 
 ddr_perf_err:
-       if (pmu->cpuhp_state)
-               cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
-
+       cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+cpuhp_instance_err:
+       cpuhp_remove_multi_state(pmu->cpuhp_state);
+cpuhp_state_err:
        ida_simple_remove(&ddr_ida, pmu->id);
        dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret);
        return ret;
@@ -625,6 +630,7 @@ static int ddr_perf_remove(struct platform_device *pdev)
        struct ddr_pmu *pmu = platform_get_drvdata(pdev);
 
        cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+       cpuhp_remove_multi_state(pmu->cpuhp_state);
        irq_set_affinity_hint(pmu->irq, NULL);
 
        perf_pmu_unregister(&pmu->pmu);