linux 的中断处理

之前在ARM平台上分析过中断处理的详细步骤, 写了个PPT, 但是后来找不到了. 正好前一阵子看mips下的中断的时候, 随手写了点东西, 还是记录到blog上来吧, 方便查找.

这里面的每一个文字都是我自己码出来的, 转载的兄弟请注明出处.


1. 重要的结构体介绍

struct irq_desc {
    unsigned int        irq;
    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 long        last_unhandled;    /* Aging timer for unhandled count */
    unsigned int        irqs_unhandled;
    spinlock_t        lock;
#ifdef CONFIG_SMP
    cpumask_t        affinity;
    unsigned int        cpu;
#endif
#ifdef CONFIG_GENERIC_PENDING_IRQ
    cpumask_t        pending_mask;
#endif
#ifdef CONFIG_PROC_FS
    struct proc_dir_entry    *dir;
#endif
    const char        *name;
} ____cacheline_internodealigned_in_smp;
包含重要的 irq_chip 的成员 chip, 和irqaction的成员 action, 以及irq_flow_handler_t类型的函数指针handle_irq;

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,
                    const struct cpumask *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;
};

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;
};
这个handler就是通过request_irq去注册的handler.


2. 重要的变量和函数等

全局数组struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp;

3. mips/concerto的中断的初始化


kernel的流程: (缩进对齐表示是被上一级函数调用的函数, 个人习惯用法)


start_kernel
  early_irq_init //初始化上面的全局的irq_desc
  init_IRQ
    arch_init_irq

mips本身的中断:
0-8是mips本身的, 8-NR_IRQS是PIC的.

如果mips支持超线程, 则0-1的初始化是
if (cpu_has_mipsmt)
        for (i = irq_base; i < irq_base + 2; i++)
            set_irq_chip(i, &mips_mt_cpu_irq_controller);
2-7的初始化是
for (i = irq_base + 2; i < irq_base + 8; i++)
        set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
                     handle_percpu_irq);
mips_cpu_irq_controller就是irq_chip类型的struct.
handle_percpu_irq 是以及 irq_flow_handler_t 类型的函数.

8-NR_IRQS的初始化是
for (irq = CONCERTO_PIC_IRQ_BASE; irq < NR_IRQS; irq++) {
        concerto_hard_disable_pic_irq(irq - CONCERTO_PIC_IRQ_BASE);
        set_irq_chip_and_handler(irq, &concerto_pic_irq_type, handle_simple_irq);
    }

常见的 irq_flow_handler_t 类型的handler有:
handle_simple_irq
handle_level_irq
handle_fasteoi_irq
handle_edge_irq
handle_percpu_irq

不管是哪种 irq_desc 中注册的 irq_flow_handler_t, 都是调用的 handle_IRQ_event, 在 handle_IRQ_event 中再调用 request_irq 中注册的各自的handler.

4. 中断的大致流程


do_IRQ
  irq_enter
  generic_handle_irq(irq)
    generic_handle_irq_desc
      desc->handle_irq(irq, desc); //比如前面的 handle_simple_irq
        handle_IRQ_event(irq, action);
          action->handler(irq, action->dev_id); //就是request_irq的注册的handler
  irq_exit
    invoke_softirq //当前没在处理hard irq和soft irq, 同时有pending的soft irq
      __do_softirq //最多restart 10次, MAX_SOFTIRQ_RESTART, 还有的话就去唤醒softirq线程 wakeup_softirqd
        h->action(h); //比如 blk_done_softirq
        ksoftirqd //如果需要

5. softirq
系统中有
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,
    TASKLET_SOFTIRQ,
    SCHED_SOFTIRQ,
    HRTIMER_SOFTIRQ,
    RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

open_softirq去注册h->action(h), 而 raise_softirq 去开始使能并执行对应的softirq.

更具体的介绍在后面的文章中, 这个是大致的处理框架.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值