diff options
author | Will Deacon <will.deacon@arm.com> | 2010-12-01 12:37:45 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2010-12-15 07:31:03 -0500 |
commit | 8fbf397c3389c1dedfa9ee412715046ab28fd82d (patch) | |
tree | b363718fb46602f882cfb58d372ec6746e3f92c5 /arch/arm/kernel/hw_breakpoint.c | |
parent | 4a55c18e2023096c8684fae5fa1cfa96a03172ff (diff) |
ARM: hw_breakpoint: do not fail initcall if monitor mode is disabled
The debug registers can only be manipulated from software if monitor
debug mode is enabled. On some cores, this can never be enabled (i.e.
the corresponding bit in the DSCR is RAZ/WI).
This patch ensures we can handle this hardware configuration and fail
gracefully, rather than blow up the kernel during boot.
Reported-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm/kernel/hw_breakpoint.c')
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 54 |
1 files changed, 25 insertions, 29 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 56ed9a62013b..c9f3f0467570 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c | |||
@@ -219,23 +219,6 @@ static int get_num_brps(void) | |||
219 | return brps; | 219 | return brps; |
220 | } | 220 | } |
221 | 221 | ||
222 | int hw_breakpoint_slots(int type) | ||
223 | { | ||
224 | /* | ||
225 | * We can be called early, so don't rely on | ||
226 | * our static variables being initialised. | ||
227 | */ | ||
228 | switch (type) { | ||
229 | case TYPE_INST: | ||
230 | return get_num_brps(); | ||
231 | case TYPE_DATA: | ||
232 | return get_num_wrps(); | ||
233 | default: | ||
234 | pr_warning("unknown slot type: %d\n", type); | ||
235 | return 0; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /* | 222 | /* |
240 | * In order to access the breakpoint/watchpoint control registers, | 223 | * In order to access the breakpoint/watchpoint control registers, |
241 | * we must be running in debug monitor mode. Unfortunately, we can | 224 | * we must be running in debug monitor mode. Unfortunately, we can |
@@ -256,8 +239,12 @@ static int enable_monitor_mode(void) | |||
256 | goto out; | 239 | goto out; |
257 | } | 240 | } |
258 | 241 | ||
242 | /* If monitor mode is already enabled, just return. */ | ||
243 | if (dscr & ARM_DSCR_MDBGEN) | ||
244 | goto out; | ||
245 | |||
259 | /* Write to the corresponding DSCR. */ | 246 | /* Write to the corresponding DSCR. */ |
260 | switch (debug_arch) { | 247 | switch (get_debug_arch()) { |
261 | case ARM_DEBUG_ARCH_V6: | 248 | case ARM_DEBUG_ARCH_V6: |
262 | case ARM_DEBUG_ARCH_V6_1: | 249 | case ARM_DEBUG_ARCH_V6_1: |
263 | ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN)); | 250 | ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN)); |
@@ -272,15 +259,30 @@ static int enable_monitor_mode(void) | |||
272 | 259 | ||
273 | /* Check that the write made it through. */ | 260 | /* Check that the write made it through. */ |
274 | ARM_DBG_READ(c1, 0, dscr); | 261 | ARM_DBG_READ(c1, 0, dscr); |
275 | if (WARN_ONCE(!(dscr & ARM_DSCR_MDBGEN), | 262 | if (!(dscr & ARM_DSCR_MDBGEN)) |
276 | "failed to enable monitor mode.")) { | ||
277 | ret = -EPERM; | 263 | ret = -EPERM; |
278 | } | ||
279 | 264 | ||
280 | out: | 265 | out: |
281 | return ret; | 266 | return ret; |
282 | } | 267 | } |
283 | 268 | ||
269 | int hw_breakpoint_slots(int type) | ||
270 | { | ||
271 | /* | ||
272 | * We can be called early, so don't rely on | ||
273 | * our static variables being initialised. | ||
274 | */ | ||
275 | switch (type) { | ||
276 | case TYPE_INST: | ||
277 | return get_num_brps(); | ||
278 | case TYPE_DATA: | ||
279 | return get_num_wrps(); | ||
280 | default: | ||
281 | pr_warning("unknown slot type: %d\n", type); | ||
282 | return 0; | ||
283 | } | ||
284 | } | ||
285 | |||
284 | /* | 286 | /* |
285 | * Check if 8-bit byte-address select is available. | 287 | * Check if 8-bit byte-address select is available. |
286 | * This clobbers WRP 0. | 288 | * This clobbers WRP 0. |
@@ -294,9 +296,6 @@ static u8 get_max_wp_len(void) | |||
294 | if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14) | 296 | if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14) |
295 | goto out; | 297 | goto out; |
296 | 298 | ||
297 | if (enable_monitor_mode()) | ||
298 | goto out; | ||
299 | |||
300 | memset(&ctrl, 0, sizeof(ctrl)); | 299 | memset(&ctrl, 0, sizeof(ctrl)); |
301 | ctrl.len = ARM_BREAKPOINT_LEN_8; | 300 | ctrl.len = ARM_BREAKPOINT_LEN_8; |
302 | ctrl_reg = encode_ctrl_reg(ctrl); | 301 | ctrl_reg = encode_ctrl_reg(ctrl); |
@@ -879,15 +878,13 @@ static struct notifier_block __cpuinitdata dbg_reset_nb = { | |||
879 | 878 | ||
880 | static int __init arch_hw_breakpoint_init(void) | 879 | static int __init arch_hw_breakpoint_init(void) |
881 | { | 880 | { |
882 | int ret = 0; | ||
883 | u32 dscr; | 881 | u32 dscr; |
884 | 882 | ||
885 | debug_arch = get_debug_arch(); | 883 | debug_arch = get_debug_arch(); |
886 | 884 | ||
887 | if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) { | 885 | if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) { |
888 | pr_info("debug architecture 0x%x unsupported.\n", debug_arch); | 886 | pr_info("debug architecture 0x%x unsupported.\n", debug_arch); |
889 | ret = -ENODEV; | 887 | return 0; |
890 | goto out; | ||
891 | } | 888 | } |
892 | 889 | ||
893 | /* Determine how many BRPs/WRPs are available. */ | 890 | /* Determine how many BRPs/WRPs are available. */ |
@@ -928,8 +925,7 @@ static int __init arch_hw_breakpoint_init(void) | |||
928 | 925 | ||
929 | /* Register hotplug notifier. */ | 926 | /* Register hotplug notifier. */ |
930 | register_cpu_notifier(&dbg_reset_nb); | 927 | register_cpu_notifier(&dbg_reset_nb); |
931 | out: | 928 | return 0; |
932 | return ret; | ||
933 | } | 929 | } |
934 | arch_initcall(arch_hw_breakpoint_init); | 930 | arch_initcall(arch_hw_breakpoint_init); |
935 | 931 | ||