Patchwork [3.5.y.z,extended,stable] Patch "perf, x86: fix kernel crash with PEBS/BTS after suspend/resume" has been added to staging queue

mail settings
Submitter Luis Henriques
Date March 20, 2013, 10:43 a.m.
Message ID <>
Download mbox | patch
Permalink /patch/229326/
State New
Headers show


Luis Henriques - March 20, 2013, 10:43 a.m.
This is a note to let you know that I have just added a patch titled

    perf,x86: fix kernel crash with PEBS/BTS after suspend/resume

to the linux-3.5.y-queue branch of the 3.5.y.z extended stable tree 
which can be found at:;a=shortlog;h=refs/heads/linux-3.5.y-queue

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.5.y.z tree, see



From a27090150fb7e7389840d4666f227db5e19e0ac2 Mon Sep 17 00:00:00 2001
From: Stephane Eranian <>
Date: Fri, 15 Mar 2013 14:26:07 +0100
Subject: [PATCH] perf,x86: fix kernel crash with PEBS/BTS after suspend/resume

commit 1d9d8639c063caf6efc2447f5f26aa637f844ff6 upstream.

This patch fixes a kernel crash when using precise sampling (PEBS)
after a suspend/resume. Turns out the CPU notifier code is not invoked
on CPU0 (BP). Therefore, the DS_AREA (used by PEBS) is not restored properly
by the kernel and keeps it power-on/resume value of 0 causing any PEBS
measurement to crash when running on CPU0.

The workaround is to add a hook in the actual resume code to restore
the DS Area MSR value. It is invoked for all CPUS. So for all but CPU0,
the DS_AREA will be restored twice but this is harmless.

Reported-by: Linus Torvalds <>
Signed-off-by: Stephane Eranian <>
Signed-off-by: Linus Torvalds <>
Signed-off-by: Luis Henriques <>
 arch/x86/kernel/cpu/perf_event_intel_ds.c | 8 ++++++++
 arch/x86/power/cpu.c                      | 2 ++
 include/linux/perf_event.h                | 2 ++
 3 files changed, 12 insertions(+)



diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 35e2192..9a9be1e 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -714,3 +714,11 @@  void intel_ds_init(void)
+void perf_restore_debug_store(void)
+	if (!x86_pmu.bts && !x86_pmu.pebs)
+		return;
+	init_debug_store_on_cpu(smp_processor_id());
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 218cdb1..fcbaac60 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -11,6 +11,7 @@ 
 #include <linux/suspend.h>
 #include <linux/export.h>
 #include <linux/smp.h>
+#include <linux/perf_event.h>

 #include <asm/pgtable.h>
 #include <asm/proto.h>
@@ -227,6 +228,7 @@  static void __restore_processor_state(struct saved_context *ctxt)
+	perf_restore_debug_store();

 /* Needed by apm.c */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index c3c98a6..1d56bf6 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1295,6 +1295,7 @@  extern void perf_swevent_put_recursion_context(int rctx);
 extern void perf_event_enable(struct perf_event *event);
 extern void perf_event_disable(struct perf_event *event);
 extern void perf_event_task_tick(void);
+extern void perf_restore_debug_store(void);
 static inline void
 perf_event_task_sched_in(struct task_struct *prev,
@@ -1333,6 +1334,7 @@  static inline void perf_swevent_put_recursion_context(int rctx)		{ }
 static inline void perf_event_enable(struct perf_event *event)		{ }
 static inline void perf_event_disable(struct perf_event *event)		{ }
 static inline void perf_event_task_tick(void)				{ }
+static inline void perf_restore_debug_store(void)			{ }

 #define perf_output_put(handle, x) perf_output_copy((handle), &(x), sizeof(x))