| From 475869b9160685711beb4e4c62dbbe3b66481951 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 14 Jan 2020 22:25:46 +0200 |
| Subject: perf/imx_ddr: Fix cpu hotplug state cleanup |
| |
| From: Leonard Crestez <leonard.crestez@nxp.com> |
| |
| [ 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 | 16 +++++++++++----- |
| 1 file changed, 11 insertions(+), 5 deletions(-) |
| |
| diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c |
| index 2a3966d059e70..0e51baa48b149 100644 |
| --- a/drivers/perf/fsl_imx8_ddr_perf.c |
| +++ b/drivers/perf/fsl_imx8_ddr_perf.c |
| @@ -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); |
| -- |
| 2.20.1 |
| |