#include <asm/fiq_glue.h>
#endif
+#ifdef CONFIG_FIQ_DEBUGGER_UART_OVERLAY
+#include <linux/of.h>
+#endif
+
#include <linux/uaccess.h>
-#include <linux/rockchip/grf.h>
-#include <linux/rockchip/iomap.h>
-#include <linux/rockchip/cpu.h>
#include "fiq_debugger.h"
#include "fiq_debugger_priv.h"
#include "fiq_debugger_ringbuf.h"
-#ifdef CONFIG_RK29_WATCHDOG
-extern void rk29_wdt_keepalive(void);
-#define wdt_keepalive() rk29_wdt_keepalive()
-#else
-#define wdt_keepalive() do {} while (0)
-#endif
#define DEBUG_MAX 64
-#define CMD_COUNT 0x0f
#define MAX_UNHANDLED_FIQ_COUNT 1000000
-#ifdef CONFIG_ARCH_ROCKCHIP
-#define MAX_FIQ_DEBUGGER_PORTS 1
-#else
#define MAX_FIQ_DEBUGGER_PORTS 4
-#endif
struct fiq_debugger_state {
#ifdef CONFIG_FIQ_GLUE
char debug_buf[DEBUG_MAX];
int debug_count;
-#ifdef CONFIG_ARCH_ROCKCHIP
- char cmd_buf[CMD_COUNT+1][DEBUG_MAX];
- int back_pointer;
- int current_pointer;
-#endif
bool no_sleep;
bool debug_enable;
bool ignore_next_wakeup_irq;
bool syslog_dumping;
#endif
-#ifdef CONFIG_ARCH_ROCKCHIP
- unsigned int last_irqs[1024];
- unsigned int last_local_irqs[NR_CPUS][32];
-#else
unsigned int last_irqs[NR_IRQS];
unsigned int last_local_timer_irqs[NR_CPUS];
-#endif
};
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
#endif
static bool fiq_kgdb_enable;
-
-static unsigned long jif = 0, recv_count0 = 0, recv_count1 = 0;
+static bool fiq_debugger_disable;
module_param_named(no_sleep, initial_no_sleep, bool, 0644);
module_param_named(debug_enable, initial_debug_enable, bool, 0644);
module_param_named(console_enable, initial_console_enable, bool, 0644);
module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644);
-
-void gic_set_irq_secure(struct irq_data *d);
-void gic_set_irq_priority(struct irq_data *d, u8 pri);
+module_param_named(disable, fiq_debugger_disable, bool, 0644);
#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
static inline
static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state)
{
-#ifdef CONFIG_ARCH_ROCKCHIP
- char buf[968];
-#else
char buf[512];
-#endif
size_t len;
struct kmsg_dumper dumper = { .active = true };
sizeof(buf) - 1, &len)) {
buf[len] = 0;
fiq_debugger_puts(state, buf);
-#ifdef CONFIG_ARCH_ROCKCHIP
- wdt_keepalive();
-#endif
}
}
-#ifdef CONFIG_RK_LAST_LOG
-#include <linux/ctype.h>
-extern char *rk_last_log_get(unsigned *size);
-static void fiq_debugger_dump_last_kernel_log(struct fiq_debugger_state *state)
-{
- unsigned size, i, c;
- char *s = rk_last_log_get(&size);
-
- for (i = 0; i < size; i++) {
- if (i % 1024 == 0)
- wdt_keepalive();
- c = s[i];
- if (c == '\n') {
- state->pdata->uart_putc(state->pdev, '\r');
- state->pdata->uart_putc(state->pdev, c);
- } else if (isascii(c) && isprint(c)) {
- state->pdata->uart_putc(state->pdev, c);
- }
- }
-}
-#endif
-
static void fiq_debugger_printf(struct fiq_debugger_output *output,
const char *fmt, ...)
{
static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state)
{
int n;
- unsigned int cpu;
struct irq_desc *desc;
fiq_debugger_printf(&state->output,
(act && act->name) ? act->name : "???");
state->last_irqs[n] = kstat_irqs(n);
}
-
-#ifdef CONFIG_ARCH_ROCKCHIP
- for (n = 16; n < 32; n++) {
- desc = irq_to_desc(n);
- if (!desc)
- continue;
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- unsigned int irqs = kstat_irqs_cpu(n, cpu);
- struct irqaction *act = desc->action;
- const char *name = (act && act->name) ? act->name : "???";
- if (!irqs)
- continue;
- fiq_debugger_printf(&state->output,
- "%5d: %10u %11u %s (CPU%d)\n", n,
- irqs, irqs - state->last_local_irqs[cpu][n],
- name, cpu);
- state->last_local_irqs[cpu][n] = irqs;
- }
- }
- for (n = 0; n < NR_IPI; n++) {
-#define S(x,s) [x] = s
-#ifdef CONFIG_ARM
- enum ipi_msg_type {
- IPI_WAKEUP,
- IPI_TIMER,
- IPI_RESCHEDULE,
- IPI_CALL_FUNC,
- IPI_CALL_FUNC_SINGLE,
- IPI_CPU_STOP,
- IPI_COMPLETION,
- IPI_CPU_BACKTRACE,
- };
- static const char *ipi_types[NR_IPI] = {
- S(IPI_WAKEUP, "CPU wakeup"),
- S(IPI_TIMER, "Timer broadcast"),
- S(IPI_RESCHEDULE, "Rescheduling"),
- S(IPI_CALL_FUNC, "Function call"),
- S(IPI_CALL_FUNC_SINGLE, "Single function call"),
- S(IPI_CPU_STOP, "CPU stop"),
- S(IPI_COMPLETION, "Completion"),
- S(IPI_CPU_BACKTRACE, "CPU backtrace"),
- };
-#elif defined(CONFIG_ARM64)
- enum ipi_msg_type {
- IPI_RESCHEDULE,
- IPI_CALL_FUNC,
- IPI_CALL_FUNC_SINGLE,
- IPI_CPU_STOP,
- IPI_TIMER,
- };
- static const char *ipi_types[NR_IPI] = {
- S(IPI_RESCHEDULE, "Rescheduling"),
- S(IPI_CALL_FUNC, "Function call"),
- S(IPI_CALL_FUNC_SINGLE, "Single function call"),
- S(IPI_CPU_STOP, "CPU stop"),
- S(IPI_TIMER, "Timer broadcast"),
- };
-#endif
-#undef S
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- unsigned int irqs = __get_irq_stat(cpu, ipi_irqs[n]);
- if (irqs == 0)
- continue;
- fiq_debugger_printf(&state->output,
- "%5d: %10u %11u %s (CPU%d)\n",
- n, irqs, irqs - state->last_local_irqs[cpu][n],
- ipi_types[n], cpu);
- state->last_local_irqs[cpu][n] = irqs;
- }
- }
-#endif
}
static void fiq_debugger_do_ps(struct fiq_debugger_state *state)
/* This function CANNOT be called in FIQ context */
static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd)
{
- int invalid_cmd = 0;
if (!strcmp(cmd, "ps"))
fiq_debugger_do_ps(state);
if (!strcmp(cmd, "sysrq"))
#endif
if (!strncmp(cmd, "reboot", 6))
fiq_debugger_schedule_work(state, cmd);
-#ifdef CONFIG_ARCH_ROCKCHIP
- else {
- invalid_cmd = 1;
- memset(state->debug_buf, 0, DEBUG_MAX);
- }
-
- if (invalid_cmd == 0) {
- state->current_pointer = (state->current_pointer-1) & CMD_COUNT;
- if (strcmp(state->cmd_buf[state->current_pointer], state->debug_buf)) {
- state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
- memset(state->cmd_buf[state->current_pointer], 0, DEBUG_MAX);
- strcpy(state->cmd_buf[state->current_pointer], state->debug_buf);
- }
- memset(state->debug_buf, 0, DEBUG_MAX);
- state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
- state->back_pointer = state->current_pointer;
- }
-#endif
}
-#ifdef CONFIG_ARCH_ROCKCHIP
-static char cmd_buf[][16] = {
- {"pc"},
- {"regs"},
- {"allregs"},
- {"bt"},
- {"reboot"},
- {"irqs"},
- {"kmsg"},
-#ifdef CONFIG_RK_LAST_LOG
- {"last_kmsg"},
-#endif
- {"version"},
- {"sleep"},
- {"nosleep"},
- {"console"},
- {"cpu"},
- {"ps"},
- {"sysrq"},
- {"reset"},
-#ifdef CONFIG_KGDB
- {"kgdb"},
-#endif
-};
-#endif
-
-
static void fiq_debugger_help(struct fiq_debugger_state *state)
{
fiq_debugger_printf(&state->output,
" irqs Interupt status\n"
" kmsg Kernel log\n"
" version Kernel version\n");
-#ifdef CONFIG_RK_LAST_LOG
- fiq_debugger_printf(&state->output,
- " last_kmsg Last kernel log\n");
-#endif
fiq_debugger_printf(&state->output,
" sleep Allow sleep while in FIQ\n"
" nosleep Disable sleep while in FIQ\n"
if (!fiq_debugger_have_fiq(state))
smp_call_function_single(cpu, fiq_debugger_take_affinity, state,
false);
-#ifdef CONFIG_ARCH_ROCKCHIP
- else {
- struct cpumask cpumask;
-
- if (!cpu_online(cpu)) {
- fiq_debugger_printf(&state->output, "cpu %d offline\n", cpu);
- return;
- }
-
- cpumask_clear(&cpumask);
- cpumask_set_cpu(cpu, &cpumask);
-
- irq_set_affinity(state->fiq, &cpumask);
- irq_set_affinity(state->uart_irq, &cpumask);
- }
-#endif
state->current_cpu = cpu;
}
if (*cmd) {
char tmp_cmd[32];
strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd));
+ blocking_notifier_call_chain(&reboot_notifier_list,
+ SYS_RESTART, (char *)cmd);
machine_restart(tmp_cmd);
} else {
machine_restart(NULL);
fiq_debugger_dump_irqs(state);
} else if (!strcmp(cmd, "kmsg")) {
fiq_debugger_dump_kernel_log(state);
-#ifdef CONFIG_RK_LAST_LOG
- } else if (!strcmp(cmd, "last_kmsg")) {
- fiq_debugger_dump_last_kernel_log(state);
-#endif
} else if (!strcmp(cmd, "version")) {
fiq_debugger_printf(&state->output, "%s\n", linux_banner);
} else if (!strcmp(cmd, "sleep")) {
fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
} else if (!strncmp(cmd, "cpu ", 4)) {
unsigned long cpu = 0;
- if (strict_strtoul(cmd + 4, 10, &cpu) == 0)
+ if (kstrtoul(cmd + 4, 10, &cpu) == 0)
fiq_debugger_switch_cpu(state, cpu);
else
fiq_debugger_printf(&state->output, "invalid cpu\n");
return state->pdata->uart_getc(state->pdev);
}
-static int fiq_debugger_cmd_check_back(struct fiq_debugger_state *state, char c)
-{
- char *s;
- int i = 0;
- if (c == 'A') {
- state->back_pointer = (state->back_pointer-1) & CMD_COUNT;
- if (state->back_pointer != state->current_pointer) {
- s = state->cmd_buf[state->back_pointer];
- if (*s != 0) {
- for(i = 0; i < strlen(state->debug_buf)-1; i++) {
- state->pdata->uart_putc(state->pdev, 8);
- state->pdata->uart_putc(state->pdev, ' ');
- state->pdata->uart_putc(state->pdev, 8);
- }
- memset(state->debug_buf, 0, DEBUG_MAX);
- strcpy(state->debug_buf, s);
- state->debug_count = strlen(state->debug_buf);
- fiq_debugger_printf(&state->output, state->debug_buf);
- } else {
- state->back_pointer = (state->back_pointer+1) & CMD_COUNT;
- }
-
- } else {
- state->back_pointer = (state->back_pointer+1) & CMD_COUNT;
- }
- } else if (c == 'B') {
-
- if (state->back_pointer != state->current_pointer) {
- state->back_pointer = (state->back_pointer+1) & CMD_COUNT;
- if(state->back_pointer == state->current_pointer){
- goto cmd_clear;
- } else {
- s = state->cmd_buf[state->back_pointer];
- if (*s != 0) {
- for(i = 0; i < strlen(state->debug_buf)-1; i++) {
- state->pdata->uart_putc(state->pdev, 8);
- state->pdata->uart_putc(state->pdev, ' ');
- state->pdata->uart_putc(state->pdev, 8);
- }
- memset(state->debug_buf, 0, DEBUG_MAX);
- strcpy(state->debug_buf, s);
- state->debug_count = strlen(state->debug_buf);
- fiq_debugger_printf(&state->output, state->debug_buf);
- }
- }
- } else {
-cmd_clear:
- for(i = 0; i < strlen(state->debug_buf)-1; i++) {
- state->pdata->uart_putc(state->pdev, 8);
- state->pdata->uart_putc(state->pdev, ' ');
- state->pdata->uart_putc(state->pdev, 8);
- }
- memset(state->debug_buf, 0, DEBUG_MAX);
- state->debug_count = 0;
- }
- }
- return 0;
-}
-
-static void fiq_debugger_cmd_tab(struct fiq_debugger_state *state)
-{
- int i,j;
- int count = 0;
-
- for (i = 0; i < ARRAY_SIZE(cmd_buf); i++) {
- cmd_buf[i][15] = 1;
- }
-
- for (j = 1; j <= strlen(state->debug_buf); j++) {
- count = 0;
- for (i = 0; i < ARRAY_SIZE(cmd_buf); i++) {
- if (cmd_buf[i][15] == 1) {
- if (strncmp(state->debug_buf, cmd_buf[i], j)) {
- cmd_buf[i][15] = 0;
- } else {
- count++;
- }
- }
- }
- if (count == 0)
- break;
- }
-
- if (count == 1) {
- for (i = 0; i < ARRAY_SIZE(cmd_buf); i++) {
- if (cmd_buf[i][15] == 1)
- break;
- }
-
- for(j = 0; j < strlen(state->debug_buf); j++) {
- state->pdata->uart_putc(state->pdev, 8);
- state->pdata->uart_putc(state->pdev, ' ');
- state->pdata->uart_putc(state->pdev, 8);
- }
- memset(state->debug_buf, 0, DEBUG_MAX);
- strcpy(state->debug_buf, cmd_buf[i]);
- state->debug_count = strlen(state->debug_buf);
- fiq_debugger_printf(&state->output, state->debug_buf);
-
- }
-}
-
static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state,
int this_cpu, const struct pt_regs *regs, void *svc_sp)
{
static int last_c;
int count = 0;
bool signal_helper = false;
- unsigned long ms = 0;
- if (this_cpu != state->current_cpu) {
+ if ((this_cpu != state->current_cpu) && (cpu_online(state->current_cpu))) {
if (state->in_fiq)
return false;
return false;
}
+ if (this_cpu != state->current_cpu)
+ state->current_cpu = this_cpu;
+
state->in_fiq = true;
while ((c = fiq_debugger_getc(state)) != FIQ_DEBUGGER_NO_CHAR) {
- recv_count0++;
- if((recv_count0 - recv_count1) > 128) {
- ms = jiffies_to_msecs(jiffies - jif);
- if(ms < 1000) {
- if(cpu_is_rk3288()){
- writel_relaxed((0x00c0 << 16),
- RK_GRF_VIRT + RK3288_GRF_UOC0_CON3);
- }
- }
- jif = jiffies;
- recv_count1 = recv_count0;
- }
- count++;
+ count++;
if (!state->debug_enable) {
if ((c == 13) || (c == 10)) {
state->debug_enable = true;
}
} else if (c == FIQ_DEBUGGER_BREAK) {
state->console_enable = false;
-#ifdef CONFIG_ARCH_ROCKCHIP
- fiq_debugger_puts(state, "\nWelcome to ");
-#endif
fiq_debugger_puts(state, "fiq debugger mode\n");
state->debug_count = 0;
-#ifdef CONFIG_ARCH_ROCKCHIP
- fiq_debugger_puts(state, "Enter ? to get command help\n");
- state->back_pointer = CMD_COUNT;
- state->current_pointer = CMD_COUNT;
- memset(state->cmd_buf, 0, (CMD_COUNT+1)*DEBUG_MAX);
-#endif
fiq_debugger_prompt(state);
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
} else if (state->console_enable && state->tty_rbuf) {
fiq_debugger_ringbuf_push(state->tty_rbuf, c);
signal_helper = true;
-#endif
-#ifdef CONFIG_ARCH_ROCKCHIP
- } else if (last_c == '[' && (c == 'A' || c == 'B' || c == 'C' || c == 'D')) {
- if (state->debug_count > 0) {
- state->debug_count--;
- state->pdata->uart_putc(state->pdev, 8);
- state->pdata->uart_putc(state->pdev, ' ');
- state->pdata->uart_putc(state->pdev, 8);
- }
- fiq_debugger_cmd_check_back(state, c);
- //tab
- } else if (c == 9) {
- fiq_debugger_cmd_tab(state);
#endif
} else if ((c >= ' ') && (c < 127)) {
if (state->debug_count < (DEBUG_MAX - 1)) {
signal_helper |=
fiq_debugger_fiq_exec(state,
state->debug_buf,
- regs, svc_sp);
-#ifdef CONFIG_ARCH_ROCKCHIP
- if (signal_helper == false) {
- state->current_pointer = (state->current_pointer-1) & CMD_COUNT;
- if (strcmp(state->cmd_buf[state->current_pointer], state->debug_buf)) {
- state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
- memset(state->cmd_buf[state->current_pointer], 0, DEBUG_MAX);
- strcpy(state->cmd_buf[state->current_pointer], state->debug_buf);
- }
- memset(state->debug_buf, 0, DEBUG_MAX);
- state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
- state->back_pointer = state->current_pointer;
- }
-#endif
+ regs, svc_sp);
} else {
fiq_debugger_prompt(state);
}
#ifdef CONFIG_FIQ_GLUE
static void fiq_debugger_fiq(struct fiq_glue_handler *h,
- void *regs, void *svc_sp)
+ const struct pt_regs *regs, void *svc_sp)
{
struct fiq_debugger_state *state =
container_of(h, struct fiq_debugger_state, handler);
unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
bool need_irq;
- /* RK2928 USB-UART function, otg dp/dm default in uart status;
- * connect with otg cable&usb device, dp/dm will be hi-z status
- * and make uart controller enter infinite fiq loop
- */
-#ifdef CONFIG_RK_USB_UART
- if (cpu_is_rk3188()) {
- if (!(readl_relaxed(RK_GRF_VIRT + RK3188_GRF_SOC_STATUS0) & (1 << 13)) ||
- (readl_relaxed(RK_GRF_VIRT + RK3188_GRF_SOC_STATUS0) & (1 << 10))) {
- /* id low or bvalid high, enter usb phy */
- writel_relaxed((0x0300 << 16), RK_GRF_VIRT + RK3188_GRF_UOC0_CON0);
- }
- } else if (cpu_is_rk3288()) {
- if (!(readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_STATUS2) & (1 << 17)) ||
- (readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_STATUS2) & (1 << 14))) {
- /* id low or bvalid high, enter usb phy */
- writel_relaxed((0x00c0 << 16), RK_GRF_VIRT + RK3288_GRF_UOC0_CON3);
- }
- }
-#endif
need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs,
svc_sp);
if (need_irq)
pr_err("%s: could not install fiq handler\n", __func__);
goto err_register_irq;
}
-#ifdef CONFIG_ARCH_ROCKCHIP
- //set state->fiq to secure state, so fiq is avalable
- gic_set_irq_secure(irq_get_irq_data(state->fiq));
- //set state->fiq priority a little higher than other interrupts (normal is 0xa0)
- gic_set_irq_priority(irq_get_irq_data(state->fiq), 0x90);
-#endif
+
pdata->fiq_enable(pdev, state->fiq, 1);
} else
#endif
if (state->wakeup_irq >= 0) {
ret = request_irq(state->wakeup_irq,
fiq_debugger_wakeup_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+ IRQF_TRIGGER_FALLING,
"debug-wakeup", state);
if (ret) {
pr_err("serial_debugger: "
},
};
+#if defined(CONFIG_FIQ_DEBUGGER_UART_OVERLAY)
+int fiq_debugger_uart_overlay(void)
+{
+ struct device_node *onp = of_find_node_by_path("/uart_overlay@0");
+ int ret;
+
+ if (!onp) {
+ pr_err("serial_debugger: uart overlay not found\n");
+ return -ENODEV;
+ }
+
+ ret = of_overlay_create(onp);
+ if (ret < 0) {
+ pr_err("serial_debugger: fail to create overlay: %d\n", ret);
+ of_node_put(onp);
+ return ret;
+ }
+
+ pr_info("serial_debugger: uart overlay applied\n");
+ return 0;
+}
+#endif
+
static int __init fiq_debugger_init(void)
{
+ if (fiq_debugger_disable) {
+ pr_err("serial_debugger: disabled\n");
+ return -ENODEV;
+ }
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
fiq_debugger_tty_init();
+#endif
+#if defined(CONFIG_FIQ_DEBUGGER_UART_OVERLAY)
+ fiq_debugger_uart_overlay();
#endif
return platform_driver_register(&fiq_debugger_driver);
}