yangxiang 2017-10-10
1.中断处理体系结构
Linux内核将所有中断统一编号,使用一个irq_desc结构数组来描述这些中断。
数组声明在/linux/kernel/irq/handle.c中,其中#define NR_IRQS 128,定义在/linux/include/asm/irq.h中
/*
 * Linux has a controller-independent interrupt architecture.
 * Every controller has a 'controller-template', that is used
 * by the main code to do the right thing. Each driver-visible
 * interrupt source is transparently wired to the appropriate
 * controller. Thus drivers need not be aware of the
 * interrupt-controller.
 *
 * The code is designed to be easily extended with new/different
 * interrupt controllers, without having to do assembly magic or
 * having to touch the generic code.
 *
 * Controller mappings for all interrupt sources:
 */
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
    [0 ... NR_IRQS-1] = {
        .status = IRQ_DISABLED,
        .chip = &no_irq_chip,
        .handle_irq = handle_bad_irq,
        .depth = 1,
        .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
#ifdef CONFIG_SMP
        .affinity = CPU_MASK_ALL
#endif
    }
};
irq_desc结构的数据类型在/linuxinclude/linux/irq.h中定义,
struct irq_desc {
    irq_flow_handler_t    handle_irq;
    struct irq_chip        *chip;
    struct msi_desc        *msi_desc;
    void            *handler_data;
    void            *chip_data;
    struct irqaction    *action;    /* IRQ action list */
    unsigned int        status;        /* IRQ status */
    unsigned int        depth;        /* nested irq disables */
    unsigned int        wake_depth;    /* nested wake enables */
    unsigned int        irq_count;    /* For detecting broken IRQs */
    unsigned int        irqs_unhandled;
    spinlock_t        lock;
#ifdef CONFIG_SMP
    cpumask_t        affinity;
    unsigned int        cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
    cpumask_t        pending_mask;
#endif
#ifdef CONFIG_PROC_FS
    struct proc_dir_entry    *dir;
#endif
    const char        *name;
} ____cacheline_internodealigned_in_smp;
handle_irq是这个或这组中断的处理函数入口。发生中断时,总入口函数asm_do_IRQ将根据中断号调用相应irq_desc数组项中handle_irq.
typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, struct irq_desc *desc);
handle_irq使用chip结构中的函数清除、屏蔽或者重新使能中断,还要调用用户在action链表中注册的中断处理函数。irq_chip结构类型也是在include/linux/irq.h中定义,其中的成员大多用于操作底层硬件,比如设置寄存器以屏蔽中断,使能中断,清除中断等。注意这里的成员name会出现在/proc/interrupts中。
struct irq_chip {
    const char    *name;
    unsigned int    (*startup)(unsigned int irq);
    void        (*shutdown)(unsigned int irq);
    void        (*enable)(unsigned int irq);
    void        (*disable)(unsigned int irq);
    void        (*ack)(unsigned int irq);
    void        (*mask)(unsigned int irq);
    void        (*mask_ack)(unsigned int irq);
    void        (*unmask)(unsigned int irq);
    void        (*eoi)(unsigned int irq);
    void        (*end)(unsigned int irq);
    void        (*set_affinity)(unsigned int irq, cpumask_t dest);
    int        (*retrigger)(unsigned int irq);
    int        (*set_type)(unsigned int irq, unsigned int flow_type);
    int        (*set_wake)(unsigned int irq, unsigned int on);
    /* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
    void        (*release)(unsigned int irq, void *dev_id);
#endif
    /*
    * For compatibility, ->typename is copied into ->name.
    * Will disappear.
    */
    const char    *typename;
};
irq_desc结构中的irqaction结构类型在include/linux/iterrupt.h中定义。用户注册的每个中断处理函数用一个irqaction结构来表示,一个中断比如共享中断可以有多个处理函数,它们的irqaction结构链接成一个链表,以action为表头。irqation结构在linux/include/linux/interrupt.h中定义如下:
typedef irqreturn_t (*irq_handler_t)(int, void *);
struct irqaction {
    irq_handler_t handler;
    unsigned long flags;
    cpumask_t mask;
    const char *name;
    void *dev_id;
    struct irqaction *next;
    int irq;
    struct proc_dir_entry *dir;
};
irq_desc结构数组、它的成员“struct irq_chip *chip” "struct irqaction *action",这3种数据结构构成了中断处理体系的框架。下图中描述了Linxu中断处理体系结构的关系图:
