aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2012-07-19 18:40:04 -0700
committerArve Hjønnevåg <arve@android.com>2013-04-29 14:42:58 -0700
commit805ef38c2e2e1a7c10e0adb3d4b88dabe3db6fdd (patch)
tree681d556ac837fd668095683b60bef073ce4efaf2 /arch
parent73da5f759156e2065c4fd03dd1b8541511c8ff3e (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/common/fiq_debugger.c67
1 files changed, 62 insertions, 5 deletions
diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c
index ac952241fdd..a12810b5fb6 100644
--- a/arch/arm/common/fiq_debugger.c
+++ b/arch/arm/common/fiq_debugger.c
@@ -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);