Chinaunix首页 | 论坛 | 博客
  • 博客访问: 394947
  • 博文数量: 138
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1620
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-10 16:55
个人简介

当你比别人优秀一点点,别人会嫉妒你。当你比别人优秀很多,别人会羡慕你。

文章分类

全部博文(138)

文章存档

2016年(2)

2015年(2)

2014年(15)

2013年(119)

我的朋友

分类: LINUX

2013-07-22 20:28:35

接下来,我们看看s3c2410处理器芯片的irq初始化函数

/* arch/arm/plat-s3c24xx/irq.c */
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
*/
/* s3c24xx系列芯片中断初始化函数 */
void __init s3c24xx_init_irq(void)
{
    unsigned long pend;
    unsigned long last;
    int irqno;
    int i;
    irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
    /* first, clear all interrupts pending... */
    /* 清空各个中断请求信号 */
    last = 0;
    for (i = 0; i < 4; i++) {
        pend = __raw_readl(S3C24XX_EINTPEND);
        if (pend == 0 || pend == last)
            break;
        __raw_writel(pend, S3C24XX_EINTPEND);
        printk("irq: clearing pending ext status %08x\n", (int)pend);
        last = pend;
    }
    last = 0;
    for (i = 0; i < 4; i++) {
        pend = __raw_readl(S3C2410_INTPND);
        if (pend == 0 || pend == last)
            break;
        __raw_writel(pend, S3C2410_SRCPND);
        __raw_writel(pend, S3C2410_INTPND);
        printk("irq: clearing pending status %08x\n", (int)pend);
        last = pend;
    }
    last = 0;
    for (i = 0; i < 4; i++) {
        pend = __raw_readl(S3C2410_SUBSRCPND);
        if (pend == 0 || pend == last)
            break;
        printk("irq: clearing subpending status %08x\n", (int)pend);
        __raw_writel(pend, S3C2410_SUBSRCPND);
        last = pend;
    }
    /* register the main interrupts */
    /* 注册主要中断 */
    irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
    for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
        /* set all the s3c2410 internal irqs */
        switch (irqno) {
            /* deal with the special IRQs (cascaded) */
        case IRQ_EINT4t7:
        case IRQ_EINT8t23:
        case IRQ_UART0:
        case IRQ_UART1:
        case IRQ_UART2:
        case IRQ_ADCPARENT:
            set_irq_chip(irqno, &s3c_irq_level_chip);    /* 设置中断操作函数集(电平) */
            set_irq_handler(irqno, handle_level_irq);    /* 设置中断的高层流处理函数(电平) */
            break;
        case IRQ_RESERVED6:
        case IRQ_RESERVED24:
            /* no IRQ here */
            break;
        default:
            //irqdbf("registering irq %d (s3c irq)\n", irqno);
            set_irq_chip(irqno, &s3c_irq_chip);            /* 默认中断为边缘触发 */
            set_irq_handler(irqno, handle_edge_irq);
            set_irq_flags(irqno, IRQF_VALID);
        }
    }
    /* setup the cascade irq handlers */
    /* 设置中断的高层流处理函数 */
    set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
    set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
    set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
    set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
    set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
    set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
    /* external interrupts */
    for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
        irqdbf("registering irq %d (ext int)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_eint0t4);
        set_irq_handler(irqno, handle_edge_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
        irqdbf("registering irq %d (extended s3c irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irqext_chip);
        set_irq_handler(irqno, handle_edge_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    /* register the uart interrupts */
    irqdbf("s3c2410: registering external interrupts\n");
    for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
        irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_uart0);
        set_irq_handler(irqno, handle_level_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
        irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_uart1);
        set_irq_handler(irqno, handle_level_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
        irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_uart2);
        set_irq_handler(irqno, handle_level_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
        irqdbf("registering irq %d (s3c adc irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_adc);
        set_irq_handler(irqno, handle_edge_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    irqdbf("s3c2410: registered interrupt handlers\n");
}
接着,我们来看一下中断处理过程 /* arch/arm/kernel/irq.c */
/*
* do_IRQ handles all hardware IRQ's. Decoded IRQs should not
* come via this function. Instead, they should provide their
* own 'handler'
*/
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);    /* 保存寄存器中的内容 */
    struct irq_desc *desc = irq_desc + irq;           /* 获取中断源 */
    /*
     * Some hardware gives randomly wrong interrupts. Rather
     * than crashing, do something sensible.
     */
    if (irq >= NR_IRQS)
        desc = &bad_irq_desc;
    irq_enter();
    desc_handle_irq(irq, desc);            /* 调用已安装的中断高层流处理函数 */
    /* AT91 specific workaround */
    irq_finish(irq);
    irq_exit();
    set_irq_regs(old_regs);
}
接下来,我们以IRQ_UART2(s3c2410串口2中断)为例,看看中断是如何分流到我们通过request_irq注册的中断处理函数
在s3c24xx_init_irq里IRQ_S3CUART_TX2中断的中断高层流处理函数被设置为s3c_irq_demux_uart2。
s3c_irq_demux_uart2主要工作是调用s3c_irq_demux_uart对串口中断进行分流处理,因为串口中断包含Rx(接收)中断、Tx(发送)中断和Rx error(接收错误)中断


/* arch/arm/plat-s3c2410/irq.c */
static void s3c_irq_demux_uart2(unsigned int irq, struct irq_desc *desc)
{
    irq = irq;
    s3c_irq_demux_uart(IRQ_S3CUART_RX2);
}
s3c_irq_demux_uart通过副中断源引脚寄存器的值,判断中断源并执行相应的中断处理函数
/* arch/arm/plat-s3c2410/irq.c */
/* start: 标示发出该中断信号的是哪个uart,即其值应为
*            IRQ_S3CUART_RX0、IRQ_S3CUART_RX1或IRQ_S3CUART_RX2
*/
static void s3c_irq_demux_uart(unsigned int start)
{
    unsigned int subsrc, submsk;
    unsigned int offset = start - IRQ_S3CUART_RX0;    /* 获取该UART中断源在副中断屏蔽寄存器中的偏移量 */
    struct irq_desc *desc;
    /* read the current pending interrupts, and the mask
     * for what it is available */
    subsrc = __raw_readl(S3C2410_SUBSRCPND);        /* 读取副中断源引脚寄存器 */
    submsk = __raw_readl(S3C2410_INTSUBMSK);        /* 读取副中断屏蔽寄存器 */
    irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
        start, offset, subsrc, submsk);
    subsrc &= ~submsk;        /* 只留下已使能(未屏蔽)的中断源 */
    subsrc >>= offset;        /* 截取发送中断的uart源到subsrc低3位 */
    subsrc &= 7;
    if (subsrc != 0)
    {
        desc = irq_desc + start;
        if (subsrc & 1)        /* Rx中断 */
            desc_handle_irq(start, desc);
        desc++;
        if (subsrc & 2)        /* Tx中断 */
            desc_handle_irq(start+1, desc);
        desc++;
        if (subsrc & 4)        /* Rx error中断 */
            desc_handle_irq(start+2, desc);
    }
}
desc_handle_irq实际上只是调用了desc->handle_irq来执行已安装的中断高层流处理函数。假设这里串口2发起的中断为Tx中断,即IRQ_S3CUART_TX2。IRQ_S3CUART_TX2的中断高层流处理函数已在s3c24xx_init_irq里通过set_irq_handler设置为handle_level_irq。
/* include/asm-arm/mach/irq.h */
/*
* Obsolete inline function for calling irq descriptor handlers.
*/
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
    desc->handle_irq(irq, desc);
}
handle_level_irq主要工作是获取该中断的action链表(所有安装在该中断号上的中断处理函数其实就是一个action结构体,详见request_irq的实现),然后传递给handle_IRQ_event。
/* kernel/irq/chip.c */
/*
*    handle_level_irq - Level type irq handler
*    @irq:    the interrupt number
*    @desc:    the interrupt description structure for this irq
*
*    Level type interrupts are active as long as the hardware line has
*    the active level. This may require to mask the interrupt and unmask
*    it after the associated handler has acknowledged the device, so the
*    interrupt line is back to inactive.
*/
void fastcall handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
    unsigned int cpu = smp_processor_id();
    struct irqaction *action;
    irqreturn_t action_ret;
    spin_lock(&desc->lock);
    mask_ack_irq(desc, irq);
    if (unlikely(desc->status & IRQ_INPROGRESS))
        goto out_unlock;
    desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
    kstat_cpu(cpu).irqs[irq]++;
    /*
     * If its disabled or no action available
     * keep it masked and get out of here
     */
    /* 获取该中断的action链表 */
    action = desc->action;
    if (unlikely(!action || (desc->status & IRQ_DISABLED)))
        goto out_unlock;
    desc->status |= IRQ_INPROGRESS;
    spin_unlock(&desc->lock);
    /* 调用handle_IRQ_event,执行已安装在该中断号上的所有中断函数 */
    action_ret = handle_IRQ_event(irq, action);
    if (!noirqdebug)
        note_interrupt(irq, desc, action_ret);
    spin_lock(&desc->lock);
    desc->status &= ~IRQ_INPROGRESS;
    if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
        desc->chip->unmask(irq);
out_unlock:
    spin_unlock(&desc->lock);
}
handle_IRQ_event主要作用就是执行那些已安装的中断处理函数action->handler /* kernel/irq/handle.c */
/*
* handle_IRQ_event - irq action chain handler
* @irq:    the interrupt number
* @action:    the interrupt action chain for this irq
*
* Handles the action chain of an irq event
*/
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
    irqreturn_t ret, retval = IRQ_NONE;
    unsigned int status = 0;
    handle_dynamic_tick(action);
    if (!(action->flags & IRQF_DISABLED))
        local_irq_enable_in_hardirq();
    /* 循环调用安装在该中断号irq上的中断处理函数 */
    do
    {
        /* action->handler就是我们调用request_irq时,
         * 安装的中断处理函数 */
        ret = action->handler(irq, action->dev_id);    
        if (ret == IRQ_HANDLED)
            status |= action->flags;
        retval |= ret;
        action = action->next;
    } while (action);
    if (status & IRQF_SAMPLE_RANDOM)
        add_interrupt_randomness(irq);
    local_irq_disable();
    return retval;
}

阅读(976) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~