Perf: Use CPU PM notifiers to save and restore PMU regs

Some PMU registers have undefined values at reset. Power collapsing
CPU's can cause the PMU state to be messed up. Use the CPU PM notifiers
to save and restore PMU state correctly.

Change-Id: I4d5d73abc3455b38219239527d94d4afc30ed886
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 9144461..b59ad93 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -26,6 +26,7 @@
 #include <asm/irq_regs.h>
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
+#include <linux/cpu_pm.h>
 
 static struct platform_device *pmu_device;
 
@@ -651,6 +652,30 @@
 #include "perf_event_msm_krait.c"
 #include "perf_event_msm_krait_l2.c"
 
+static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
+		void *v)
+{
+	switch (cmd) {
+	case CPU_PM_ENTER:
+		perf_pmu_disable(&pmu);
+		break;
+
+	case CPU_PM_ENTER_FAILED:
+	case CPU_PM_EXIT:
+		if (armpmu && armpmu->reset)
+			armpmu->reset(NULL);
+		perf_pmu_enable(&pmu);
+
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block perf_cpu_pm_notifier_block = {
+	.notifier_call = perf_cpu_pm_notifier,
+};
+
 /*
  * Ensure the PMU has sane values out of reset.
  * This requires SMP to be available, so exists as a separate initcall.
@@ -733,6 +758,8 @@
 
 	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
 
+	cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
+
 	return 0;
 }
 early_initcall(init_hw_perf_events);