From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966460AbcLVUTi (ORCPT ); Thu, 22 Dec 2016 15:19:38 -0500 Received: from terminus.zytor.com ([198.137.202.10]:42416 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754228AbcLVUTg (ORCPT ); Thu, 22 Dec 2016 15:19:36 -0500 Date: Thu, 22 Dec 2016 12:18:55 -0800 From: tip-bot for Thomas Gleixner Message-ID: Cc: tglx@linutronix.de, frank.li@nxp.com, bigeasy@linutronix.de, hpa@zytor.com, zhengyu.shen@nxp.com, shawnguo@kernel.org, linux-kernel@vger.kernel.org, mingo@kernel.org, peterz@infradead.org Reply-To: zhengyu.shen@nxp.com, shawnguo@kernel.org, hpa@zytor.com, linux-kernel@vger.kernel.org, frank.li@nxp.com, tglx@linutronix.de, bigeasy@linutronix.de, mingo@kernel.org, peterz@infradead.org In-Reply-To: <20161221192111.596204211@linutronix.de> References: <20161221192111.596204211@linutronix.de> To: linux-tip-commits@vger.kernel.org Subject: [tip:smp/urgent] ARM/imx/mmcd: Fix broken cpu hotplug handling Git-Commit-ID: a5d3bb6a5ba9727a02b328a249652f3ea655a064 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: a5d3bb6a5ba9727a02b328a249652f3ea655a064 Gitweb: http://git.kernel.org/tip/a5d3bb6a5ba9727a02b328a249652f3ea655a064 Author: Thomas Gleixner AuthorDate: Wed, 21 Dec 2016 20:19:48 +0100 Committer: Thomas Gleixner CommitDate: Thu, 22 Dec 2016 11:37:53 +0100 ARM/imx/mmcd: Fix broken cpu hotplug handling The cpu hotplug support of this perf driver is broken in several ways: 1) It adds a instance before setting up the state. 2) The state for the instance is different from the state of the callback. It's just a randomly chosen state. 3) The instance registration is not error checked so nobody noticed that the call can never succeed. 4) The state for the multi install callbacks is chosen randomly and overwrites existing state. This is now prevented by the core code so the call is guaranteed to fail. 5) The error exit path in the init function leaves the instance registered and then frees the memory which contains the enqueued hlist node. 6) The remove function is removing the state and not the instance. Fix it by: - Setting up the state before adding instances. Use a dynamically allocated state for it. - Installing instances after the state has been set up - Removing the instance in the error path before freeing memory - Removing the instance not the state in the driver remove callback While at is use raw_cpu_processor_id(), because cpu_processor_id() cannot be used in preemptible context, and set the driver data after successful registration of the pmu. Signed-off-by: Thomas Gleixner Acked-by: Shawn Guo Cc: Peter Zijlstra Cc: Sebastian Siewior Cc: Frank Li Cc: Zhengyu Shen Link: http://lkml.kernel.org/r/20161221192111.596204211@linutronix.de Signed-off-by: Thomas Gleixner --- arch/arm/mach-imx/mmdc.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index ba96bf9..6991577 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -60,6 +60,7 @@ #define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu) +static enum cpuhp_state cpuhp_mmdc_state; static int ddr_type; struct fsl_mmdc_devtype_data { @@ -451,8 +452,8 @@ static int imx_mmdc_remove(struct platform_device *pdev) { struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev); + cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node); perf_pmu_unregister(&pmu_mmdc->pmu); - cpuhp_remove_state_nocalls(CPUHP_ONLINE); kfree(pmu_mmdc); return 0; } @@ -472,6 +473,18 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b return -ENOMEM; } + /* The first instance registers the hotplug state */ + if (!cpuhp_mmdc_state) { + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + "perf/arm/mmdc:online", NULL, + mmdc_pmu_offline_cpu); + if (ret < 0) { + pr_err("cpuhp_setup_state_multi failed\n"); + goto pmu_free; + } + cpuhp_mmdc_state = ret; + } + mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev); if (mmdc_num == 0) name = "mmdc"; @@ -485,26 +498,23 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b HRTIMER_MODE_REL); pmu_mmdc->hrtimer.function = mmdc_pmu_timer_handler; - cpuhp_state_add_instance_nocalls(CPUHP_ONLINE, - &pmu_mmdc->node); - cpumask_set_cpu(smp_processor_id(), &pmu_mmdc->cpu); - ret = cpuhp_setup_state_multi(CPUHP_AP_NOTIFY_ONLINE, - "MMDC_ONLINE", NULL, - mmdc_pmu_offline_cpu); - if (ret) { - pr_err("cpuhp_setup_state_multi failure\n"); - goto pmu_register_err; - } + cpumask_set_cpu(raw_smp_processor_id(), &pmu_mmdc->cpu); + + /* Register the pmu instance for cpu hotplug */ + cpuhp_state_add_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node); ret = perf_pmu_register(&(pmu_mmdc->pmu), name, -1); - platform_set_drvdata(pdev, pmu_mmdc); if (ret) goto pmu_register_err; + + platform_set_drvdata(pdev, pmu_mmdc); return 0; pmu_register_err: pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret); + cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node); hrtimer_cancel(&pmu_mmdc->hrtimer); +pmu_free: kfree(pmu_mmdc); return ret; }