对于一个特定的irq_desc[irq],其上的中断处理分为两级,第一级是调用irq_desc[irq].handle_irq,第二级是设备特定的中断处理例程isr,在handle_irq的内部通过irq_desc[irq].action->handler调用。
    第一级函数在平台初始化期间被安装到irq_desc数组中,第二级函数的注册发生在设备驱动程序调用request_irq安装对应设备的中断处理例程时。第一级函数主要面向pic的某一中断线irq line,第二级函数则面向该中断线上连接的具体设备。
static int mxc_gpio_probe(struct platform_device *pdev)
{
     struct device_node *np = pdev->dev.of_node;
     struct mxc_gpio_port *port;
     struct resource *iores;
     int irq_base;
     int err;
     mxc_gpio_get_hw(pdev);
     port = devm_kzalloc(&pdev->dev, sizeof(*port), gfp_kernel);
     if (!port)
          return -enomem;
     iores = platform_get_resource(pdev, ioresource_mem, 0);
     port->base = devm_ioremap_resource(&pdev->dev, iores);
     if (is_err(port->base))
          return ptr_err(port->base);
     port->irq_high = platform_get_irq(pdev, 1);
     port->irq = platform_get_irq(pdev, 0);
     if (port->irq < 0)
          return port->irq;
     /* disable the interrupt and clear the status */
     writel(0, port->base   gpio_imr);
     writel(~0, port->base   gpio_isr);
     if (mxc_gpio_hwtype == imx21_gpio) 
    {
          /*
         * setup one handler for all gpio interrupts. actually setting
         * the handler is needed only once, but doing it for every port
         * is more robust and easier.
         */
         irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
     } 
    else 
    {
          /* setup one handler for each entry */
          irq_set_chained_handler(port->irq, mx3_gpio_irq_handler);
          irq_set_handler_data(port->irq, port);
          if (port->irq_high > 0) 
        {
               /* setup handler for gpio 16 to 31 */
              irq_set_chained_handler(port->irq_high, mx3_gpio_irq_handler);
               irq_set_handler_data(port->irq_high, port);
          }
    }
    /* gpio-mxc can be a generic irq chip */
     mxc_gpio_init_gc(port, irq_base);
}
    linux内核提供两个函数 irq_set_handler 和 irq_set_chained_handler 来设置第一级中断处理函数。
static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
{
     struct irq_chip_generic *gc;
     struct irq_chip_type *ct;
     gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, port->base, handle_level_irq);
     gc->private = port;
     ct = gc->chip_types;
     ct->chip.irq_ack = irq_gc_ack_set_bit;
     ct->chip.irq_mask = irq_gc_mask_clr_bit;
     ct->chip.irq_unmask = irq_gc_mask_set_bit;
     ct->chip.irq_set_type = gpio_set_irq_type;
     ct->chip.irq_set_wake = gpio_set_wake_irq;
     ct->regs.ack = gpio_isr;
     ct->regs.mask = gpio_imr;
     irq_setup_generic_chip(gc, irq_msk(32), irq_gc_init_nested_lock, irq_norequest,0);
}
    
内核中通过irq_chip结构体来描述中断控制器,描述了中断mask,ack等成员函数。多个控制器之间还可以级联,多中断控制器的情况下,我们使用内核提供的通用的irq_chip驱动架构irq_chip_generic,目前,主流的arm芯片内部的一级中断控制器都是用了arm公司的gic。
void handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
     raw_spin_lock(&desc->lock);
     mask_ack_irq(desc);
     if (!irq_may_run(desc))
          goto out_unlock;
     desc->istate &= ~(irqs_replay | irqs_waiting);
     kstat_incr_irqs_this_cpu(irq, desc);
     /*
     * if its disabled or no action available
     * keep it masked and get out of here
     */
     if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) 
    {
          desc->istate |= irqs_pending;
          goto out_unlock;
     }
     handle_irq_event(desc);
     cond_unmask_irq(desc);
out_unlock:
     raw_spin_unlock(&desc->lock);
}
    
handle_level_irq  是通用中断子系统提供的标准流控回调函数,用于电平触发中断的流控处理,其他函数还有handle_simple_irq  用于简易流控处理,handle_edge_irq  用于边沿触发中断的流控处理,handle_fasteoi_irq  用于需要响应eoi的中断控制器,handle_percpu_irq  用于只在单一cpu响应的中断,handle_nested_irq  用于处理使用线程的嵌套中断。
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;
}
	    函数handle_irq_event 为调用设备驱动程序安装的中断处理例程做最后的准备工作,
清除irqs_pending位,将当前设备的中断线设置irqd_irq_inprogress状态,表明
该中断线上一个中断正在被处理。
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
     irqreturn_t retval = irq_none;
     unsigned int flags = 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:
               flags |= action->flags;
               break;
               default:
                    break;
           }
          retval |= res;
          action = action->next;
     } while (action);
     add_interrupt_randomness(irq, flags);
     if (!noirqdebug)
          note_interrupt(irq, desc, retval);
     return retval;
}
    函数遍历action上的中断处理例程链表,通过action->handler来调用具体设备的中断处理例程,
即通过request_irq函数安装的中断处理函数。如果返回值是irq_wake_thread,那么函数将调用
irq_wake_thread来唤醒action->thread表示的一个内核线程。