fiq-debugger

一、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;
	}
}

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会写代码的小可爱&&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值