透明大页相关内核参数_第三十六期-ARM Linux内核的中断(6)

ebd506f51bc3af6d88e774ae0bba17ba.png

作者:罗宇哲,中国科学院软件研究所智能软件研究中心

上一期中我们介绍了ARM Linux内核中SGI的处理流程,这一期我们将介绍ARM Linux内核的与中断相关的常用函数。

一、ARM Linux内核中与中断相关的常用函数

在ARM Linux内核源码中,常见的与中断有关的函数包括中断处理程序注册函数、中断释放函数、开中断函数和关中断函数。

中断处理程序注册函数用于注册设备所用的中断处理函数,主要有request_irq()和request_threaded_irq()。request_irq()是通过调用request_threaded_irq()实现的,其源代码可以在openEuler源码仓库中的openeuler/kernel/blob/kernel-4.19/include/linux/interrupt.h文件中找到:

73bc10b683493f6d4afecaebd9676478.png

它将request_threaded_irq()的thread_fn参数设为NULL,表示不使用中断线程化。中断线程化是使用内核线程来处理中断,可以减少系统关中断的时间,增加系统的实时性[1]。函数request_threaded_irq()用于注册线程化的中断,其代码可以在openEuler源码仓库的openeuler/kernel/blob/kernel-4.19/kernel/irq/manage.c文件中找到:

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
			 irq_handler_t thread_fn, unsigned long irqflags,
			 const char *devname, void *dev_id)
{
	struct irqaction *action;
	struct irq_desc *desc;
	int retval;

	if (irq == IRQ_NOTCONNECTED)
		return -ENOTCONN;

	/*
	 * Sanity-check: shared interrupts must pass in a real dev-ID,
	 * otherwise we'll have trouble later trying to figure out
	 * which interrupt is which (messes up the interrupt freeing
	 * logic etc).
	 *
	 * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and
	 * it cannot be set along with IRQF_NO_SUSPEND.
	 */
	if (((irqflags & IRQF_SHARED) && !dev_id) ||
	    (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
	    ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
		return -EINVAL;

	desc = irq_to_desc(irq);
	if (!desc)
		return -EINVAL;

	if (!irq_settings_can_request(desc) ||
	    WARN_ON(irq_settings_is_per_cpu_devid(desc)))
		return -EINVAL;

	if (!handler) {
		if (!thread_fn)
			return -EINVAL;
		handler = irq_default_primary_handler;
	}

	action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
	if (!action)
		return -ENOMEM;

	action->handler = handler;
	action->thread_fn = thread_fn;
	action->flags = irqflags;
	action->name = devname;
	action->dev_id = dev_id;

	retval = irq_chip_pm_get(&desc->irq_data);
	if (retval < 0) {
		kfree(action);
		return retval;
	}

	retval = __setup_irq(irq, desc, action);

	if (retval) {
		irq_chip_pm_put(&desc->irq_data);
		kfree(action->secondary);
		kfree(action);
	}

#ifdef CONFIG_DEBUG_SHIRQ_FIXME
	if (!retval && (irqflags & IRQF_SHARED)) {
		/*
		 * It's a shared IRQ -- the driver ought to be prepared for it
		 * to happen immediately, so let's make sure....
		 * We disable the irq to make sure that a 'real' IRQ doesn't
		 * run in parallel with our fake.
		 */
		unsigned long flags;

		disable_irq(irq);
		local_irq_save(flags);

		handler(irq, dev_id);

		local_irq_restore(flags);
		enable_irq(irq);
	}
#endif
	return retval;
}

该函数参数列表中各参数的意义为:

  • irq:Linux中断号;
  • handler:当IRQ发生时被调用的函数;
  • thread_fn:IRQ处理线程调用的函数,如果是NULL就不创建线程;
  • irqflags:中断类型标志符;
  • devname:设备的ascii名称;
  • dev_id:传递给handler函数的cookie。

该函数分配中断资源并使能中断处理。当handler参数为NULL时,若thread_fn参数不为NULL,则将handler参数设置为irq_default_primary_handler。该函数设置了irqaction结构体的参数,通过调用__setup_irq()->setup_irq_thread()函数设置处理中断的线程的优先级和调度策略,然后在关中断的情况下调用中断处理函数handler()。如果irqaction结构体重被注册的中断处理函数执行后返回的是IRQ_WAKE_THREAD那么将唤醒中断处理线程并运行thread_fn。

在上面的函数中包含了关中断的函数(local_irq_disable()和local_irq_save())和开中断的函数(local_irq_enable()和local_irq_restore())。local_irq_save(flags)函数先把中断状态保存在其参数flags中然后禁止中断,local_irq_restore()则恢复本处理器的中断状态[1]。local_irq_disable()最终调用arch_local_irq_disable()函数,arch_local_irq_disable()函数通过汇编指令设置DAIF标志位来屏蔽中断;而local_irq_enable()函数最终调用arch_local_irq_enable()函数,arch_local_irq_enable()函数通过汇编指令清除DAIF标志位来使能中断。arch_local_irq_disable()函数和arch_local_irq_enable()函数在openEuler源码仓库的openeuler/kernel/blob/kernel-4.19/arch/arm64/include/asm/irqflags.h文件中可以找到:

d802250eff20b53c8fab101fb80d90d3.png

32f69a50897f9573521c7bafab930fa7.png

最后我们介绍一下中断释放函数free_irq(),该函数用于移除被注册的中断处理函数。如果Linux中断号对应的中断不再被任何设备使用那么该中断被disable。该函数有两个参数:

  • irq: 待释放的中断的Linux中断号;
  • dev_id:待释放的设备标识。

该函数的代码可以在openEuler源码仓库的openeuler/kernel/blob/kernel-4.19/kernel/irq/manage.c文件中找到:

b95a473ad26c27f5aab710fc48556b6f.png

二、结语

本期我们介绍了与中断相关的几个常用函数,下一期我们将介绍ARM Linux内核中的底半机制。

参考文献

[1] 《Linux内核深度解析》,余华兵著,2019

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值