中断API之setup_irq【转】

转自:https://blog.csdn.net/tiantao2012/article/details/78957472

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiantao2012/article/details/78957472

[html] view plain copy
int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction.  
  
其使用的例程如下:  
struct irq_domain * __init __init_i8259_irqs(struct device_node *node)  
{  
    struct irq_domain *domain;  
  
    insert_resource(&ioport_resource, &pic1_io_resource);  
    insert_resource(&ioport_resource, &pic2_io_resource);  
  
    init_8259A(0);  
  
    domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0,  
                       &i8259A_ops, NULL);  
    if (!domain)  
        panic("Failed to add i8259 IRQ domain");  
  
    setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);  
    return domain;  
}  
其源码分析如下:  
  
int setup_irq(unsigned int irq, struct irqaction *act)  
{  
    int retval;  
    struct irq_desc *desc = irq_to_desc(irq);  
    #中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出  
    if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))  
        return -EINVAL;  
  
    retval = irq_chip_pm_get(&desc->irq_data);  
    if (retval < 0)  
        return retval;  
    #核心代码,设置irq对应的irqaction *act  
    retval = __setup_irq(irq, desc, act);  
  
    if (retval)  
        irq_chip_pm_put(&desc->irq_data);  
  
    return retval;  
}  
static int  
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  
{  
    struct irqaction *old, **old_ptr;  
    unsigned long flags, thread_mask = 0;  
    int ret, nested, shared = 0;  
    #中断描述符为null,则退出  
    if (!desc)  
        return -EINVAL;  
    #没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.  
    if (desc->irq_data.chip == &no_irq_chip)  
        return -ENOSYS;  
    #增加这个模块的引用计数  
    if (!try_module_get(desc->owner))  
        return -ENODEV;  
    #更新struct irqaction *new 中的irq number  
    new->irq = irq;  
  
    /*  
     * If the trigger type is not specified by the caller,  
     * then use the default for this interrupt.  
     */  
     #没有设置中断触发类型的话,则用默认值.  
    if (!(new->flags & IRQF_TRIGGER_MASK))  
        new->flags |= irqd_get_trigger_type(&desc->irq_data);  
  
    /*  
     * Check whether the interrupt nests into another interrupt  
     * thread.  
     */  
    #检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套  
    nested = irq_settings_is_nested_thread(desc);  
    if (nested) {  
        if (!new->thread_fn) {  
            ret = -EINVAL;  
            goto out_mput;  
        }  
        /*  
         * Replace the primary handler which was provided from  
         * the driver for non nested interrupt handling by the  
         * dummy function which warns when called.  
         */  
        new->handler = irq_nested_primary_handler;  
    } else {  
    #这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化  
        if (irq_settings_can_thread(desc)) {  
            ret = irq_setup_forced_threading(new);  
            if (ret)  
                goto out_mput;  
        }  
    }  
  
    /*  
     * Create a handler thread when a thread function is supplied  
     * and the interrupt does not nest into another interrupt  
     * thread.  
     */  
    #在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程  
    if (new->thread_fn && !nested) {  
        ret = setup_irq_thread(new, irq, false);  
        if (ret)  
            goto out_mput;  
        #中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.  
        if (new->secondary) {  
            ret = setup_irq_thread(new->secondary, irq, true);  
            if (ret)  
                goto out_thread;  
        }  
    }  
  
    /*  
     * Drivers are often written to work w/o knowledge about the  
     * underlying irq chip implementation, so a request for a  
     * threaded irq without a primary hard irq context handler  
     * requires the ONESHOT flag to be set. Some irq chips like  
     * MSI based interrupts are per se one shot safe. Check the  
     * chip flags, so we can avoid the unmask dance at the end of  
     * the threaded handler for those.  
     */  
    #有设置oneshot 标志的话,则清掉这个标志.  
    if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)  
        new->flags &= ~IRQF_ONESHOT;  
  
    /*  
     * Protects against a concurrent __free_irq() call which might wait  
     * for synchronize_irq() to complete without holding the optional  
     * chip bus lock and desc->lock.  
     */  
    mutex_lock(&desc->request_mutex);  
  
    /*  
     * Acquire bus lock as the irq_request_resources() callback below  
     * might rely on the serialization or the magic power management  
     * functions which are abusing the irq_bus_lock() callback,  
     */  
    chip_bus_lock(desc);  
  
    /* First installed action requests resources. */  
    #中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.  
    if (!desc->action) {  
        ret = irq_request_resources(desc);  
        if (ret) {  
            pr_err("Failed to request resources for %s (irq %d) on irqchip %s
",  
                   new->name, irq, desc->irq_data.chip->name);  
            goto out_bus_unlock;  
        }  
    }  
  
    /*  
     * The following block of code has to be executed atomically  
     * protected against a concurrent interrupt and any of the other  
     * management calls which are not serialized via  
     * desc->request_mutex or the optional bus lock.  
     */  
    raw_spin_lock_irqsave(&desc->lock, flags);  
    old_ptr = &desc->action;  
    old = *old_ptr;  
    #如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了  
    #这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.  
    if (old) {  
        /*  
         * Can't share interrupts unless both agree to and are  
         * the same type (level, edge, polarity). So both flag  
         * fields must have IRQF_SHARED set and the bits which  
         * set the trigger type must match. Also all must  
         * agree on ONESHOT.  
         */  
        unsigned int oldtype;  
  
        /*  
         * If nobody did set the configuration before, inherit  
         * the one provided by the requester.  
         */  
        if (irqd_trigger_type_was_set(&desc->irq_data)) {  
            oldtype = irqd_get_trigger_type(&desc->irq_data);  
        } else {  
            oldtype = new->flags & IRQF_TRIGGER_MASK;  
            irqd_set_trigger_type(&desc->irq_data, oldtype);  
        }  
  
        if (!((old->flags & new->flags) & IRQF_SHARED) ||  
            (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||  
            ((old->flags ^ new->flags) & IRQF_ONESHOT))  
            goto mismatch;  
  
        /* All handlers must agree on per-cpuness */  
        if ((old->flags & IRQF_PERCPU) !=  
            (new->flags & IRQF_PERCPU))  
            goto mismatch;  
  
        /* add new interrupt at end of irq queue */  
        do {  
            /*  
             * Or all existing action->thread_mask bits,  
             * so we can find the next zero bit for this  
             * new action.  
             */  
            thread_mask |= old->thread_mask;  
            old_ptr = &old->next;  
            old = *old_ptr;  
        } while (old);  
        shared = 1;  
    }  
  
    /*  
     * Setup the thread mask for this irqaction for ONESHOT. For  
     * !ONESHOT irqs the thread mask is 0 so we can avoid a  
     * conditional in irq_wake_thread().  
     */  
    if (new->flags & IRQF_ONESHOT) {  
        /*  
         * Unlikely to have 32 resp 64 irqs sharing one line,  
         * but who knows.  
         */  
        if (thread_mask == ~0UL) {  
            ret = -EBUSY;  
            goto out_unlock;  
        }  
        /*  
         * The thread_mask for the action is or'ed to  
         * desc->thread_active to indicate that the  
         * IRQF_ONESHOT thread handler has been woken, but not  
         * yet finished. The bit is cleared when a thread  
         * completes. When all threads of a shared interrupt  
         * line have completed desc->threads_active becomes  
         * zero and the interrupt line is unmasked. See  
         * handle.c:irq_wake_thread() for further information.  
         *  
         * If no thread is woken by primary (hard irq context)  
         * interrupt handlers, then desc->threads_active is  
         * also checked for zero to unmask the irq line in the  
         * affected hard irq flow handlers  
         * (handle_[fasteoi|level]_irq).  
         *  
         * The new action gets the first zero bit of  
         * thread_mask assigned. See the loop above which or's  
         * all existing action->thread_mask bits.  
         */  
        new->thread_mask = 1UL << ffz(thread_mask);  
  
    } else if (new->handler == irq_default_primary_handler &&  
           !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {  
        /*  
         * The interrupt was requested with handler = NULL, so  
         * we use the default primary handler for it. But it  
         * does not have the oneshot flag set. In combination  
         * with level interrupts this is deadly, because the  
         * default primary handler just wakes the thread, then  
         * the irq lines is reenabled, but the device still  
         * has the level irq asserted. Rinse and repeat....  
         *  
         * While this works for edge type interrupts, we play  
         * it safe and reject unconditionally because we can't  
         * say for sure which type this interrupt really  
         * has. The type flags are unreliable as the  
         * underlying chip implementation can override them.  
         */  
        pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d
",  
               irq);  
        ret = -EINVAL;  
        goto out_unlock;  
    }  
    #非共享中断  
    if (!shared) {  
        #初始化一个等待队列,这个等待队列包含在中断描述符中  
        init_waitqueue_head(&desc->wait_for_threads);  
  
        /* Setup the type (level, edge polarity) if configured: */  
        if (new->flags & IRQF_TRIGGER_MASK) {  
            ret = __irq_set_trigger(desc,  
                        new->flags & IRQF_TRIGGER_MASK);  
  
            if (ret)  
                goto out_unlock;  
        }  
  
        /*  
         * Activate the interrupt. That activation must happen  
         * independently of IRQ_NOAUTOEN. request_irq() can fail  
         * and the callers are supposed to handle  
         * that. enable_irq() of an interrupt requested with  
         * IRQ_NOAUTOEN is not supposed to fail. The activation  
         * keeps it in shutdown mode, it merily associates  
         * resources if necessary and if that's not possible it  
         * fails. Interrupts which are in managed shutdown mode  
         * will simply ignore that activation request.  
         */  
         #激活这个中断  
        ret = irq_activate(desc);  
        if (ret)  
            goto out_unlock;  
  
        desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED |   
                  IRQS_ONESHOT | IRQS_WAITING);  
        irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);  
        #是不是percpu中断  
        if (new->flags & IRQF_PERCPU) {  
            irqd_set(&desc->irq_data, IRQD_PER_CPU);  
            irq_settings_set_per_cpu(desc);  
        }  
  
        if (new->flags & IRQF_ONESHOT)  
            desc->istate |= IRQS_ONESHOT;  
  
        /* Exclude IRQ from balancing if requested */  
        #不用设置irq balance  
        if (new->flags & IRQF_NOBALANCING) {  
            irq_settings_set_no_balancing(desc);  
            irqd_set(&desc->irq_data, IRQD_NO_BALANCING);  
        }  
        #开始中断  
        if (irq_settings_can_autoenable(desc)) {  
            irq_startup(desc, IRQ_RESEND, IRQ_START_COND);  
        } else {  
            /*  
             * Shared interrupts do not go well with disabling  
             * auto enable. The sharing interrupt might request  
             * it while it's still disabled and then wait for  
             * interrupts forever.  
             */  
            WARN_ON_ONCE(new->flags & IRQF_SHARED);  
            /* Undo nested disables: */  
            desc->depth = 1;  
        }  
  
    } else if (new->flags & IRQF_TRIGGER_MASK) {  
        unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;  
        unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);  
  
        if (nmsk != omsk)  
            /* hope the handler works with current  trigger mode */  
            pr_warn("irq %d uses trigger mode %u; requested %u
",  
                irq, omsk, nmsk);  
    }  
  
    *old_ptr = new;  
    #设置power相关  
    irq_pm_install_action(desc, new);  
  
    /* Reset broken irq detection when installing new handler */  
    desc->irq_count = 0;  
    desc->irqs_unhandled = 0;  
  
    /*  
     * Check whether we disabled the irq via the spurious handler  
     * before. Reenable it and give it another chance.  
     */  
    if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {  
        desc->istate &= ~IRQS_SPURIOUS_DISABLED;  
        __enable_irq(desc);  
    }  
  
    raw_spin_unlock_irqrestore(&desc->lock, flags);  
    chip_bus_sync_unlock(desc);  
    mutex_unlock(&desc->request_mutex);  
  
    irq_setup_timings(desc, new);  
  
    /*  
     * Strictly no need to wake it up, but hung_task complains  
     * when no hard interrupt wakes the thread up.  
     */  
    # 如果有中断线程的话,则wakeup线程  
    if (new->thread)  
        wake_up_process(new->thread);  
    if (new->secondary)  
        wake_up_process(new->secondary->thread);  
    #注册irq在proc中的接口  
    register_irq_proc(irq, desc);  
    new->dir = NULL;  
    register_handler_proc(irq, new);  
    return 0;  
  
