Commit d7a83d12 authored by Will Deacon's avatar Will Deacon

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: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent a8427898
...@@ -857,7 +857,7 @@ void hw_breakpoint_thread_switch(struct task_struct *next) ...@@ -857,7 +857,7 @@ void hw_breakpoint_thread_switch(struct task_struct *next)
/* /*
* CPU initialisation. * CPU initialisation.
*/ */
static void hw_breakpoint_reset(void *unused) static int hw_breakpoint_reset(unsigned int cpu)
{ {
int i; int i;
struct perf_event **slots; struct perf_event **slots;
...@@ -888,28 +888,14 @@ static void hw_breakpoint_reset(void *unused) ...@@ -888,28 +888,14 @@ static void hw_breakpoint_reset(void *unused)
write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL);
} }
} }
}
static int hw_breakpoint_reset_notify(struct notifier_block *self, return 0;
unsigned long action,
void *hcpu)
{
if ((action & ~CPU_TASKS_FROZEN) == CPU_ONLINE) {
local_irq_disable();
hw_breakpoint_reset(NULL);
local_irq_enable();
}
return NOTIFY_OK;
} }
static struct notifier_block hw_breakpoint_reset_nb = {
.notifier_call = hw_breakpoint_reset_notify,
};
#ifdef CONFIG_CPU_PM #ifdef CONFIG_CPU_PM
extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)); extern void cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int));
#else #else
static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) static inline void cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
{ {
} }
#endif #endif
...@@ -919,36 +905,34 @@ static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) ...@@ -919,36 +905,34 @@ static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
*/ */
static int __init arch_hw_breakpoint_init(void) static int __init arch_hw_breakpoint_init(void)
{ {
int ret;
core_num_brps = get_num_brps(); core_num_brps = get_num_brps();
core_num_wrps = get_num_wrps(); core_num_wrps = get_num_wrps();
pr_info("found %d breakpoint and %d watchpoint registers.\n", pr_info("found %d breakpoint and %d watchpoint registers.\n",
core_num_brps, core_num_wrps); core_num_brps, core_num_wrps);
cpu_notifier_register_begin();
/*
* Reset the breakpoint resources. We assume that a halting
* debugger will leave the world in a nice state for us.
*/
smp_call_function(hw_breakpoint_reset, NULL, 1);
hw_breakpoint_reset(NULL);
/* Register debug fault handlers. */ /* Register debug fault handlers. */
hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP,
TRAP_HWBKPT, "hw-breakpoint handler"); TRAP_HWBKPT, "hw-breakpoint handler");
hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP, hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP,
TRAP_HWBKPT, "hw-watchpoint handler"); TRAP_HWBKPT, "hw-watchpoint handler");
/* Register hotplug notifier. */ /*
__register_cpu_notifier(&hw_breakpoint_reset_nb); * Reset the breakpoint resources. We assume that a halting
* debugger will leave the world in a nice state for us.
cpu_notifier_register_done(); */
ret = cpuhp_setup_state(CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING,
"CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING",
hw_breakpoint_reset, NULL);
if (ret)
pr_err("failed to register CPU hotplug notifier: %d\n", ret);
/* Register cpu_suspend hw breakpoint restore hook */ /* Register cpu_suspend hw breakpoint restore hook */
cpu_suspend_set_dbg_restorer(hw_breakpoint_reset); cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
return 0; return ret;
} }
arch_initcall(arch_hw_breakpoint_init); arch_initcall(arch_hw_breakpoint_init);
......
...@@ -23,8 +23,8 @@ unsigned long *sleep_save_stash; ...@@ -23,8 +23,8 @@ unsigned long *sleep_save_stash;
* time the notifier runs debug exceptions might have been enabled already, * time the notifier runs debug exceptions might have been enabled already,
* with HW breakpoints registers content still in an unknown state. * with HW breakpoints registers content still in an unknown state.
*/ */
static void (*hw_breakpoint_restore)(void *); static int (*hw_breakpoint_restore)(unsigned int);
void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) void __init cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
{ {
/* Prevent multiple restore hook initializations */ /* Prevent multiple restore hook initializations */
if (WARN_ON(hw_breakpoint_restore)) if (WARN_ON(hw_breakpoint_restore))
...@@ -34,6 +34,8 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) ...@@ -34,6 +34,8 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
void notrace __cpu_suspend_exit(void) void notrace __cpu_suspend_exit(void)
{ {
unsigned int cpu = smp_processor_id();
/* /*
* We are resuming from reset with the idmap active in TTBR0_EL1. * We are resuming from reset with the idmap active in TTBR0_EL1.
* We must uninstall the idmap and restore the expected MMU * We must uninstall the idmap and restore the expected MMU
...@@ -45,7 +47,7 @@ void notrace __cpu_suspend_exit(void) ...@@ -45,7 +47,7 @@ void notrace __cpu_suspend_exit(void)
* Restore per-cpu offset before any kernel * Restore per-cpu offset before any kernel
* subsystem relying on it has a chance to run. * subsystem relying on it has a chance to run.
*/ */
set_my_cpu_offset(per_cpu_offset(smp_processor_id())); set_my_cpu_offset(per_cpu_offset(cpu));
/* /*
* Restore HW breakpoint registers to sane values * Restore HW breakpoint registers to sane values
...@@ -53,7 +55,7 @@ void notrace __cpu_suspend_exit(void) ...@@ -53,7 +55,7 @@ void notrace __cpu_suspend_exit(void)
* through local_dbg_restore. * through local_dbg_restore.
*/ */
if (hw_breakpoint_restore) if (hw_breakpoint_restore)
hw_breakpoint_restore(NULL); hw_breakpoint_restore(cpu);
} }
/* /*
......
...@@ -45,6 +45,7 @@ enum cpuhp_state { ...@@ -45,6 +45,7 @@ enum cpuhp_state {
CPUHP_AP_PERF_METAG_STARTING, CPUHP_AP_PERF_METAG_STARTING,
CPUHP_AP_MIPS_OP_LOONGSON3_STARTING, CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
CPUHP_AP_ARM_VFP_STARTING, CPUHP_AP_ARM_VFP_STARTING,
CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING,
CPUHP_AP_PERF_ARM_STARTING, CPUHP_AP_PERF_ARM_STARTING,
CPUHP_AP_ARM_L2X0_STARTING, CPUHP_AP_ARM_L2X0_STARTING,
CPUHP_AP_ARM_ARCH_TIMER_STARTING, CPUHP_AP_ARM_ARCH_TIMER_STARTING,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment