Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 948f4f0d authored by Colin Cross's avatar Colin Cross Committed by Ruchi Kandoi
Browse files

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: default avatarColin Cross <ccross@android.com>
parent 633e92cb
Loading
Loading
Loading
Loading
+62 −5
Original line number Diff line number Diff line
@@ -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);