From c512de955f0982aafa49d3f00d5643052a6790e5 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 2 Aug 2011 13:01:17 +0100 Subject: [PATCH] ARM: hw_breakpoint: reserve one breakpoint for watchpoint stepping The current hw_breakpoint code on ARM reserves 1 breakpoint for each watchpoint that is available. Since debug architectures prior to 7.1 are restricted to 1 watchpoint anyway, only one breakpoint was ever reserved. This patch changes the reservation strategy so that a single breakpoint is reserved, regardless of the number of watchpoints. This is in preparation for multiple-watchpoint support on debug architectures from 7.1 onwards. Signed-off-by: Will Deacon --- arch/arm/kernel/hw_breakpoint.c | 63 +++++++++++++-------------------- 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index b6ddbfaae52c..156b8af13571 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -45,7 +45,6 @@ static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]); /* Number of BRP/WRP registers on this CPU. */ static int core_num_brps; -static int core_num_reserved_brps; static int core_num_wrps; /* Debug architecture version. */ @@ -160,7 +159,15 @@ static int debug_arch_supported(void) arch >= ARM_DEBUG_ARCH_V7_1; } -/* Determine number of BRP register available. */ +/* Determine number of WRP registers available. */ +static int get_num_wrp_resources(void) +{ + u32 didr; + ARM_DBG_READ(c0, 0, didr); + return ((didr >> 28) & 0xf) + 1; +} + +/* Determine number of BRP registers available. */ static int get_num_brp_resources(void) { u32 didr; @@ -179,9 +186,10 @@ static int core_has_mismatch_brps(void) static int get_num_wrps(void) { /* - * FIXME: When a watchpoint fires, the only way to work out which - * watchpoint it was is by disassembling the faulting instruction - * and working out the address of the memory access. + * On debug architectures prior to 7.1, when a watchpoint fires, the + * only way to work out which watchpoint it was is by disassembling + * the faulting instruction and working out the address of the memory + * access. * * Furthermore, we can only do this if the watchpoint was precise * since imprecise watchpoints prevent us from calculating register @@ -195,36 +203,17 @@ static int get_num_wrps(void) * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows * that it is set on some implementations]. */ + if (get_debug_arch() < ARM_DEBUG_ARCH_V7_1) + return 1; -#if 0 - int wrps; - u32 didr; - ARM_DBG_READ(c0, 0, didr); - wrps = ((didr >> 28) & 0xf) + 1; -#endif - int wrps = 1; - - if (core_has_mismatch_brps() && wrps >= get_num_brp_resources()) - wrps = get_num_brp_resources() - 1; - - return wrps; -} - -/* We reserve one breakpoint for each watchpoint. */ -static int get_num_reserved_brps(void) -{ - if (core_has_mismatch_brps()) - return get_num_wrps(); - return 0; + return get_num_wrp_resources(); } /* Determine number of usable BRPs available. */ static int get_num_brps(void) { int brps = get_num_brp_resources(); - if (core_has_mismatch_brps()) - brps -= get_num_reserved_brps(); - return brps; + return core_has_mismatch_brps() ? brps - 1 : brps; } /* @@ -721,7 +710,7 @@ static void watchpoint_single_step_handler(unsigned long pc) slots = (struct perf_event **)__get_cpu_var(wp_on_reg); - for (i = 0; i < core_num_reserved_brps; ++i) { + for (i = 0; i < core_num_wrps; ++i) { rcu_read_lock(); wp = slots[i]; @@ -840,7 +829,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, */ static void reset_ctrl_regs(void *info) { - int i, err = 0, cpu = smp_processor_id(); + int i, raw_num_brps, err = 0, cpu = smp_processor_id(); u32 dbg_power; cpumask_t *cpumask = info; @@ -896,7 +885,8 @@ static void reset_ctrl_regs(void *info) return; /* We must also reset any reserved registers. */ - for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { + raw_num_brps = get_num_brp_resources(); + for (i = 0; i < raw_num_brps; ++i) { write_wb_reg(ARM_BASE_BCR + i, 0UL); write_wb_reg(ARM_BASE_BVR + i, 0UL); } @@ -933,15 +923,11 @@ static int __init arch_hw_breakpoint_init(void) /* Determine how many BRPs/WRPs are available. */ core_num_brps = get_num_brps(); - core_num_reserved_brps = get_num_reserved_brps(); core_num_wrps = get_num_wrps(); - pr_info("found %d breakpoint and %d watchpoint registers.\n", - core_num_brps + core_num_reserved_brps, core_num_wrps); - - if (core_num_reserved_brps) - pr_info("%d breakpoint(s) reserved for watchpoint " - "single-step.\n", core_num_reserved_brps); + pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n", + core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " : + "", core_num_wrps); /* * Reset the breakpoint resources. We assume that a halting @@ -950,7 +936,6 @@ static int __init arch_hw_breakpoint_init(void) on_each_cpu(reset_ctrl_regs, &cpumask, 1); if (!cpumask_empty(&cpumask)) { core_num_brps = 0; - core_num_reserved_brps = 0; core_num_wrps = 0; return 0; }