aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2016-08-15 13:55:11 -0400
committerWill Deacon <will.deacon@arm.com>2016-09-01 08:45:51 -0400
commitd7a83d127a64fd91ef1ad39b7e2d78db36cf388b (patch)
treec6bdc26aef406690a7fb44be0311ca87ec5ad2c7
parenta842789837c0e3734357c6b4c54d39d60a1d24b1 (diff)
arm64: hw_breakpoint: convert CPU hotplug notifier to new infrastructure
The arm64 hw_breakpoint implementation uses a CPU hotplug notifier to reset the {break,watch}point registers when CPUs come online. This patch converts the code to the new hotplug mechanism, whilst moving the invocation earlier to remove the need to disable IRQs explicitly in the driver (which could cause havok if we trip a watchpoint in an IRQ handler whilst restoring the debug register state). Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c48
-rw-r--r--arch/arm64/kernel/suspend.c10
-rw-r--r--include/linux/cpuhotplug.h1
3 files changed, 23 insertions, 36 deletions
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index 26a6bf77d272..948b73148d56 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -857,7 +857,7 @@ void hw_breakpoint_thread_switch(struct task_struct *next)
857/* 857/*
858 * CPU initialisation. 858 * CPU initialisation.
859 */ 859 */
860static void hw_breakpoint_reset(void *unused) 860static int hw_breakpoint_reset(unsigned int cpu)
861{ 861{
862 int i; 862 int i;
863 struct perf_event **slots; 863 struct perf_event **slots;
@@ -888,28 +888,14 @@ static void hw_breakpoint_reset(void *unused)
888 write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); 888 write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL);
889 } 889 }
890 } 890 }
891}
892 891
893static int hw_breakpoint_reset_notify(struct notifier_block *self, 892 return 0;
894 unsigned long action,
895 void *hcpu)
896{
897 if ((action & ~CPU_TASKS_FROZEN) == CPU_ONLINE) {
898 local_irq_disable();
899 hw_breakpoint_reset(NULL);
900 local_irq_enable();
901 }
902 return NOTIFY_OK;
903} 893}
904 894
905static struct notifier_block hw_breakpoint_reset_nb = {
906 .notifier_call = hw_breakpoint_reset_notify,
907};
908
909#ifdef CONFIG_CPU_PM 895#ifdef CONFIG_CPU_PM
910extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)); 896extern void cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int));
911#else 897#else
912static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) 898static inline void cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
913{ 899{
914} 900}
915#endif 901#endif
@@ -919,36 +905,34 @@ static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
919 */ 905 */
920static int __init arch_hw_breakpoint_init(void) 906static int __init arch_hw_breakpoint_init(void)
921{ 907{
908 int ret;
909
922 core_num_brps = get_num_brps(); 910 core_num_brps = get_num_brps();
923 core_num_wrps = get_num_wrps(); 911 core_num_wrps = get_num_wrps();
924 912
925 pr_info("found %d breakpoint and %d watchpoint registers.\n", 913 pr_info("found %d breakpoint and %d watchpoint registers.\n",
926 core_num_brps, core_num_wrps); 914 core_num_brps, core_num_wrps);
927 915
928 cpu_notifier_register_begin();
929
930 /*
931 * Reset the breakpoint resources. We assume that a halting
932 * debugger will leave the world in a nice state for us.
933 */
934 smp_call_function(hw_breakpoint_reset, NULL, 1);
935 hw_breakpoint_reset(NULL);
936
937 /* Register debug fault handlers. */ 916 /* Register debug fault handlers. */
938 hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, 917 hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP,
939 TRAP_HWBKPT, "hw-breakpoint handler"); 918 TRAP_HWBKPT, "hw-breakpoint handler");
940 hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP, 919 hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP,
941 TRAP_HWBKPT, "hw-watchpoint handler"); 920 TRAP_HWBKPT, "hw-watchpoint handler");
942 921
943 /* Register hotplug notifier. */ 922 /*
944 __register_cpu_notifier(&hw_breakpoint_reset_nb); 923 * Reset the breakpoint resources. We assume that a halting
945 924 * debugger will leave the world in a nice state for us.
946 cpu_notifier_register_done(); 925 */
926 ret = cpuhp_setup_state(CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING,
927 "CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING",
928 hw_breakpoint_reset, NULL);
929 if (ret)
930 pr_err("failed to register CPU hotplug notifier: %d\n", ret);
947 931
948 /* Register cpu_suspend hw breakpoint restore hook */ 932 /* Register cpu_suspend hw breakpoint restore hook */
949 cpu_suspend_set_dbg_restorer(hw_breakpoint_reset); 933 cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
950 934
951 return 0; 935 return ret;
952} 936}
953arch_initcall(arch_hw_breakpoint_init); 937arch_initcall(arch_hw_breakpoint_init);
954 938
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index b616e365cee3..ad734142070d 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -23,8 +23,8 @@ unsigned long *sleep_save_stash;
23 * time the notifier runs debug exceptions might have been enabled already, 23 * time the notifier runs debug exceptions might have been enabled already,
24 * with HW breakpoints registers content still in an unknown state. 24 * with HW breakpoints registers content still in an unknown state.
25 */ 25 */
26static void (*hw_breakpoint_restore)(void *); 26static int (*hw_breakpoint_restore)(unsigned int);
27void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) 27void __init cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
28{ 28{
29 /* Prevent multiple restore hook initializations */ 29 /* Prevent multiple restore hook initializations */
30 if (WARN_ON(hw_breakpoint_restore)) 30 if (WARN_ON(hw_breakpoint_restore))
@@ -34,6 +34,8 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
34 34
35void notrace __cpu_suspend_exit(void) 35void notrace __cpu_suspend_exit(void)
36{ 36{
37 unsigned int cpu = smp_processor_id();
38
37 /* 39 /*
38 * We are resuming from reset with the idmap active in TTBR0_EL1. 40 * We are resuming from reset with the idmap active in TTBR0_EL1.
39 * We must uninstall the idmap and restore the expected MMU 41 * We must uninstall the idmap and restore the expected MMU
@@ -45,7 +47,7 @@ void notrace __cpu_suspend_exit(void)
45 * Restore per-cpu offset before any kernel 47 * Restore per-cpu offset before any kernel
46 * subsystem relying on it has a chance to run. 48 * subsystem relying on it has a chance to run.
47 */ 49 */
48 set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 50 set_my_cpu_offset(per_cpu_offset(cpu));
49 51
50 /* 52 /*
51 * Restore HW breakpoint registers to sane values 53 * Restore HW breakpoint registers to sane values
@@ -53,7 +55,7 @@ void notrace __cpu_suspend_exit(void)
53 * through local_dbg_restore. 55 * through local_dbg_restore.
54 */ 56 */
55 if (hw_breakpoint_restore) 57 if (hw_breakpoint_restore)
56 hw_breakpoint_restore(NULL); 58 hw_breakpoint_restore(cpu);
57} 59}
58 60
59/* 61/*
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 242bf530edfc..3758fe6d5968 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -45,6 +45,7 @@ enum cpuhp_state {
45 CPUHP_AP_PERF_METAG_STARTING, 45 CPUHP_AP_PERF_METAG_STARTING,
46 CPUHP_AP_MIPS_OP_LOONGSON3_STARTING, 46 CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
47 CPUHP_AP_ARM_VFP_STARTING, 47 CPUHP_AP_ARM_VFP_STARTING,
48 CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING,
48 CPUHP_AP_PERF_ARM_STARTING, 49 CPUHP_AP_PERF_ARM_STARTING,
49 CPUHP_AP_ARM_L2X0_STARTING, 50 CPUHP_AP_ARM_L2X0_STARTING,
50 CPUHP_AP_ARM_ARCH_TIMER_STARTING, 51 CPUHP_AP_ARM_ARCH_TIMER_STARTING,