zoukankan      html  css  js  c++  java
  • 中断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. }  
  • 相关阅读:
    密码验证合格程序(Python)
    Python找到所有子集
    Semi-Supervised Classification with Graph Convolutional Networks 阅读笔记
    2018 ICPC南京网络赛 L Magical Girl Haze 题解
    2018 CCPC网络赛 hdu6444 Neko's loop
    2018 CCPC 网络赛 Buy and Resell
    实对称矩阵可对角化证明
    矩阵的极分解证明
    关于欧几里得空间上的仿射变换的直观几何理解
    Codeforces Hello 2018 E题Logical Expression dp+最短路 好题
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/8907958.html
Copyright © 2011-2022 走看看