【转】linux中断流程详解

来源:互联网 发布:淘宝店铺装修首页全屏 编辑:程序博客网 时间:2024/05/17 01:05

参考 :http://blog.csdn.net/yimu13/article/details/6803957

中断早期初始化
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.

2.
在内核早期初始化的时候,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_thandle_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。

原创粉丝点击