diff options
author | Will Deacon <will.deacon@arm.com> | 2011-08-02 08:01:17 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2011-08-31 05:42:48 -0400 |
commit | c512de955f0982aafa49d3f00d5643052a6790e5 (patch) | |
tree | 5bf3d463211f174ccf724e82be07cdf800b3168d /arch | |
parent | b5d5b8f98641edac6641af9e19e933083ade603b (diff) |
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 <will.deacon@arm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 63 |
1 files 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]); | |||
45 | 45 | ||
46 | /* Number of BRP/WRP registers on this CPU. */ | 46 | /* Number of BRP/WRP registers on this CPU. */ |
47 | static int core_num_brps; | 47 | static int core_num_brps; |
48 | static int core_num_reserved_brps; | ||
49 | static int core_num_wrps; | 48 | static int core_num_wrps; |
50 | 49 | ||
51 | /* Debug architecture version. */ | 50 | /* Debug architecture version. */ |
@@ -160,7 +159,15 @@ static int debug_arch_supported(void) | |||
160 | arch >= ARM_DEBUG_ARCH_V7_1; | 159 | arch >= ARM_DEBUG_ARCH_V7_1; |
161 | } | 160 | } |
162 | 161 | ||
163 | /* Determine number of BRP register available. */ | 162 | /* Determine number of WRP registers available. */ |
163 | static int get_num_wrp_resources(void) | ||
164 | { | ||
165 | u32 didr; | ||
166 | ARM_DBG_READ(c0, 0, didr); | ||
167 | return ((didr >> 28) & 0xf) + 1; | ||
168 | } | ||
169 | |||
170 | /* Determine number of BRP registers available. */ | ||
164 | static int get_num_brp_resources(void) | 171 | static int get_num_brp_resources(void) |
165 | { | 172 | { |
166 | u32 didr; | 173 | u32 didr; |
@@ -179,9 +186,10 @@ static int core_has_mismatch_brps(void) | |||
179 | static int get_num_wrps(void) | 186 | static int get_num_wrps(void) |
180 | { | 187 | { |
181 | /* | 188 | /* |
182 | * FIXME: When a watchpoint fires, the only way to work out which | 189 | * On debug architectures prior to 7.1, when a watchpoint fires, the |
183 | * watchpoint it was is by disassembling the faulting instruction | 190 | * only way to work out which watchpoint it was is by disassembling |
184 | * and working out the address of the memory access. | 191 | * the faulting instruction and working out the address of the memory |
192 | * access. | ||
185 | * | 193 | * |
186 | * Furthermore, we can only do this if the watchpoint was precise | 194 | * Furthermore, we can only do this if the watchpoint was precise |
187 | * since imprecise watchpoints prevent us from calculating register | 195 | * since imprecise watchpoints prevent us from calculating register |
@@ -195,36 +203,17 @@ static int get_num_wrps(void) | |||
195 | * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows | 203 | * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows |
196 | * that it is set on some implementations]. | 204 | * that it is set on some implementations]. |
197 | */ | 205 | */ |
206 | if (get_debug_arch() < ARM_DEBUG_ARCH_V7_1) | ||
207 | return 1; | ||
198 | 208 | ||
199 | #if 0 | 209 | return get_num_wrp_resources(); |
200 | int wrps; | ||
201 | u32 didr; | ||
202 | ARM_DBG_READ(c0, 0, didr); | ||
203 | wrps = ((didr >> 28) & 0xf) + 1; | ||
204 | #endif | ||
205 | int wrps = 1; | ||
206 | |||
207 | if (core_has_mismatch_brps() && wrps >= get_num_brp_resources()) | ||
208 | wrps = get_num_brp_resources() - 1; | ||
209 | |||
210 | return wrps; | ||
211 | } | ||
212 | |||
213 | /* We reserve one breakpoint for each watchpoint. */ | ||
214 | static int get_num_reserved_brps(void) | ||
215 | { | ||
216 | if (core_has_mismatch_brps()) | ||
217 | return get_num_wrps(); | ||
218 | return 0; | ||
219 | } | 210 | } |
220 | 211 | ||
221 | /* Determine number of usable BRPs available. */ | 212 | /* Determine number of usable BRPs available. */ |
222 | static int get_num_brps(void) | 213 | static int get_num_brps(void) |
223 | { | 214 | { |
224 | int brps = get_num_brp_resources(); | 215 | int brps = get_num_brp_resources(); |
225 | if (core_has_mismatch_brps()) | 216 | return core_has_mismatch_brps() ? brps - 1 : brps; |
226 | brps -= get_num_reserved_brps(); | ||
227 | return brps; | ||
228 | } | 217 | } |
229 | 218 | ||
230 | /* | 219 | /* |
@@ -721,7 +710,7 @@ static void watchpoint_single_step_handler(unsigned long pc) | |||
721 | 710 | ||
722 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); | 711 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); |
723 | 712 | ||
724 | for (i = 0; i < core_num_reserved_brps; ++i) { | 713 | for (i = 0; i < core_num_wrps; ++i) { |
725 | rcu_read_lock(); | 714 | rcu_read_lock(); |
726 | 715 | ||
727 | wp = slots[i]; | 716 | wp = slots[i]; |
@@ -840,7 +829,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, | |||
840 | */ | 829 | */ |
841 | static void reset_ctrl_regs(void *info) | 830 | static void reset_ctrl_regs(void *info) |
842 | { | 831 | { |
843 | int i, err = 0, cpu = smp_processor_id(); | 832 | int i, raw_num_brps, err = 0, cpu = smp_processor_id(); |
844 | u32 dbg_power; | 833 | u32 dbg_power; |
845 | cpumask_t *cpumask = info; | 834 | cpumask_t *cpumask = info; |
846 | 835 | ||
@@ -896,7 +885,8 @@ static void reset_ctrl_regs(void *info) | |||
896 | return; | 885 | return; |
897 | 886 | ||
898 | /* We must also reset any reserved registers. */ | 887 | /* We must also reset any reserved registers. */ |
899 | for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { | 888 | raw_num_brps = get_num_brp_resources(); |
889 | for (i = 0; i < raw_num_brps; ++i) { | ||
900 | write_wb_reg(ARM_BASE_BCR + i, 0UL); | 890 | write_wb_reg(ARM_BASE_BCR + i, 0UL); |
901 | write_wb_reg(ARM_BASE_BVR + i, 0UL); | 891 | write_wb_reg(ARM_BASE_BVR + i, 0UL); |
902 | } | 892 | } |
@@ -933,15 +923,11 @@ static int __init arch_hw_breakpoint_init(void) | |||
933 | 923 | ||
934 | /* Determine how many BRPs/WRPs are available. */ | 924 | /* Determine how many BRPs/WRPs are available. */ |
935 | core_num_brps = get_num_brps(); | 925 | core_num_brps = get_num_brps(); |
936 | core_num_reserved_brps = get_num_reserved_brps(); | ||
937 | core_num_wrps = get_num_wrps(); | 926 | core_num_wrps = get_num_wrps(); |
938 | 927 | ||
939 | pr_info("found %d breakpoint and %d watchpoint registers.\n", | 928 | pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n", |
940 | core_num_brps + core_num_reserved_brps, core_num_wrps); | 929 | core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " : |
941 | 930 | "", core_num_wrps); | |
942 | if (core_num_reserved_brps) | ||
943 | pr_info("%d breakpoint(s) reserved for watchpoint " | ||
944 | "single-step.\n", core_num_reserved_brps); | ||
945 | 931 | ||
946 | /* | 932 | /* |
947 | * Reset the breakpoint resources. We assume that a halting | 933 | * Reset the breakpoint resources. We assume that a halting |
@@ -950,7 +936,6 @@ static int __init arch_hw_breakpoint_init(void) | |||
950 | on_each_cpu(reset_ctrl_regs, &cpumask, 1); | 936 | on_each_cpu(reset_ctrl_regs, &cpumask, 1); |
951 | if (!cpumask_empty(&cpumask)) { | 937 | if (!cpumask_empty(&cpumask)) { |
952 | core_num_brps = 0; | 938 | core_num_brps = 0; |
953 | core_num_reserved_brps = 0; | ||
954 | core_num_wrps = 0; | 939 | core_num_wrps = 0; |
955 | return 0; | 940 | return 0; |
956 | } | 941 | } |