diff options
| -rw-r--r-- | arch/arm64/kernel/hw_breakpoint.c | 28 | ||||
| -rw-r--r-- | arch/arm64/kernel/suspend.c | 23 |
2 files changed, 28 insertions, 23 deletions
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index bcaaac9e14d6..f17f581116fc 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c | |||
| @@ -894,29 +894,10 @@ static struct notifier_block hw_breakpoint_reset_nb = { | |||
| 894 | .notifier_call = hw_breakpoint_reset_notify, | 894 | .notifier_call = hw_breakpoint_reset_notify, |
| 895 | }; | 895 | }; |
| 896 | 896 | ||
| 897 | #ifdef CONFIG_CPU_PM | 897 | #ifdef CONFIG_ARM64_CPU_SUSPEND |
| 898 | static int hw_breakpoint_cpu_pm_notify(struct notifier_block *self, | 898 | extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)); |
| 899 | unsigned long action, | ||
| 900 | void *v) | ||
| 901 | { | ||
| 902 | if (action == CPU_PM_EXIT) { | ||
| 903 | hw_breakpoint_reset(NULL); | ||
| 904 | return NOTIFY_OK; | ||
| 905 | } | ||
| 906 | |||
| 907 | return NOTIFY_DONE; | ||
| 908 | } | ||
| 909 | |||
| 910 | static struct notifier_block hw_breakpoint_cpu_pm_nb = { | ||
| 911 | .notifier_call = hw_breakpoint_cpu_pm_notify, | ||
| 912 | }; | ||
| 913 | |||
| 914 | static void __init hw_breakpoint_pm_init(void) | ||
| 915 | { | ||
| 916 | cpu_pm_register_notifier(&hw_breakpoint_cpu_pm_nb); | ||
| 917 | } | ||
| 918 | #else | 899 | #else |
| 919 | static inline void hw_breakpoint_pm_init(void) | 900 | static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) |
| 920 | { | 901 | { |
| 921 | } | 902 | } |
| 922 | #endif | 903 | #endif |
| @@ -947,7 +928,8 @@ static int __init arch_hw_breakpoint_init(void) | |||
| 947 | 928 | ||
| 948 | /* Register hotplug notifier. */ | 929 | /* Register hotplug notifier. */ |
| 949 | register_cpu_notifier(&hw_breakpoint_reset_nb); | 930 | register_cpu_notifier(&hw_breakpoint_reset_nb); |
| 950 | hw_breakpoint_pm_init(); | 931 | /* Register cpu_suspend hw breakpoint restore hook */ |
| 932 | cpu_suspend_set_dbg_restorer(hw_breakpoint_reset); | ||
| 951 | 933 | ||
| 952 | return 0; | 934 | return 0; |
| 953 | } | 935 | } |
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, | |||
| 38 | return cpu_ops[cpu]->cpu_suspend(arg); | 38 | return cpu_ops[cpu]->cpu_suspend(arg); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | /* | ||
| 42 | * This hook is provided so that cpu_suspend code can restore HW | ||
| 43 | * breakpoints as early as possible in the resume path, before reenabling | ||
| 44 | * debug exceptions. Code cannot be run from a CPU PM notifier since by the | ||
| 45 | * time the notifier runs debug exceptions might have been enabled already, | ||
| 46 | * with HW breakpoints registers content still in an unknown state. | ||
| 47 | */ | ||
| 48 | void (*hw_breakpoint_restore)(void *); | ||
| 49 | void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) | ||
| 50 | { | ||
| 51 | /* Prevent multiple restore hook initializations */ | ||
| 52 | if (WARN_ON(hw_breakpoint_restore)) | ||
| 53 | return; | ||
| 54 | hw_breakpoint_restore = hw_bp_restore; | ||
| 55 | } | ||
| 56 | |||
| 41 | /** | 57 | /** |
| 42 | * cpu_suspend | 58 | * cpu_suspend |
| 43 | * | 59 | * |
| @@ -73,6 +89,13 @@ int cpu_suspend(unsigned long arg) | |||
| 73 | if (ret == 0) { | 89 | if (ret == 0) { |
| 74 | cpu_switch_mm(mm->pgd, mm); | 90 | cpu_switch_mm(mm->pgd, mm); |
| 75 | flush_tlb_all(); | 91 | flush_tlb_all(); |
| 92 | /* | ||
| 93 | * Restore HW breakpoint registers to sane values | ||
| 94 | * before debug exceptions are possibly reenabled | ||
| 95 | * through local_dbg_restore. | ||
| 96 | */ | ||
| 97 | if (hw_breakpoint_restore) | ||
| 98 | hw_breakpoint_restore(NULL); | ||
| 76 | } | 99 | } |
| 77 | 100 | ||
| 78 | /* | 101 | /* |
