Skip to content

Commit d7a83d1

Browse files
committed
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>
1 parent a842789 commit d7a83d1

File tree

3 files changed

+23
-36
lines changed

3 files changed

+23
-36
lines changed

arch/arm64/kernel/hw_breakpoint.c

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ void hw_breakpoint_thread_switch(struct task_struct *next)
857857
/*
858858
* CPU initialisation.
859859
*/
860-
static void hw_breakpoint_reset(void *unused)
860+
static int hw_breakpoint_reset(unsigned int cpu)
861861
{
862862
int i;
863863
struct perf_event **slots;
@@ -888,28 +888,14 @@ static void hw_breakpoint_reset(void *unused)
888888
write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL);
889889
}
890890
}
891-
}
892891

893-
static int hw_breakpoint_reset_notify(struct notifier_block *self,
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;
892+
return 0;
903893
}
904894

905-
static struct notifier_block hw_breakpoint_reset_nb = {
906-
.notifier_call = hw_breakpoint_reset_notify,
907-
};
908-
909895
#ifdef CONFIG_CPU_PM
910-
extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *));
896+
extern void cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int));
911897
#else
912-
static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
898+
static inline void cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
913899
{
914900
}
915901
#endif
@@ -919,36 +905,34 @@ static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
919905
*/
920906
static int __init arch_hw_breakpoint_init(void)
921907
{
908+
int ret;
909+
922910
core_num_brps = get_num_brps();
923911
core_num_wrps = get_num_wrps();
924912

925913
pr_info("found %d breakpoint and %d watchpoint registers.\n",
926914
core_num_brps, core_num_wrps);
927915

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-
937916
/* Register debug fault handlers. */
938917
hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP,
939918
TRAP_HWBKPT, "hw-breakpoint handler");
940919
hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP,
941920
TRAP_HWBKPT, "hw-watchpoint handler");
942921

943-
/* Register hotplug notifier. */
944-
__register_cpu_notifier(&hw_breakpoint_reset_nb);
945-
946-
cpu_notifier_register_done();
922+
/*
923+
* Reset the breakpoint resources. We assume that a halting
924+
* debugger will leave the world in a nice state for us.
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);
947931

948932
/* Register cpu_suspend hw breakpoint restore hook */
949933
cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
950934

951-
return 0;
935+
return ret;
952936
}
953937
arch_initcall(arch_hw_breakpoint_init);
954938

arch/arm64/kernel/suspend.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ unsigned long *sleep_save_stash;
2323
* time the notifier runs debug exceptions might have been enabled already,
2424
* with HW breakpoints registers content still in an unknown state.
2525
*/
26-
static void (*hw_breakpoint_restore)(void *);
27-
void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
26+
static int (*hw_breakpoint_restore)(unsigned int);
27+
void __init cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
2828
{
2929
/* Prevent multiple restore hook initializations */
3030
if (WARN_ON(hw_breakpoint_restore))
@@ -34,6 +34,8 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
3434

3535
void notrace __cpu_suspend_exit(void)
3636
{
37+
unsigned int cpu = smp_processor_id();
38+
3739
/*
3840
* We are resuming from reset with the idmap active in TTBR0_EL1.
3941
* We must uninstall the idmap and restore the expected MMU
@@ -45,15 +47,15 @@ void notrace __cpu_suspend_exit(void)
4547
* Restore per-cpu offset before any kernel
4648
* subsystem relying on it has a chance to run.
4749
*/
48-
set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
50+
set_my_cpu_offset(per_cpu_offset(cpu));
4951

5052
/*
5153
* Restore HW breakpoint registers to sane values
5254
* before debug exceptions are possibly reenabled
5355
* through local_dbg_restore.
5456
*/
5557
if (hw_breakpoint_restore)
56-
hw_breakpoint_restore(NULL);
58+
hw_breakpoint_restore(cpu);
5759
}
5860

5961
/*

include/linux/cpuhotplug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum cpuhp_state {
4545
CPUHP_AP_PERF_METAG_STARTING,
4646
CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
4747
CPUHP_AP_ARM_VFP_STARTING,
48+
CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING,
4849
CPUHP_AP_PERF_ARM_STARTING,
4950
CPUHP_AP_ARM_L2X0_STARTING,
5051
CPUHP_AP_ARM_ARCH_TIMER_STARTING,

0 commit comments

Comments
 (0)