mismatch:  
    if (!(new->flags & IRQF_PROBE_SHARED)) {  
        pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)
",  
               irq, new->flags, new->name, old->flags, old->name);  
#ifdef CONFIG_DEBUG_SHIRQ  
        dump_stack();  
#endif  
    }  
    ret = -EBUSY;  
#一下都是异常case  
out_unlock:  
    raw_spin_unlock_irqrestore(&desc->lock, flags);  
  
    if (!desc->action)  
        irq_release_resources(desc);  
out_bus_unlock:  
    chip_bus_sync_unlock(desc);  
    mutex_unlock(&desc->request_mutex);  
  
out_thread:  
    if (new->thread) {  
        struct task_struct *t = new->thread;  
  
        new->thread = NULL;  
        kthread_stop(t);  
        put_task_struct(t);  
    }  
    if (new->secondary && new->secondary->thread) {  
        struct task_struct *t = new->secondary->thread;  
  
        new->secondary->thread = NULL;  
        kthread_stop(t);  
        put_task_struct(t);  
    }  
out_mput:  
    module_put(desc->owner);  
    return ret;  
}  
[html] view plain copy
 
  1. int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction.  
  2.   
  3. 其使用的例程如下:  
  4. struct irq_domain * __init __init_i8259_irqs(struct device_node *node)  
  5. {  
  6.     struct irq_domain *domain;  
  7.   
  8.     insert_resource(&ioport_resource, &pic1_io_resource);  
  9.     insert_resource(&ioport_resource, &pic2_io_resource);  
  10.   
  11.     init_8259A(0);  
  12.   
  13.     domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0,  
  14.                        &i8259A_ops, NULL);  
  15.     if (!domain)  
  16.         panic("Failed to add i8259 IRQ domain");  
  17.   
  18.     setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);  
  19.     return domain;  
  20. }  
  21. 其源码分析如下:  
  22.   
  23. int setup_irq(unsigned int irq, struct irqaction *act)  
  24. {  
  25.     int retval;  
  26.     struct irq_desc *desc = irq_to_desc(irq);  
  27.     #中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出  
  28.     if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))  
  29.         return -EINVAL;  
  30.   
  31.     retval = irq_chip_pm_get(&desc->irq_data);  
  32.     if (retval < 0)  
  33.         return retval;  
  34.     #核心代码,设置irq对应的irqaction *act  
  35.     retval = __setup_irq(irq, desc, act);  
  36.   
  37.     if (retval)  
  38.         irq_chip_pm_put(&desc->irq_data);  
  39.   
  40.     return retval;  
  41. }  
  42. static int  
  43. __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  
  44. {  
  45.     struct irqaction *old, **old_ptr;  
  46.     unsigned long flags, thread_mask = 0;  
  47.     int ret, nested, shared = 0;  
  48.     #中断描述符为null,则退出  
  49.     if (!desc)  
  50.         return -EINVAL;  
  51.     #没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.  
  52.     if (desc->irq_data.chip == &no_irq_chip)  
  53.         return -ENOSYS;  
  54.     #增加这个模块的引用计数  
  55.     if (!try_module_get(desc->owner))  
  56.         return -ENODEV;  
  57.     #更新struct irqaction *new 中的irq number  
  58.     new->irq = irq;  
  59.   
  60.     /*  
  61.      * If the trigger type is not specified by the caller,  
  62.      * then use the default for this interrupt.  
  63.      */  
  64.      #没有设置中断触发类型的话,则用默认值.  
  65.     if (!(new->flags & IRQF_TRIGGER_MASK))  
  66.         new->flags |= irqd_get_trigger_type(&desc->irq_data);  
  67.   
  68.     /*  
  69.      * Check whether the interrupt nests into another interrupt  
  70.      * thread.  
  71.      */  
  72.     #检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套  
  73.     nested = irq_settings_is_nested_thread(desc);  
  74.     if (nested) {  
  75.         if (!new->thread_fn) {  
  76.             ret = -EINVAL;  
  77.             goto out_mput;  
  78.         }  
  79.         /*  
  80.          * Replace the primary handler which was provided from  
  81.          * the driver for non nested interrupt handling by the  
  82.          * dummy function which warns when called.  
  83.          */  
  84.         new->handler = irq_nested_primary_handler;  
  85.     } else {  
  86.     #这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化  
  87.         if (irq_settings_can_thread(desc)) {  
  88.             ret = irq_setup_forced_threading(new);  
  89.             if (ret)  
  90.                 goto out_mput;  
  91.         }  
  92.     }  
  93.   
  94.     /*  
  95.      * Create a handler thread when a thread function is supplied  
  96.      * and the interrupt does not nest into another interrupt  
  97.      * thread.  
  98.      */  
  99.     #在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程  
  100.     if (new->thread_fn && !nested) {  
  101.         ret = setup_irq_thread(new, irq, false);  
  102.         if (ret)  
  103.             goto out_mput;  
  104.         #中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.  
  105.         if (new->secondary) {  
  106.             ret = setup_irq_thread(new->secondary, irq, true);  
  107.             if (ret)  
  108.                 goto out_thread;  
  109.         }  
  110.     }  
  111.   
  112.     /*  
  113.      * Drivers are often written to work w/o knowledge about the  
  114.      * underlying irq chip implementation, so a request for a  
  115.      * threaded irq without a primary hard irq context handler  
  116.      * requires the ONESHOT flag to be set. Some irq chips like  
  117.      * MSI based interrupts are per se one shot safe. Check the  
  118.      * chip flags, so we can avoid the unmask dance at the end of  
  119.      * the threaded handler for those.  
  120.      */  
  121.     #有设置oneshot 标志的话,则清掉这个标志.  
  122.     if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)  
  123.         new->flags &= ~IRQF_ONESHOT;  
  124.   
  125.     /*  
  126.      * Protects against a concurrent __free_irq() call which might wait  
  127.      * for synchronize_irq() to complete without holding the optional  
  128.      * chip bus lock and desc->lock.  
  129.      */  
  130.     mutex_lock(&desc->request_mutex);  
  131.   
  132.     /*  
  133.      * Acquire bus lock as the irq_request_resources() callback below  
  134.      * might rely on the serialization or the magic power management  
  135.      * functions which are abusing the irq_bus_lock() callback,  
  136.      */  
  137.     chip_bus_lock(desc);  
  138.   
  139.     /* First installed action requests resources. */  
  140.     #中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.  
  141.     if (!desc->action) {  
  142.         ret = irq_request_resources(desc);  
  143.         if (ret) {  
  144.             pr_err("Failed to request resources for %s (irq %d) on irqchip %s ",  
  145.                    new->name, irq, desc->irq_data.chip->name);  
  146.             goto out_bus_unlock;  
  147.         }  
  148.     }  
  149.   
  150.     /*  
  151.      * The following block of code has to be executed atomically  
  152.      * protected against a concurrent interrupt and any of the other  
  153.      * management calls which are not serialized via  
  154.      * desc->request_mutex or the optional bus lock.  
  155.      */  
  156.     raw_spin_lock_irqsave(&desc->lock, flags);  
  157.     old_ptr = &desc->action;  
  158.     old = *old_ptr;  
  159.     #如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了  
  160.     #这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.  
  161.     if (old) {  
  162.         /*  
  163.          * Can't share interrupts unless both agree to and are  
  164.          * the same type (level, edge, polarity). So both flag  
  165.          * fields must have IRQF_SHARED set and the bits which  
  166.          * set the trigger type must match. Also all must  
  167.          * agree on ONESHOT.  
  168.          */  
  169.         unsigned int oldtype;  
  170.   
  171.         /*  
  172.          * If nobody did set the configuration before, inherit  
  173.          * the one provided by the requester.  
  174.          */  
  175.         if (irqd_trigger_type_was_set(&desc->irq_data)) {  
  176.             oldtype = irqd_get_trigger_type(&desc->irq_data);  
  177.         } else {  
  178.             oldtype = new->flags & IRQF_TRIGGER_MASK;  
  179.             irqd_set_trigger_type(&desc->irq_data, oldtype);  
  180.         }  
  181.   
  182.         if (!((old->flags & new->flags) & IRQF_SHARED) ||  
  183.             (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||  
  184.             ((old->flags ^ new->flags) & IRQF_ONESHOT))  
  185.             goto mismatch;  
  186.   
  187.         /* All handlers must agree on per-cpuness */  
  188.         if ((old->flags & IRQF_PERCPU) !=  
  189.             (new->flags & IRQF_PERCPU))  
  190.             goto mismatch;  
  191.   
  192.         /* add new interrupt at end of irq queue */  
  193.         do {  
  194.             /*  
  195.              * Or all existing action->thread_mask bits,  
  196.              * so we can find the next zero bit for this  
  197.              * new action.  
  198.              */  
  199.             thread_mask |= old->thread_mask;  
  200.             old_ptr = &old->next;  
  201.             old = *old_ptr;  
  202.         } while (old);  
  203.         shared = 1;  
  204.     }  
  205.   
  206.     /*  
  207.      * Setup the thread mask for this irqaction for ONESHOT. For  
  208.      * !ONESHOT irqs the thread mask is 0 so we can avoid a  
  209.      * conditional in irq_wake_thread().  
  210.      */  
  211.     if (new->flags & IRQF_ONESHOT) {  
  212.         /*  
  213.          * Unlikely to have 32 resp 64 irqs sharing one line,  
  214.          * but who knows.  
  215.          */  
  216.         if (thread_mask == ~0UL) {  
  217.             ret = -EBUSY;  
  218.             goto out_unlock;  
  219.         }  
  220.         /*  
  221.          * The thread_mask for the action is or'ed to  
  222.          * desc->thread_active to indicate that the  
  223.          * IRQF_ONESHOT thread handler has been woken, but not  
  224.          * yet finished. The bit is cleared when a thread  
  225.          * completes. When all threads of a shared interrupt  
  226.          * line have completed desc->threads_active becomes  
  227.          * zero and the interrupt line is unmasked. See  
  228.          * handle.c:irq_wake_thread() for further information.  
  229.          *  
  230.          * If no thread is woken by primary (hard irq context)  
  231.          * interrupt handlers, then desc->threads_active is  
  232.          * also checked for zero to unmask the irq line in the  
  233.          * affected hard irq flow handlers  
  234.          * (handle_[fasteoi|level]_irq).  
  235.          *  
  236.          * The new action gets the first zero bit of  
  237.          * thread_mask assigned. See the loop above which or's  
  238.          * all existing action->thread_mask bits.  
  239.          */  
  240.         new->thread_mask = 1UL << ffz(thread_mask);  
  241.   
  242.     } else if (new->handler == irq_default_primary_handler &&  
  243.            !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {  
  244.         /*  
  245.          * The interrupt was requested with handler = NULL, so  
  246.          * we use the default primary handler for it. But it  
  247.          * does not have the oneshot flag set. In combination  
  248.          * with level interrupts this is deadly, because the  
  249.          * default primary handler just wakes the thread, then  
  250.          * the irq lines is reenabled, but the device still  
  251.          * has the level irq asserted. Rinse and repeat....  
  252.          *  
  253.          * While this works for edge type interrupts, we play  
  254.          * it safe and reject unconditionally because we can't  
  255.          * say for sure which type this interrupt really  
  256.          * has. The type flags are unreliable as the  
  257.          * underlying chip implementation can override them.  
  258.          */  
  259.         pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d ",  
  260.                irq);  
  261.         ret = -EINVAL;  
  262.         goto out_unlock;  
  263.     }  
  264.     #非共享中断  
  265.     if (!shared) {  
  266.         #初始化一个等待队列,这个等待队列包含在中断描述符中  
  267.         init_waitqueue_head(&desc->wait_for_threads);  
  268.   
  269.         /* Setup the type (level, edge polarity) if configured: */  
  270.         if (new->flags & IRQF_TRIGGER_MASK) {  
  271.             ret = __irq_set_trigger(desc,  
  272.                         new->flags & IRQF_TRIGGER_MASK);  
  273.   
  274.             if (ret)  
  275.                 goto out_unlock;  
  276.         }  
  277.   
  278.         /*  
  279.          * Activate the interrupt. That activation must happen  
  280.          * independently of IRQ_NOAUTOEN. request_irq() can fail  
  281.          * and the callers are supposed to handle  
  282.          * that. enable_irq() of an interrupt requested with  
  283.          * IRQ_NOAUTOEN is not supposed to fail. The activation  
  284.          * keeps it in shutdown mode, it merily associates  
  285.          * resources if necessary and if that's not possible it  
  286.          * fails. Interrupts which are in managed shutdown mode  
  287.          * will simply ignore that activation request.  
  288.          */  
  289.          #激活这个中断  
  290.         ret = irq_activate(desc);  
  291.         if (ret)  
  292.             goto out_unlock;  
  293.   
  294.         desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED |   
  295.                   IRQS_ONESHOT | IRQS_WAITING);  
  296.         irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);  
  297.         #是不是percpu中断  
  298.         if (new->flags & IRQF_PERCPU) {  
  299.             irqd_set(&desc->irq_data, IRQD_PER_CPU);  
  300.             irq_settings_set_per_cpu(desc);  
  301.         }  
  302.   
  303.         if (new->flags & IRQF_ONESHOT)  
  304.             desc->istate |= IRQS_ONESHOT;  
  305.   
  306.         /* Exclude IRQ from balancing if requested */  
  307.         #不用设置irq balance  
  308.         if (new->flags & IRQF_NOBALANCING) {  
  309.             irq_settings_set_no_balancing(desc);  
  310.             irqd_set(&desc->irq_data, IRQD_NO_BALANCING);  
  311.         }  
  312.         #开始中断  
  313.         if (irq_settings_can_autoenable(desc)) {  
  314.             irq_startup(desc, IRQ_RESEND, IRQ_START_COND);  
  315.         } else {  
  316.             /*  
  317.              * Shared interrupts do not go well with disabling  
  318.              * auto enable. The sharing interrupt might request  
  319.              * it while it's still disabled and then wait for  
  320.              * interrupts forever.  
  321.              */  
  322.             WARN_ON_ONCE(new->flags & IRQF_SHARED);  
  323.             /* Undo nested disables: */  
  324.             desc->depth = 1;  
  325.         }  
  326.   
  327.     } else if (new->flags & IRQF_TRIGGER_MASK) {  
  328.         unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;  
  329.         unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);  
  330.   
  331.         if (nmsk != omsk)  
  332.             /* hope the handler works with current  trigger mode */  
  333.             pr_warn("irq %d uses trigger mode %u; requested %u ",  
  334.                 irq, omsk, nmsk);  
  335.     }  
  336.   
  337.     *old_ptr = new;  
  338.     #设置power相关  
  339.     irq_pm_install_action(desc, new);  
  340.   
  341.     /* Reset broken irq detection when installing new handler */  
  342.     desc->irq_count = 0;  
  343.     desc->irqs_unhandled = 0;  
  344.   
  345.     /*  
  346.      * Check whether we disabled the irq via the spurious handler  
  347.      * before. Reenable it and give it another chance.  
  348.      */  
  349.     if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {  
  350.         desc->istate &= ~IRQS_SPURIOUS_DISABLED;  
  351.         __enable_irq(desc);  
  352.     }  
  353.   
  354.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
  355.     chip_bus_sync_unlock(desc);  
  356.     mutex_unlock(&desc->request_mutex);  
  357.   
  358.     irq_setup_timings(desc, new);  
  359.   
  360.     /*  
  361.      * Strictly no need to wake it up, but hung_task complains  
  362.      * when no hard interrupt wakes the thread up.  
  363.      */  
  364.     # 如果有中断线程的话,则wakeup线程  
  365.     if (new->thread)  
  366.         wake_up_process(new->thread);  
  367.     if (new->secondary)  
  368.         wake_up_process(new->secondary->thread);  
  369.     #注册irq在proc中的接口  
  370.     register_irq_proc(irq, desc);  
  371.     new->dir = NULL;  
  372.     register_handler_proc(irq, new);  
  373.     return 0;  
  374.   
  375. mismatch:  
  376.     if (!(new->flags & IRQF_PROBE_SHARED)) {  
  377.         pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s) ",  
  378.                irq, new->flags, new->name, old->flags, old->name);  
  379. #ifdef CONFIG_DEBUG_SHIRQ  
  380.         dump_stack();  
  381. #endif  
  382.     }  
  383.     ret = -EBUSY;  
  384. #一下都是异常case  
  385. out_unlock:  
  386.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
  387.   
  388.     if (!desc->action)  
  389.         irq_release_resources(desc);  
  390. out_bus_unlock:  
  391.     chip_bus_sync_unlock(desc);  
  392.     mutex_unlock(&desc->request_mutex);  
  393.   
  394. out_thread:  
  395.     if (new->thread) {  
  396.         struct task_struct *t = new->thread;  
  397.   
  398.         new->thread = NULL;  
  399.         kthread_stop(t);  
  400.         put_task_struct(t);  
  401.     }  
  402.     if (new->secondary && new->secondary->thread) {  
  403.         struct task_struct *t = new->secondary->thread;  
  404.   
  405.         new->secondary->thread = NULL;  
  406.         kthread_stop(t);  
  407.         put_task_struct(t);  
  408.     }  
  409. out_mput:  
  410.     module_put(desc->owner);  
  411.     return ret;  
  412. }  
原文地址:https://www.cnblogs.com/sky-heaven/p/8907958.html