aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/hw_breakpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/hw_breakpoint.c')
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c79
1 files changed, 66 insertions, 13 deletions
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index e89459123fa3..bcaaac9e14d6 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -20,6 +20,7 @@
20 20
21#define pr_fmt(fmt) "hw-breakpoint: " fmt 21#define pr_fmt(fmt) "hw-breakpoint: " fmt
22 22
23#include <linux/cpu_pm.h>
23#include <linux/errno.h> 24#include <linux/errno.h>
24#include <linux/hw_breakpoint.h> 25#include <linux/hw_breakpoint.h>
25#include <linux/perf_event.h> 26#include <linux/perf_event.h>
@@ -171,7 +172,8 @@ static enum debug_el debug_exception_level(int privilege)
171 172
172enum hw_breakpoint_ops { 173enum hw_breakpoint_ops {
173 HW_BREAKPOINT_INSTALL, 174 HW_BREAKPOINT_INSTALL,
174 HW_BREAKPOINT_UNINSTALL 175 HW_BREAKPOINT_UNINSTALL,
176 HW_BREAKPOINT_RESTORE
175}; 177};
176 178
177/** 179/**
@@ -210,6 +212,10 @@ static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
210 return i; 212 return i;
211 } 213 }
212 break; 214 break;
215 case HW_BREAKPOINT_RESTORE:
216 if (*slot == bp)
217 return i;
218 break;
213 default: 219 default:
214 pr_warn_once("Unhandled hw breakpoint ops %d\n", ops); 220 pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
215 return -EINVAL; 221 return -EINVAL;
@@ -256,7 +262,8 @@ static int hw_breakpoint_control(struct perf_event *bp,
256 * level. 262 * level.
257 */ 263 */
258 enable_debug_monitors(dbg_el); 264 enable_debug_monitors(dbg_el);
259 265 /* Fall through */
266 case HW_BREAKPOINT_RESTORE:
260 /* Setup the address register. */ 267 /* Setup the address register. */
261 write_wb_reg(val_reg, i, info->address); 268 write_wb_reg(val_reg, i, info->address);
262 269
@@ -840,18 +847,36 @@ void hw_breakpoint_thread_switch(struct task_struct *next)
840/* 847/*
841 * CPU initialisation. 848 * CPU initialisation.
842 */ 849 */
843static void reset_ctrl_regs(void *unused) 850static void hw_breakpoint_reset(void *unused)
844{ 851{
845 int i; 852 int i;
846 853 struct perf_event **slots;
847 for (i = 0; i < core_num_brps; ++i) { 854 /*
848 write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL); 855 * When a CPU goes through cold-boot, it does not have any installed
849 write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL); 856 * slot, so it is safe to share the same function for restoring and
857 * resetting breakpoints; when a CPU is hotplugged in, it goes
858 * through the slots, which are all empty, hence it just resets control
859 * and value for debug registers.
860 * When this function is triggered on warm-boot through a CPU PM
861 * notifier some slots might be initialized; if so they are
862 * reprogrammed according to the debug slots content.
863 */
864 for (slots = this_cpu_ptr(bp_on_reg), i = 0; i < core_num_brps; ++i) {
865 if (slots[i]) {
866 hw_breakpoint_control(slots[i], HW_BREAKPOINT_RESTORE);
867 } else {
868 write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL);
869 write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL);
870 }
850 } 871 }
851 872
852 for (i = 0; i < core_num_wrps; ++i) { 873 for (slots = this_cpu_ptr(wp_on_reg), i = 0; i < core_num_wrps; ++i) {
853 write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL); 874 if (slots[i]) {
854 write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); 875 hw_breakpoint_control(slots[i], HW_BREAKPOINT_RESTORE);
876 } else {
877 write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL);
878 write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL);
879 }
855 } 880 }
856} 881}
857 882
@@ -861,7 +886,7 @@ static int hw_breakpoint_reset_notify(struct notifier_block *self,
861{ 886{
862 int cpu = (long)hcpu; 887 int cpu = (long)hcpu;
863 if (action == CPU_ONLINE) 888 if (action == CPU_ONLINE)
864 smp_call_function_single(cpu, reset_ctrl_regs, NULL, 1); 889 smp_call_function_single(cpu, hw_breakpoint_reset, NULL, 1);
865 return NOTIFY_OK; 890 return NOTIFY_OK;
866} 891}
867 892
@@ -869,6 +894,33 @@ static struct notifier_block hw_breakpoint_reset_nb = {
869 .notifier_call = hw_breakpoint_reset_notify, 894 .notifier_call = hw_breakpoint_reset_notify,
870}; 895};
871 896
897#ifdef CONFIG_CPU_PM
898static int hw_breakpoint_cpu_pm_notify(struct notifier_block *self,
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
910static struct notifier_block hw_breakpoint_cpu_pm_nb = {
911 .notifier_call = hw_breakpoint_cpu_pm_notify,
912};
913
914static void __init hw_breakpoint_pm_init(void)
915{
916 cpu_pm_register_notifier(&hw_breakpoint_cpu_pm_nb);
917}
918#else
919static inline void hw_breakpoint_pm_init(void)
920{
921}
922#endif
923
872/* 924/*
873 * One-time initialisation. 925 * One-time initialisation.
874 */ 926 */
@@ -884,8 +936,8 @@ static int __init arch_hw_breakpoint_init(void)
884 * Reset the breakpoint resources. We assume that a halting 936 * Reset the breakpoint resources. We assume that a halting
885 * debugger will leave the world in a nice state for us. 937 * debugger will leave the world in a nice state for us.
886 */ 938 */
887 smp_call_function(reset_ctrl_regs, NULL, 1); 939 smp_call_function(hw_breakpoint_reset, NULL, 1);
888 reset_ctrl_regs(NULL); 940 hw_breakpoint_reset(NULL);
889 941
890 /* Register debug fault handlers. */ 942 /* Register debug fault handlers. */
891 hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, 943 hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP,
@@ -895,6 +947,7 @@ static int __init arch_hw_breakpoint_init(void)
895 947
896 /* Register hotplug notifier. */ 948 /* Register hotplug notifier. */
897 register_cpu_notifier(&hw_breakpoint_reset_nb); 949 register_cpu_notifier(&hw_breakpoint_reset_nb);
950 hw_breakpoint_pm_init();
898 951
899 return 0; 952 return 0;
900} 953}