aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c28
-rw-r--r--arch/arm64/kernel/suspend.c23
2 files changed, 28 insertions, 23 deletions
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index f3f879388d22..b989233a9d31 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -894,29 +894,10 @@ static struct notifier_block __cpuinitdata hw_breakpoint_reset_nb = {
.notifier_call = hw_breakpoint_reset_notify,
};
-#ifdef CONFIG_CPU_PM
-static int hw_breakpoint_cpu_pm_notify(struct notifier_block *self,
- unsigned long action,
- void *v)
-{
- if (action == CPU_PM_EXIT) {
- hw_breakpoint_reset(NULL);
- return NOTIFY_OK;
- }
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block hw_breakpoint_cpu_pm_nb = {
- .notifier_call = hw_breakpoint_cpu_pm_notify,
-};
-
-static void __init hw_breakpoint_pm_init(void)
-{
- cpu_pm_register_notifier(&hw_breakpoint_cpu_pm_nb);
-}
+#ifdef CONFIG_ARM64_CPU_SUSPEND
+extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *));
#else
-static inline void hw_breakpoint_pm_init(void)
+static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
{
}
#endif
@@ -947,7 +928,8 @@ static int __init arch_hw_breakpoint_init(void)
/* Register hotplug notifier. */
register_cpu_notifier(&hw_breakpoint_reset_nb);
- hw_breakpoint_pm_init();
+ /* Register cpu_suspend hw breakpoint restore hook */
+ cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
return 0;
}
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index e074b1c32723..430344e2c989 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -38,6 +38,22 @@ int __cpu_suspend_finisher(unsigned long arg, struct cpu_suspend_ctx *ptr,
return cpu_ops[cpu]->cpu_suspend(arg);
}
+/*
+ * This hook is provided so that cpu_suspend code can restore HW
+ * breakpoints as early as possible in the resume path, before reenabling
+ * debug exceptions. Code cannot be run from a CPU PM notifier since by the
+ * time the notifier runs debug exceptions might have been enabled already,
+ * with HW breakpoints registers content still in an unknown state.
+ */
+void (*hw_breakpoint_restore)(void *);
+void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
+{
+ /* Prevent multiple restore hook initializations */
+ if (WARN_ON(hw_breakpoint_restore))
+ return;
+ hw_breakpoint_restore = hw_bp_restore;
+}
+
/**
* cpu_suspend
*
@@ -73,6 +89,13 @@ int cpu_suspend(unsigned long arg)
if (ret == 0) {
cpu_switch_mm(mm->pgd, mm);
flush_tlb_all();
+ /*
+ * Restore HW breakpoint registers to sane values
+ * before debug exceptions are possibly reenabled
+ * through local_dbg_restore.
+ */
+ if (hw_breakpoint_restore)
+ hw_breakpoint_restore(NULL);
}
/*