【转】linux中断流程详解

中断早期初始化

  1. irq_desc[]
struct irq_desc {
	struct irq_data		irq_data;
	struct timer_rand_state *timer_rand_state;
	unsigned int __percpu	*kstat_irqs;
	irq_flow_handler_t	handle_irq;
#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
	irq_preflow_handler_t	preflow_handler;
#endif
	struct irqaction	*action;	/* IRQ action list */
	unsigned int		status_use_accessors;
	unsigned int		core_internal_state__do_not_mess_with_it;
	unsigned int		depth;		/* nested irq disables */
	unsigned int		wake_depth;	/* nested wake enables */
	unsigned int		irq_count;	/* For detecting broken IRQs */
	unsigned long		last_unhandled;	/* Aging timer for unhandled count */
	unsigned int		irqs_unhandled;
	raw_spinlock_t		lock;
#ifdef CONFIG_SMP
	const struct cpumask	*affinity_hint;
	struct irq_affinity_notify *affinity_notify;
#ifdef CONFIG_GENERIC_PENDING_IRQ
	cpumask_var_t		pending_mask;
#endif
#endif
	unsigned long		threads_oneshot;
	atomic_t		threads_active;
	wait_queue_head_t       wait_for_threads;
#ifdef CONFIG_PROC_FS
	struct proc_dir_entry	*dir;
#endif
	const char		*name;
}
extern struct irq_desc irq_desc[NR_IRQS];
#define NR_IRQS			(GODNET_IRQ_START + 96)
#define GODNET_IRQ_START	(32)

GIC控制器,有PPI、SGI、SPI
SPI 共享外设中断号大于32.

在内核早期初始化的时候,machine_desc会初始化gic_irq。
并且在别的函数(irq_set_handler)里设置irq_desc[]–>handle_irq。这个handle_irq后面会用得到。

==========================
下面是中断执行流程:

中断异常向量表:
1 在 arch/arm/kernel/entry-armv.S 中定义了宏 irq_handler
irq_handler里面会执行arch_irq_handler_default–》asm_do_IRQ

  6         .macro  arch_irq_handler_default
  7         get_irqnr_preamble r5, lr
  8 1:      get_irqnr_and_base r0, r6, r5, lr
  9         movne   r1, sp
 10         @
 11         @ routine called with r0 = irq number, r1 = struct pt_regs *
 12         @
 13         adrne   lr, BSYM(1b)
 14         bne     asm_do_IRQ

无论是gic 控制器,还是别的中断控制器,都会执行到asm_do_IRQ
下面分析asm_do_IRQ 不

  1. `asmlinkage void __exception_irq_entry
    asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
    {
    struct pt_regs *old_regs = set_irq_regs(regs);//18个寄存器,保存参数

    irq_enter();

    /*

    • Some hardware gives randomly wrong interrupts. Rather
    • than crashing, do something sensible.
      */
      if (unlikely(irq >= nr_irqs)) {
      if (printk_ratelimit())
      printk(KERN_WARNING “Bad IRQ%u\n”, irq);
      ack_bad_irq(irq);
      } else {
      generic_handle_irq(irq);
      }

    /* AT91 specific workaround */
    irq_finish(irq);

    irq_exit();
    set_irq_regs(old_regs);
    }`

int generic_handle_irq(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);

	if (!desc)
		return -EINVAL;
	generic_handle_irq_desc(irq, desc);
	return 0;
}
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
	desc->handle_irq(irq, desc);
}

这里的desc_handle_rq就是内核早期初始化的时候设置的函数。
如有的平台是handle_level_irq
这函数会调用 handle_irq_event(desc);

irqreturn_t handle_irq_event(struct irq_desc *desc)
{
	struct irqaction *action = desc->action;
	irqreturn_t ret;

	desc->istate &= ~IRQS_PENDING;
	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
	raw_spin_unlock(&desc->lock);

	ret = handle_irq_event_percpu(desc, action);

	raw_spin_lock(&desc->lock);
	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
	return ret;
}
irqreturn_t
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
	irqreturn_t retval = IRQ_NONE;
	unsigned int random = 0, irq = desc->irq_data.irq;

	do {
		irqreturn_t res;

		trace_irq_handler_entry(irq, action);
		res = action->handler(irq, action->dev_id);
		trace_irq_handler_exit(irq, action, res);

		if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
			      irq, action->handler))
			local_irq_disable();

		switch (res) {
		case IRQ_WAKE_THREAD:
			/*
			 * Catch drivers which return WAKE_THREAD but
			 * did not set up a thread function
			 */
			if (unlikely(!action->thread_fn)) {
				warn_no_thread(irq, action);
				break;
			}

			irq_wake_thread(desc, action);

			/* Fall through to add to randomness */
		case IRQ_HANDLED:
			random |= action->flags;
			break;

		default:
			break;
		}

		retval |= res;
		action = action->next;
	} while (action);

	if (random & IRQF_SAMPLE_RANDOM)
		add_interrupt_randomness(irq);

	if (!noirqdebug)
		note_interrupt(irq, desc, retval);
	return retval;
}

由此找到了action->handler.
里面还会根据handler的返回值,如果是IRQ_WAKE_THREAD则唤醒中断线程。
那么这个handler是什么?
request_irq->request_threaded_irq-

	if (!action)
		return -ENOMEM;

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

	chip_bus_lock(desc);
	retval = __setup_irq(irq, desc, action);
	chip_bus_sync_unlock(desc);


在__setup_irq里添加action到desc[]的action链表中。
然后遍历这个表,最终执行的就是中断申请的时候使用的handler。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值