Perf: bring CPU online if needed when disabling irq

When disabling an irq, check that the CPU is online
before trying to run on that CPU. Bring the CPU
online if necessary.

This fixes a problem where a CPU that was not online
when disabling the irq caused the disable and the
free to fail. A subsequent attempt to request the irq
also failed because it had not been freed.

Change-Id: Ib873b5ded83ab843ea4e609f196a31ef0083a213
Signed-off-by: Neil Leeder <nleeder@codeaurora.org>
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 478848d..d36b431 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -32,6 +32,7 @@
 	"12 Perf: Make per-process counters configurable\n"
 	"13 msm: perf: Add L2 support for tracecounters\n"
 	"14 Perf: keep events across hotplug\n"
+	"15 Perf: bring CPU online if needed when disabling irq\n"
 ;
 
 static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 8d65eea..fe45fa4 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,6 +11,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/irq.h>
 #include <asm/pmu.h>
 #include <mach/irqs.h>
 #include <mach/socinfo.h>
@@ -18,6 +19,19 @@
 #if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP)
 static DEFINE_PER_CPU(u32, pmu_irq_cookie);
 
+static __ref int armpmu_cpu_up(int cpu)
+{
+	int ret = 0;
+
+	if (!cpumask_test_cpu(cpu, cpu_online_mask)) {
+		ret = cpu_up(cpu);
+		if (ret)
+			pr_err("Failed to bring up CPU: %d, ret: %d\n",
+			       cpu, ret);
+	}
+	return ret;
+}
+
 static int
 multicore_request_irq(int irq, irq_handler_t *handle_irq)
 {
@@ -41,10 +55,12 @@
 multicore_free_irq(int irq)
 {
 	int cpu;
+	struct irq_desc *desc = irq_to_desc(irq);
 
 	if (irq >= 0) {
-		for_each_cpu(cpu, cpu_online_mask) {
-			smp_call_function_single(cpu,
+		for_each_cpu(cpu, desc->percpu_enabled) {
+			if (!armpmu_cpu_up(cpu))
+				smp_call_function_single(cpu,
 					disable_irq_callback, &irq, 1);
 		}
 		free_percpu_irq(irq, &pmu_irq_cookie);