• local_irq_disable和disable_irq的区别


    local_irq_disable:

    local_irq_disable的功能是屏蔽当前CPU上的所有中断,通过操作arm核心中的寄存器来屏蔽到达CPU上的中断,此时中断控制器中所有送往该CPU上的中断信号都将被忽略。

    Kernel/arch/arm/include/asm/irqflag.h

    static inline void arch_local_irq_disable(void)
    {
        asm volatile(
            "   cpsid i         @ arch_local_irq_disable"
            :
            :
            : "memory", "cc");
    }
    

    kernel/include/linux/irqflags.h

    #define raw_local_irq_disable()     arch_local_irq_disable()
    
    #define local_irq_disable() 
          do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)
    

    disable_irq:

    在全局范围内屏蔽某一个中断号(irq num)。该irq num对应的irq handler不会在任何一个CPU上执行。这个操作是通过设置中断控制器中的寄存器来对指定中断进行屏蔽,而其他未屏蔽的中断依然可以正常送往CPU。

    413 void disable_irq(unsigned int irq)
     414 {
     415     if (!__disable_irq_nosync(irq))
     416         synchronize_irq(irq);
     417 }
    
    372 static int __disable_irq_nosync(unsigned int irq)
     373 {
     374     unsigned long flags;
     375     struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_     CHECK_GLOBAL);
     376 
     377     if (!desc)
     378         return -EINVAL;
     379     __disable_irq(desc, irq, false);
     380     irq_put_desc_busunlock(desc, flags);
     381     return 0;
     382 }
     383
    
    360 void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
     361 {
     362     if (suspend) {
     363         if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
     364             return;
     365         desc->istate |= IRQS_SUSPENDED;
     366     }
     367 
     368     if (!desc->depth++)
     369         irq_disable(desc);
     370 }
    

    chip.c

    216 void irq_disable(struct irq_desc *desc)
    217 {
    218     irq_state_set_disabled(desc);
    219     if (desc->irq_data.chip->irq_disable) {
    220         desc->irq_data.chip->irq_disable(&desc->irq_data);
    221         irq_state_set_masked(desc);
    222     }
    223 }
    
    160 static void irq_state_set_disabled(struct irq_desc *desc)
    161 {
    162     irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
    163 }
    

    一个中断处理的流程是这样的:

    关CPU中断——–>mask and ack interrupt controller——–>设备驱动中注册的irq_handler ——>unmask interrupt controller——–>开CPU中断 
    

    我们需要在irq_handler中做如下处理,其中包含了一个启动下半部softirq的操作(可选)。

    ack device irq——–>copy data to ram——>raise softirq
    

    在代码中,是这样的调用流程:

    High level irq handler 
    –> mask_ack_irq 
    –>chip->irq_mask 
    –>chip->irq_ack 
    –> handle_irq_event (就是调用irq_handler的处理) 
    –>chip-> irq_unmask
    

    具体可以参考蜗窝上的文章,对两种场景有比较详细的介绍。我们接下来讨论电平触发的场景,来看看如何在所有CPU上进行屏蔽中断的。其他场景可以举一反三。

    void handle_level_irq(unsigned int irq, struct irq_desc *desc) 
    { 
        raw_spin_lock(&desc->lock); 
        mask_ack_irq(desc); 
        if (unlikely(irqd_irq_inprogress(&desc->irq_data))) 
            if (!irq_check_poll(desc)) 
                goto out_unlock; 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);--和retrigger中断以及自动探测IRQ相关 
        kstat_incr_irqs_this_cpu(irq, desc); 
    
        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); 
    } 
    

    从代码中可以看到,在函数中首先做的就是mask_ack_irq,在其中会调用chip中的回调来设置硬件。

    static inline void mask_ack_irq(struct irq_desc *desc)
     {
         if (desc->irq_data.chip->irq_mask_ack)
             desc->irq_data.chip->irq_mask_ack(&desc->irq_data);
         else {
             desc->irq_data.chip->irq_mask(&desc->irq_data);
             if (desc->irq_data.chip->irq_ack)
                 desc->irq_data.chip->irq_ack(&desc->irq_data);
         }
         irq_state_set_masked(desc);
     }
    

    该函数中调用的就是chip中的irq_mask和irq_ack来操作chip中的寄存器.其中的irqd_irq_disabled就是用来判断该中断是否被其他CPU给disable了,这里的disable就是调用disable_irq函数来做的,由此可见,使用disable_irq会在所有的CPU上把中断号给屏蔽掉。

    当在一个CPU上调用了disable_irq的时候,可能另一个CPU已经接收了中断了,但是在handler的处理中可以看到,它会判断是否被其它CPU disable了,如果disable了,它会把这个中断标志设置为IRQS_PENDING,但并不会去执行irq handler,而是直接退出,此时也没有调用unmask函数,由此就屏蔽了该中断,注意这里的mask和ack只是对于中断控制器到CPU上的信号进行了屏蔽,而外设到中断控制器上的中断信号并没有消失。

    而在使能中断函数enable_irq中,我们可以看到它会调用unmask来取消该中断的屏蔽。由于是电平触发,所以当unmask后,中断控制器立刻就会感知到外设上的中断信号。由此进入中断处理流程。

  • 相关阅读:
    Docker 学习4 Docker容器虚拟化网络概述
    Ceph 命令
    Day_09【常用API】扩展案例1_程序中使用一个长度为3的对象数组,存储用户的登录名和密码……
    Day_08【面向对象】扩展案例4_年龄为30岁的老王养了一只黑颜色的2岁的宠物……
    Day_08【面向对象】扩展案例3_使用多态的形式创建缉毒狗对象,调用缉毒方法和吼叫方法
    Day_08【面向对象】扩展案例2_测试旧手机新手机类,并给新手机实现玩游戏功能
    Day_08【面向对象】扩展案例1_测试项目经理类和程序员类
    用两个栈实现队列
    二叉树前序、中序、后序遍历相互求法
    洗牌
  • 原文地址:https://www.cnblogs.com/linhaostudy/p/10537054.html
Copyright © 2020-2023  润新知