ARM: fiq_debugger: add process context reboot command

kernel_restart cannot be called from interrupt context.  Add support for
commands called from a work function, and implement the "reboot" command
there.  Also rename the existing irq-mode command to "reset" and change
it to use machine_restart instead of kernel_restart.

Change-Id: I3c423147c01db03d89e95a5b99096ca89462079f
Signed-off-by: Colin Cross <ccross@android.com>
This commit is contained in:
Colin Cross 2012-07-19 18:40:04 -07:00 committed by John Stultz
parent 30f1c58cc5
commit 05c369015c

View file

@ -81,6 +81,10 @@ struct fiq_debugger_state {
atomic_t unhandled_fiq_count;
bool in_fiq;
struct work_struct work;
spinlock_t work_lock;
char work_cmd[DEBUG_MAX];
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
struct console console;
struct tty_struct *tty;
@ -557,6 +561,53 @@ static void do_kgdb(struct fiq_debugger_state *state)
}
#endif
static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd)
{
unsigned long flags;
spin_lock_irqsave(&state->work_lock, flags);
if (state->work_cmd[0] != '\0') {
debug_printf(state, "work command processor busy\n");
spin_unlock_irqrestore(&state->work_lock, flags);
return;
}
strlcpy(state->work_cmd, cmd, sizeof(state->work_cmd));
spin_unlock_irqrestore(&state->work_lock, flags);
schedule_work(&state->work);
}
static void debug_work(struct work_struct *work)
{
struct fiq_debugger_state *state;
char work_cmd[DEBUG_MAX];
char *cmd;
unsigned long flags;
state = container_of(work, struct fiq_debugger_state, work);
spin_lock_irqsave(&state->work_lock, flags);
strlcpy(work_cmd, state->work_cmd, sizeof(work_cmd));
state->work_cmd[0] = '\0';
spin_unlock_irqrestore(&state->work_lock, flags);
cmd = work_cmd;
if (!strncmp(cmd, "reboot", 6)) {
cmd += 6;
while (*cmd == ' ')
cmd++;
if (cmd != '\0')
kernel_restart(cmd);
else
kernel_restart(NULL);
} else {
debug_printf(state, "unknown work command '%s'\n", work_cmd);
}
}
/* This function CANNOT be called in FIQ context */
static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd)
{
@ -570,6 +621,8 @@ static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd)
if (!strcmp(cmd, "kgdb"))
do_kgdb(state);
#endif
if (!strncmp(cmd, "reboot", 6))
debug_schedule_work(state, cmd);
}
static void debug_help(struct fiq_debugger_state *state)
@ -579,7 +632,8 @@ static void debug_help(struct fiq_debugger_state *state)
" regs Register dump\n"
" allregs Extended Register dump\n"
" bt Stack trace\n"
" reboot Reboot\n"
" reboot [<c>] Reboot with command <c>\n"
" reset [<c>] Hard reset with command <c>\n"
" irqs Interupt status\n"
" kmsg Kernel log\n"
" version Kernel version\n");
@ -630,16 +684,16 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state,
dump_allregs(state, regs);
} else if (!strcmp(cmd, "bt")) {
dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp);
} else if (!strncmp(cmd, "reboot", 6)) {
cmd += 6;
} else if (!strncmp(cmd, "reset", 5)) {
cmd += 5;
while (*cmd == ' ')
cmd++;
if (*cmd) {
char tmp_cmd[32];
strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd));
kernel_restart(tmp_cmd);
machine_restart(tmp_cmd);
} else {
kernel_restart(NULL);
machine_restart(NULL);
}
} else if (!strcmp(cmd, "irqs")) {
dump_irqs(state);
@ -1189,6 +1243,9 @@ static int fiq_debugger_probe(struct platform_device *pdev)
state->signal_irq = platform_get_irq_byname(pdev, "signal");
state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
INIT_WORK(&state->work, debug_work);
spin_lock_init(&state->work_lock);
platform_set_drvdata(pdev, state);
spin_lock_init(&state->sleep_timer_lock);