|
@@ -857,11 +857,31 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
|
|
/*
|
|
/*
|
|
* One-time initialisation.
|
|
* One-time initialisation.
|
|
*/
|
|
*/
|
|
-static void reset_ctrl_regs(void *info)
|
|
|
|
|
|
+static cpumask_t debug_err_mask;
|
|
|
|
+
|
|
|
|
+static int debug_reg_trap(struct pt_regs *regs, unsigned int instr)
|
|
|
|
+{
|
|
|
|
+ int cpu = smp_processor_id();
|
|
|
|
+
|
|
|
|
+ pr_warning("Debug register access (0x%x) caused undefined instruction on CPU %d\n",
|
|
|
|
+ instr, cpu);
|
|
|
|
+
|
|
|
|
+ /* Set the error flag for this CPU and skip the faulting instruction. */
|
|
|
|
+ cpumask_set_cpu(cpu, &debug_err_mask);
|
|
|
|
+ instruction_pointer(regs) += 4;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct undef_hook debug_reg_hook = {
|
|
|
|
+ .instr_mask = 0x0fe80f10,
|
|
|
|
+ .instr_val = 0x0e000e10,
|
|
|
|
+ .fn = debug_reg_trap,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void reset_ctrl_regs(void *unused)
|
|
{
|
|
{
|
|
int i, raw_num_brps, err = 0, cpu = smp_processor_id();
|
|
int i, raw_num_brps, err = 0, cpu = smp_processor_id();
|
|
u32 dbg_power;
|
|
u32 dbg_power;
|
|
- cpumask_t *cpumask = info;
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* v7 debug contains save and restore registers so that debug state
|
|
* v7 debug contains save and restore registers so that debug state
|
|
@@ -893,7 +913,7 @@ static void reset_ctrl_regs(void *info)
|
|
|
|
|
|
if (err) {
|
|
if (err) {
|
|
pr_warning("CPU %d debug is powered down!\n", cpu);
|
|
pr_warning("CPU %d debug is powered down!\n", cpu);
|
|
- cpumask_or(cpumask, cpumask, cpumask_of(cpu));
|
|
|
|
|
|
+ cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu));
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -932,6 +952,7 @@ static int __cpuinit dbg_reset_notify(struct notifier_block *self,
|
|
{
|
|
{
|
|
if (action == CPU_ONLINE)
|
|
if (action == CPU_ONLINE)
|
|
smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1);
|
|
smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1);
|
|
|
|
+
|
|
return NOTIFY_OK;
|
|
return NOTIFY_OK;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -942,7 +963,6 @@ static struct notifier_block __cpuinitdata dbg_reset_nb = {
|
|
static int __init arch_hw_breakpoint_init(void)
|
|
static int __init arch_hw_breakpoint_init(void)
|
|
{
|
|
{
|
|
u32 dscr;
|
|
u32 dscr;
|
|
- cpumask_t cpumask = { CPU_BITS_NONE };
|
|
|
|
|
|
|
|
debug_arch = get_debug_arch();
|
|
debug_arch = get_debug_arch();
|
|
|
|
|
|
@@ -955,21 +975,29 @@ static int __init arch_hw_breakpoint_init(void)
|
|
core_num_brps = get_num_brps();
|
|
core_num_brps = get_num_brps();
|
|
core_num_wrps = get_num_wrps();
|
|
core_num_wrps = get_num_wrps();
|
|
|
|
|
|
- pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n",
|
|
|
|
- core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " :
|
|
|
|
- "", core_num_wrps);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * We need to tread carefully here because DBGSWENABLE may be
|
|
|
|
+ * driven low on this core and there isn't an architected way to
|
|
|
|
+ * determine that.
|
|
|
|
+ */
|
|
|
|
+ register_undef_hook(&debug_reg_hook);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Reset the breakpoint resources. We assume that a halting
|
|
* Reset the breakpoint resources. We assume that a halting
|
|
* debugger will leave the world in a nice state for us.
|
|
* debugger will leave the world in a nice state for us.
|
|
*/
|
|
*/
|
|
- on_each_cpu(reset_ctrl_regs, &cpumask, 1);
|
|
|
|
- if (!cpumask_empty(&cpumask)) {
|
|
|
|
|
|
+ on_each_cpu(reset_ctrl_regs, NULL, 1);
|
|
|
|
+ unregister_undef_hook(&debug_reg_hook);
|
|
|
|
+ if (!cpumask_empty(&debug_err_mask)) {
|
|
core_num_brps = 0;
|
|
core_num_brps = 0;
|
|
core_num_wrps = 0;
|
|
core_num_wrps = 0;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n",
|
|
|
|
+ core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " :
|
|
|
|
+ "", core_num_wrps);
|
|
|
|
+
|
|
ARM_DBG_READ(c1, 0, dscr);
|
|
ARM_DBG_READ(c1, 0, dscr);
|
|
if (dscr & ARM_DSCR_HDBGEN) {
|
|
if (dscr & ARM_DSCR_HDBGEN) {
|
|
max_watchpoint_len = 4;
|
|
max_watchpoint_len = 4;
|