Linux IRQ Sub System V

驱动申请中断API

request_irq

框架流程图如下所示:
在这里插入图片描述
具体流程如下所示;

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
	return request_threaded_irq(irq, handler, NULL, flags, name, dev);
/*
/**
 *	request_threaded_irq - allocate an interrupt line
 *	@irq: Interrupt line to allocate
 *	@handler: Function to be called when the IRQ occurs.
 *		  Primary handler for threaded interrupts
 *		  If NULL and thread_fn != NULL the default
 *		  primary handler is installed
 *	@thread_fn: Function called from the irq handler thread
 *		    If NULL, no irq thread is created
 *	@irqflags: Interrupt type flags
 *	@devname: An ascii name for the claiming device
 *	@dev_id: A cookie passed back to the handler function
*/

struct irq_desc *desc;
desc = irq_to_desc(irq);	

a.通过 virq 获取对应中断描述符 ,以 virq 为索引,通过 radix tree 中搜索获取对应irq_desc;

struct irqaction *action;
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
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);/* 通过 chip 对irq chip的上电操作???*/
retval = __setup_irq(irq, desc, action);/* 注册 */

b.分配 struct irqaction,赋值,调用 __setup_irq 进行实际的注册过程,把该 action填充到 desc中;

c.接下来解剖注册函数的实现方式:__setup_irq

init_waitqueue_head(&desc->wait_for_threads);
1).初始化一个等待队列,这个等待队列包含在中断描述符中

ret = __irq_set_trigger(desc,new->flags & IRQF_TRIGGER_MASK);
2).根据传递进来的参数设置中断触发,类型,比如在 FP中,触发类型为上升沿触发;

irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
3).清除中断

irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
	irq_enable(desc);/*使能中断*/
4).使能中断

register_irq_proc(irq, desc);
irq_add_debugfs_entry(irq, desc);
new->dir = NULL;
register_handler_proc(irq, new);

d.创建 proc系统下相关节点,方便调试;

free_irq

代码流程如下所示,

const void *free_irq(unsigned int irq, void *dev_id)
	struct irq_desc *desc = irq_to_desc(irq);/* radix tree 方式获取 irq_desc */
		return radix_tree_lookup(&irq_desc_tree, irq);
	
	struct irqaction *action;
	action = __free_irq(irq, dev_id);/* 通过 virq 和 具体的设备dev_id 获取对应的action */
	kfree(action);/* 卸载 */

接下来主要分析一下 __free_irq ;

static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
	struct irq_desc *desc = irq_to_desc(irq);/* radix tree 方式获取 irq_desc */
		return radix_tree_lookup(&irq_desc_tree, irq);

	struct irqaction *action, **action_ptr;
	action_ptr = &desc->action;/* 从 irq_desc 中获取一个 action 链表 */
	
	for (;;) {
		action = *action_ptr;

		if (!action) {
			WARN(1, "Trying to free already-free IRQ %d\n", irq);
			raw_spin_unlock_irqrestore(&desc->lock, flags);
			chip_bus_sync_unlock(desc);
			mutex_unlock(&desc->request_mutex);
			return NULL;
		}

		if (action->dev_id == dev_id)
			break;
		action_ptr = &action->next;
	}	
	/* 在 action 中 通过传递进来的参数 dev_id 循环查找对应 dev_id 所对应的 action */
	
	/* Found it - now remove it from the list of entries: */
	*action_ptr = action->next;/* 使用二级指针的一个技术删除 链表中的 action */

	irq_pm_remove_action(desc, action);
	
	/* If this was the last handler, shut down the IRQ line: */
	if (!desc->action) {
		irq_settings_clr_disable_unlazy(desc);
		irq_shutdown(desc); /* 通过类似状态机的方式切换状态,并关闭中断*/
			if (irqd_is_started(&desc->irq_data)) {/* 通过状态的判断是否开启中断*/
				__irq_disable(desc, true);
					irq_state_set_disabled(desc);/* 切换中断状态,禁止中断*/
						irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
				mask_irq(desc);
					irqd_irq_masked(&desc->irq_data)
						return __irqd_to_state(d) & IRQD_IRQ_MASKED;/* 关闭中断 */
			irq_state_clr_started(desc);
				irqd_clear(&desc->irq_data, IRQD_IRQ_STARTED);/* 关闭中断 */
					__irqd_to_state(d) &= ~mask;
		irq_domain_deactivate_irq(&desc->irq_data);/* 可以参考gic-v3的datasheet ,这是activate --> deactivate 的切换流程 */
			__irq_domain_deactivate_irq(irq_data);
				domain->ops->deactivate(domain, irq_data);
			irqd_clr_activated(irq_data);
				__irqd_to_state(d) &= ~IRQD_ACTIVATED;
	}	
	
	/* Last action releases resources */
	if (!desc->action) {
		/*
		 * Reaquire bus lock as irq_release_resources() might
		 * require it to deallocate resources over the slow bus.
		 */
		chip_bus_lock(desc);
		irq_release_resources(desc); /* 释放之前设置的一些相关资源0r数据的流程 */
			c->irq_release_resources(d);
		chip_bus_sync_unlock(desc);
		irq_remove_timings(desc);
	}
	
	irq_chip_pm_put(&desc->irq_data);/* 通过 runtime PM 的方式对 intc 模块电源的管理,然后再 gic-v3 中并没有使用 */
	
	return action;
}

enable_irq_wake/ disable_irq_wake

enable_irq_wake(fp_dev->irq);
	return irq_set_irq_wake(irq, 1);
		struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
		ret = set_irq_wake_real(irq, on);
			irq_desc_get_chip(desc)->flags &  IRQCHIP_SKIP_SET_WAKE
	irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);/* 即从休眠中唤醒中断 */
		__irqd_to_state(d) |= mask;

static inline int disable_irq_wake(unsigned int irq)
	return irq_set_irq_wake(irq, 0);
		struct irq_desc *desc = irq_get_desc_buslock(irq,&flags,IRQ_GET_DESC_CHECK_GLOBAL);
		ret = set_irq_wake_real(irq, on);
		irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);/* 即进入休眠状态 */
			__irqd_to_state(d) &= ~mask;

disable_irq_nosync/enable_irq

silfp_irq_disable(fp_dev);
	disable_irq_nosync(fp_dev->irq);
		__disable_irq_nosync(irq);
			struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
			__disable_irq(desc);
				desc->depth++
				irq_disable(desc);
					__irq_disable(desc, irq_settings_disable_unlazy(desc));
						mask_irq(desc);/* 屏蔽中断 */
							desc->irq_data.chip->irq_mask(&desc->irq_data);/* 调用 irq-gic-v3.c 里面的 irq_mask 函数,通过设置inc GICD_ICENABLER 寄存器屏蔽中断*/
								gic_mask_irq
									gic_poke_irq(d, GICD_ICENABLER);
silfp_irq_enable(fp_dev);
	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
	__enable_irq(desc);
		switch (desc->depth) {/* 这里为 1*/
			irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
				irq_enable(desc);
					unmask_irq(desc);
						desc->irq_data.chip->irq_unmask(&desc->irq_data);/* 调用 irq-gic-v3.c 里面的 irq_unmask函数,通过设置inc GICD_ISENABLER 寄存器使能中断*/
							gic_unmask_irq
								gic_poke_irq(d, GICD_ISENABLER);

综上,再结合我们 fp 的源码,可知 irq 的流程如下所示:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

人在路上……

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

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

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

打赏作者

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

抵扣说明:

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

余额充值