一、fiq-debugger简介
fiq-debugger是一种集成到内核中的系统调试手段,主要用于Rockchip系列处理器的系统调试。
1.功能特点
它主要有以下功能特点:
FIQ中断集成:在arm架构中,FIQ(Fast Interrupt Request)相当于NMI(Non-Maskable Interrupt)中断。fiq-debugger将串口注册为FIQ中断,在串口FIQ中断服务程序中集成了一些系统调试命令。
调试场景适用性强:由于FIQ是不可屏蔽中断,因此fiq-debugger特别适用于调试CPU被hang住的情况。它可以在系统挂起时通过FIQ中断打印出CPU的故障现场,从而帮助开发者定位问题。
与console模式切换:fiq-debugger支持与console模式互相切换,使得开发者可以在调试过程中灵活地在两种模式之间切换。
2.配置和使用
1)内核配置
主要配置为以下3个配置项
CONFIG_FIQ_DEBUGGER // 使能fiq debugger
CONFIG_FIQ_DEBUGGER_CONSOLE // fiq debugger与console可以互相切换
CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE // 启动时默认串口在console模式
参考配置项
CONFIG配置:
CONFIG_FIQ_DEBUGGER=y
CONFIG_FIQ_DEBUGGER_NO_SLEEP=y
CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set
CONFIG_FIQ_DEBUGGER_CONSOLE=y
CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y
CONFIG_FIQ_DEBUGGER_TRUST_ZONE is not set
CONFIG_FIQ_DEBUGGER_UART_OVERLAY is not set
CONFIG_FIQ_WATCHDOG is not set
2)DTS设备树配置
fiq-debugger {
compatible = "rockchip,fiq-debugger";
rockchip,serial-id = <2>;
rockchip,wake-irq = <0>;
/* If enable uart uses irq instead of fiq */
rockchip,irq-mode-enable = <1>;
rockchip,baudrate = <115200>; /* Only 115200 and 1500000 */
interrupts = <GIC_SPI 252 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&uart2m0_xfer>;
status = "okay";
};
3)相关命令
debug> help
FIQ Debugger commands:
pc PC status
regs Register dump
allregs Extended Register dump
bt Stack trace
reboot [<c>] Reboot with command <c>
reset [<c>] Hard reset with command <c>
irqs Interupt status
sleep Allow sleep while in FIQ
nosleep Disable sleep while in FIQ
console Switch terminal to console
cpu Current CPU
cpu <number> Switch to CPU<number>
ps Process list
sysrq sysrq options
sysrq <param> Execute sysrq with <param>
二、fiq-debugger的核心代码实现
1.DTS配置文件的解析
主要分为以下步骤
①读取DTS文件中描述的"rockchip,serial-id"信息并赋值给serial_id
②读取DTS文件中描述的"rockchip,irq-mode-enable"信息并赋值给irq-mode
③map出irq中断并关联给signal_irq
④读取DTS文件中描述的"rockchip,wake-irq"信息并赋值给wake-irq
⑤读取DTS文件中描述的"rockchip,baudrate"信息并赋值给baudrate
⑥解析serial的硬件中断
⑦获取pclk和clk信息
⑧使能pclk和clk
⑨调用rk_serial_debug_init(base, phy_base, irq, signal_irq, wake_irq, baudrate)初始化设备
详细代码如下:
// 这个函数主要是去读取DTS文件里面的设备树配置项
static int __init rk_fiqdbg_probe(struct platform_device *pdev)
{
void __iomem *base; //base地址
struct device_node *np = pdev->dev.of_node;
unsigned int id, ok = 0;
int irq, signal_irq = -1, wake_irq = -1; //中断,3个中断
unsigned int baudrate = 0, irq_mode = 0; //端口号,irq模式
phys_addr_t phy_base = 0; //物理基地址
int serial_id;
struct clk *clk; //时钟clk
struct clk *pclk; //时钟pclk
struct of_phandle_args oirq;
struct resource res;
if (!of_device_is_available(np)) {
pr_err("fiq-debugger is disabled in device tree\n");
return -ENODEV;
}
//读取DTS文件中描述的"rockchip,serial-id"信息并赋值给serial_id
if (of_property_read_u32(np, "rockchip,serial-id", &serial_id))
return -EINVAL;
//读取DTS文件中描述的"rockchip,irq-mode-enable"信息并赋值给irq-mode
if (of_property_read_u32(np, "rockchip,irq-mode-enable", &irq_mode))
irq_mode = -1;
if (irq_mode == 1) {
signal_irq = -1;
} else {
//map出irq中断并关联给signal_irq
signal_irq = irq_of_parse_and_map(np, 0);
if (!signal_irq)
return -EINVAL;
}
//读取DTS文件中描述的"rockchip,wake-irq"信息并赋值给wake-irq
if (of_property_read_u32(np, "rockchip,wake-irq", &wake_irq))
wake_irq = -1;
//读取DTS文件中描述的"rockchip,baudrate"信息并赋值给baudrate
if (of_property_read_u32(np, "rockchip,baudrate", &baudrate))
baudrate = -1;
np = NULL;
do {
np = of_find_node_by_name(np, "serial");
if (np) {
id = of_alias_get_id(np, "serial");
if (id == serial_id) {
ok = 1;
break;
}
}
} while(np);
if (!ok)
return -EINVAL;
//解析serial的硬件中断
/* parse serial hw irq */
if (!of_irq_parse_one(np, 0, &oirq))
serial_hwirq = oirq.args[1] + 32;
/* parse serial phy base address */
if (!of_address_to_resource(np, 0, &res))
phy_base = res.start;
//获取pclk和clk信息
pclk = of_clk_get_by_name(np, "apb_pclk");
clk = of_clk_get_by_name(np, "baudclk");
if (unlikely(IS_ERR(clk)) || unlikely(IS_ERR(pclk))) {
pr_err("fiq-debugger get clock fail\n");
return -EINVAL;
}
//使能pclk和clk
clk_prepare_enable(clk);
clk_prepare_enable(pclk);
irq = irq_of_parse_and_map(np, 0);
if (!irq)
return -EINVAL;
base = of_iomap(np, 0);
if (base)
rk_serial_debug_init(base, phy_base,
irq, signal_irq, wake_irq, baudrate); //初始化设备,包括中断管理,端口号设置
return 0;
}
2.fiq debugger的device设备注册
①初始化rk_fiq_debugger结构体成员
t->irq = irq;
t->baudrate = baudrate;
t->pdata.uart_init = debug_port_init;
t->pdata.uart_getc = debug_getc;
t->pdata.uart_putc = debug_putc;
#ifndef CONFIG_RK_CONSOLE_THREAD
t->pdata.uart_flush = debug_flush;
#endif
t->pdata.fiq_enable = fiq_enable;
t->pdata.force_irq = NULL;
t->debug_port_base = base;
②确定使用fiq或者uart_irq(我们这里使用的是uart_irq)
res[0]对应的是uart_irq
res[1]对应的是signal_irq
res[2]对应的wake_irq未使能
③初始化rk_fiq_debugger结构体中的console_task成员,为一个console_thread线程,并关联console_write接口
④初始化pdev结构体成员
pdev->name = "fiq_debugger";
pdev->id = rk_fiq_debugger_id++;
pdev->dev.platform_data = &t->pdata;
pdev->resource = res;
pdev->num_resources = res_count;
⑤注册名为fiq_debugger的device设备
详细代码如下:
void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base,
int irq, int signal_irq,
int wakeup_irq, unsigned int baudrate)
{
struct rk_fiq_debugger *t = NULL;
struct platform_device *pdev = NULL;
struct resource *res = NULL;
int res_count = 0;
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
int ret = 0;
#endif
if (!base) {
pr_err("Invalid fiq debugger uart base\n");
return;
}
t = kzalloc(sizeof(struct rk_fiq_debugger), GFP_KERNEL);
if (!t) {
pr_err("Failed to allocate for fiq debugger\n");
return;
}
//初始化rk_fiq_debugger结构体成员
t->irq = irq;
t->baudrate = baudrate;
t->pdata.uart_init = debug_port_init;
t->pdata.uart_getc = debug_getc;
t->pdata.uart_putc = debug_putc;
#ifndef CONFIG_RK_CONSOLE_THREAD
t->pdata.uart_flush = debug_flush;
#endif
t->pdata.fiq_enable = fiq_enable;
t->pdata.force_irq = NULL;
t->debug_port_base = base;
res = kzalloc(sizeof(struct resource) * 3, GFP_KERNEL);
if (!res) {
pr_err("Failed to alloc fiq debugger resources\n");
goto out2;
}
pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
if (!pdev) {
pr_err("Failed to alloc fiq debugger platform device\n");
goto out3;
}
/* clear busy interrupt, make sure all interrupts are disabled */
rk_fiq_read(t, UART_USR);
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
if ((signal_irq > 0) && (serial_hwirq > 0)) {
ret = fiq_debugger_bind_sip_smc(t, phy_base, serial_hwirq,
signal_irq, baudrate);
if (ret)
tf_fiq_sup = false;
else
tf_fiq_sup = true;
}
#endif
//初始化res内容,关联中断信息
//res[0]对应的是uart_irq
//res[1]对应的是signal_irq
//res[2]对应的wake_irq未使能
if (irq > 0) {
res[0].flags = IORESOURCE_IRQ;
res[0].start = irq;
res[0].end = irq;
#if defined(CONFIG_FIQ_GLUE)
if (signal_irq > 0)
res[0].name = "fiq";
else
res[0].name = "uart_irq";
#elif defined(CONFIG_FIQ_DEBUGGER_TRUST_ZONE)
if (tf_fiq_sup && (signal_irq > 0))
res[0].name = "fiq";
else
res[0].name = "uart_irq";
#else
res[0].name = "uart_irq";
#endif
res_count++;
}
if (signal_irq > 0) {
res[1].flags = IORESOURCE_IRQ;
res[1].start = signal_irq;
res[1].end = signal_irq;
res[1].name = "signal";
res_count++;
}
if (wakeup_irq > 0) {
res[2].flags = IORESOURCE_IRQ;
res[2].start = wakeup_irq;
res[2].end = wakeup_irq;
res[2].name = "wakeup";
res_count++;
}
#ifdef CONFIG_RK_CONSOLE_THREAD
//初始化rk_fiq_debugger结构体中的console_task成员,为一个console_thread线程
t->console_task = kthread_run(console_thread, pdev, "kconsole");
if (!IS_ERR(t->console_task))
t->pdata.console_write = console_write; //关联console_write接口
#endif
//初始化pdev结构体成员
pdev->name = "fiq_debugger";
pdev->id = rk_fiq_debugger_id++;
pdev->dev.platform_data = &t->pdata;
pdev->resource = res;
pdev->num_resources = res_count;
//注册名为fiq_debugger的device设备
if (platform_device_register(pdev)) {
pr_err("Failed to register fiq debugger\n");
goto out4;
}
return;
out4:
kfree(pdev);
out3:
kfree(res);
out2:
kfree(t);
}
3.fiq debugger的输出线程
这个线程的特点是只要线程不被stop,则一直在判断fifo里是否存在日志信息,有就打印出来。详细代码如下:
static int console_thread(void *data)
{
struct platform_device *pdev = data;
char *buf = console_buf;
unsigned int len;
while (1) {
unsigned int dropped;
set_current_state(TASK_INTERRUPTIBLE);
//判断管道是否为空,为空则调度
if (kfifo_is_empty(&fifo))
schedule();
//线程是否应该stop,stop则关闭线程
if (kthread_should_stop())
break;
set_current_state(TASK_RUNNING);
//只要线程没有stop,则一直调用kfifo_out输出日志信息
while (!console_thread_stop) {
len = kfifo_out(&fifo, buf, LINE_MAX);
if (!len)
break; //如果fifo空,则当前没有日志可以输出,退出此次循环,等下次日志输出
console_put(pdev, buf, len);
}
dropped = console_dropped_messages;
if (dropped && !console_thread_stop) {
//如果存在drop的messages,并且当前线程未stop
console_dropped_messages = 0;
smp_wmb();
len = snprintf(buf, LINE_MAX,
"** %u console messages dropped **\n",
dropped);
console_put(pdev, buf, len);
}
if (!console_thread_stop)
console_flush(pdev);
}
return 0;
}
4.fiq debugger的驱动注册
主要是调用了fiq_debugger_tty_init接口,初始化完成后,注册fiq_debugger_driver驱动
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);
}
fiq_debugger_tty_init接口的实现流程如下:
①初始化fiq_tty_driver结构体,驱动的owner,名称,驱动的设备名称,驱动类型,驱动总线类型,驱动的状态,驱动的端口
②设置并关联tty_driver的操作接口
③注册fiq_tty_driver
详细代码如下:
static int fiq_debugger_tty_init(void)
{
int ret;
struct fiq_debugger_state **states = NULL;
states = kzalloc(sizeof(*states) * MAX_FIQ_DEBUGGER_PORTS, GFP_KERNEL);
if (!states) {
pr_err("Failed to allocate fiq debugger state structres\n");
return -ENOMEM;
}
fiq_tty_driver = alloc_tty_driver(MAX_FIQ_DEBUGGER_PORTS);
if (!fiq_tty_driver) {
pr_err("Failed to allocate fiq debugger tty\n");
ret = -ENOMEM;
goto err_free_state;
}
//初始化fiq_tty_driver结构体,,驱动的设备名称,驱动类型,驱动总线类型,驱动的状态,驱动的端口
fiq_tty_driver->owner = THIS_MODULE; //驱动的owner
fiq_tty_driver->driver_name = "fiq-debugger"; //名称
fiq_tty_driver->name = "ttyFIQ"; //设备名称
fiq_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; //类型
fiq_tty_driver->subtype = SERIAL_TYPE_NORMAL; //总线类型
fiq_tty_driver->init_termios = tty_std_termios;
fiq_tty_driver->flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV;
fiq_tty_driver->driver_state = states; //状态
fiq_tty_driver->init_termios.c_cflag =
B115200 | CS8 | CREAD | HUPCL | CLOCAL;
fiq_tty_driver->init_termios.c_ispeed = 115200; //端口
fiq_tty_driver->init_termios.c_ospeed = 115200; //端口
//设置并关联tty_driver的操作接口
tty_set_operations(fiq_tty_driver, &fiq_tty_driver_ops);
//注册fiq_tty_driver
ret = tty_register_driver(fiq_tty_driver);
if (ret) {
pr_err("Failed to register fiq tty: %d\n", ret);
goto err_free_tty;
}
pr_info("Registered FIQ tty driver\n");
return 0;
err_free_tty:
put_tty_driver(fiq_tty_driver);
fiq_tty_driver = NULL;
err_free_state:
kfree(states);
return ret;
}
5.fiq debugger的驱动probe
这里总结就是注册中断处理函数以及执行
①fiq和uart_irq中断二选一进行注册
②注册uart_irq中断处理函数
③注册signal_irq中断处理函数
④调用debug_port_init接口完成port的初始化
static int fiq_debugger_probe(struct platform_device *pdev)
{
int ret;
struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
struct fiq_debugger_state *state;
int fiq;
int uart_irq;
if (pdev->id >= MAX_FIQ_DEBUGGER_PORTS)
return -EINVAL;
if (!pdata->uart_getc || !pdata->uart_putc)
return -EINVAL;
if ((pdata->uart_enable && !pdata->uart_disable) ||
(!pdata->uart_enable && pdata->uart_disable))
return -EINVAL;
//通过fiq这个名称,找到对应的中断号
fiq = platform_get_irq_byname(pdev, "fiq");
//通过uart_irq这个名称,找到对应的中断号
uart_irq = platform_get_irq_byname(pdev, "uart_irq");
#ifndef CONFIG_ARCH_ROCKCHIP
/* uart_irq mode and fiq mode are mutually exclusive, but one of them
* is required */
//uart_irq和fiq二选一,不能同时成立,因为他们是冲突的,我们只能选择其中一个
if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0))
return -EINVAL;
if (fiq >= 0 && !pdata->fiq_enable)
return -EINVAL;
#endif
//初始化state结构体
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->output.printf = fiq_debugger_printf;
setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired,
(unsigned long)state);
state->pdata = pdata;
state->pdev = pdev;
state->no_sleep = initial_no_sleep;
state->debug_enable = initial_debug_enable;
state->console_enable = initial_console_enable;
state->fiq = fiq;
state->uart_irq = uart_irq;
//通过signal这个名称,找到对应的中断号
state->signal_irq = platform_get_irq_byname(pdev, "signal");
//通过wakeup这个名称,找到对应的中断号
state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
//关联fiq_debugger_work到state->work成员
INIT_WORK(&state->work, fiq_debugger_work);
spin_lock_init(&state->work_lock);
//设置driver数据内容
platform_set_drvdata(pdev, state);
spin_lock_init(&state->sleep_timer_lock);
if (state->wakeup_irq < 0 && fiq_debugger_have_fiq(state))
state->no_sleep = true;
state->ignore_next_wakeup_irq = !state->no_sleep;
wake_lock_init(&state->debugger_wake_lock,
WAKE_LOCK_SUSPEND, "serial-debug");
#ifdef CONFIG_ARCH_ROCKCHIP
if (uart_irq < 0 && fiq < 0)
goto console_out;
#endif
state->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(state->clk))
state->clk = NULL;
/* do not call pdata->uart_enable here since uart_init may still
* need to do some initialization before uart_enable can work.
* So, only try to manage the clock during init.
*/
if (state->clk)
clk_enable(state->clk);
//fiq和uart_irq二选一后,注册中断处理函数
if (fiq_debugger_have_fiq(state)) {
#ifdef CONFIG_FIQ_GLUE
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
if (sip_fiq_debugger_is_enabled()) {
} else
#endif
{
state->handler.fiq = fiq_debugger_fiq;
state->handler.resume = fiq_debugger_resume;
ret = fiq_glue_register_handler(&state->handler);
if (ret) {
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 available */
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);
}
#endif
} else {
//这里注册fiq_debugger_uart_irq为uart_irq中断的处理函数
ret = request_irq(state->uart_irq, fiq_debugger_uart_irq,
IRQF_NO_SUSPEND, "debug", state);
if (ret) {
pr_err("%s: could not install irq handler\n", __func__);
goto err_register_irq;
}
/* for irq-only mode, we want this irq to wake us up, if it
* can.
*/
enable_irq_wake(state->uart_irq);
}
if (state->signal_irq >= 0) {
//这里注册fiq_debugger_signal_irq为signal_irq中断的处理函数
ret = request_irq(state->signal_irq, fiq_debugger_signal_irq,
IRQF_TRIGGER_RISING, "debug-signal", state);
if (ret)
pr_err("serial_debugger: could not install signal_irq");
}
//wakeup_irq未使能,忽略,动作和uart_irq、signal_irq一样
if (state->wakeup_irq >= 0) {
ret = request_irq(state->wakeup_irq,
fiq_debugger_wakeup_irq_handler,
IRQF_TRIGGER_FALLING,
"debug-wakeup", state);
if (ret) {
pr_err("serial_debugger: "
"could not install wakeup irq\n");
state->wakeup_irq = -1;
} else {
ret = enable_irq_wake(state->wakeup_irq);
if (ret) {
pr_err("serial_debugger: "
"could not enable wakeup\n");
state->wakeup_irq_no_set_wake = true;
}
}
}
if (state->no_sleep)
fiq_debugger_handle_wakeup(state);
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
state_tf = state;
#endif
if (pdata->uart_init) {
//执行uart_init函数,这里我们的是debug_port_init接口
ret = pdata->uart_init(pdev);
if (ret)
goto err_uart_init;
}
if (state->clk)
clk_disable(state->clk);
#ifdef CONFIG_ARCH_ROCKCHIP
console_out:
#endif
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
spin_lock_init(&state->console_lock);
state->console = fiq_debugger_console;
state->console.index = pdev->id;
if (!console_set_on_cmdline)
add_preferred_console(state->console.name,
state->console.index, NULL);
register_console(&state->console);
fiq_debugger_tty_init_one(state);
#endif
return 0;
err_register_irq:
if (pdata->uart_free)
pdata->uart_free(pdev);
err_uart_init:
if (state->clk)
clk_disable(state->clk);
if (state->clk)
clk_put(state->clk);
wake_lock_destroy(&state->debugger_wake_lock);
platform_set_drvdata(pdev, NULL);
kfree(state);
return ret;
}
6.fiq debugger的串口中断处理
1)注册的中断处理程序
/*
* When not using FIQs, we only use this single interrupt as an entry point.
* This just effectively takes over the UART interrupt and does all the work
* in this context.
*/
static irqreturn_t fiq_debugger_uart_irq(int irq, void *dev)
{
struct fiq_debugger_state *state = dev;
bool not_done;
fiq_debugger_handle_wakeup(state);
/* handle the debugger irq in regular context */
not_done = fiq_debugger_handle_uart_interrupt(state, smp_processor_id(),
get_irq_regs(),
current_thread_info());
if (not_done)
fiq_debugger_handle_irq_context(state);
return IRQ_HANDLED;
}
/*
* If FIQs are used, not everything can happen in fiq context.
* FIQ handler does what it can and then signals this interrupt to finish the
* job in irq context.
*/
static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev)
{
struct fiq_debugger_state *state = dev;
if (state->pdata->force_irq_ack)
state->pdata->force_irq_ack(state->pdev, state->signal_irq);
fiq_debugger_handle_irq_context(state);
return IRQ_HANDLED;
}
2)处理接口主要逻辑
fiq_debugger_handle_irq_context
->fiq_debugger_handle_console_irq_context
->tty_insert_flip_char插入终端命令行中断
->tty_flip_buffer_push提交工作队列
static
void fiq_debugger_handle_console_irq_context(struct fiq_debugger_state *state)
{
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
if (state->tty_port.ops) {
int i;
int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
for (i = 0; i < count; i++) {
int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
tty_insert_flip_char(&state->tty_port, c, TTY_NORMAL);
if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1))
pr_warn("fiq tty failed to consume byte\n");
}
tty_flip_buffer_push(&state->tty_port);
}
#endif
}
static void fiq_debugger_handle_irq_context(struct fiq_debugger_state *state)
{
if (!state->no_sleep) {
unsigned long flags;
spin_lock_irqsave(&state->sleep_timer_lock, flags);
wake_lock(&state->debugger_wake_lock);
mod_timer(&state->sleep_timer, jiffies + HZ * 5);
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
fiq_debugger_handle_console_irq_context(state);
if (state->debug_busy) {
fiq_debugger_irq_exec(state, state->debug_cmd);
if (!state->console_enable)
fiq_debugger_prompt(state);
state->debug_busy = 0;
}
}