local_irq_disable和disable_irq的区别

原创 2016年06月01日 11:53:10

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

对于中断的处理,内核有一套自己的流程,它会调用high level irq handler来做最上层的处理,内核中定义了多种high level irq handler,比如电平触发方式的处理函数handle_level_irq,还有边缘触发方式的处理函数handle_edge_irq等等。每个handler都需要在特定场景下才能使用,它会被赋值给irqchip驱动,并由chip来调用使用。

具体可以参考蜗窝上的文章,对两种场景有比较详细的介绍。我们接下来讨论电平触发的场景,来看看如何在所有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后,中断控制器立刻就会感知到外设上的中断信号。由此进入中断处理流程。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

local_irq_disable与local_irq_enable

这两个函数可用于禁止与激活当前处理器(仅仅是当前处理器)上的所有本地中断(所有本地中断线上的中断),禁止本地CPU中断是确保一组内核语句被当作一个临界区处理的主要机制。这个机制的意义是:即使当硬件设备...

local_irq_save和 local_irq_disable

local_irq_disable禁用当前处理器上的中断发送。注意, flags 被直接传递, 而不是通过指针来传递。 local_irq_disable不保存状态而关闭本地处理器上的中断发送; 只...
  • bytxl
  • bytxl
  • 2015-09-26 15:00
  • 767

实时抢占补丁概观

A realtime preemption overview(2005-08-10/Paul McKenney) 实时抢占补丁概观 Yang Honggang ref: http://lwn.net...

rtlinux - hello

rt preempt -- 编译实时内核

rtpreempt howto Yang Honggang ------------------------- ref: https://rt.wiki.kernel.org/index.ph...

local_irq_disable

local_irq_disable仅仅是设置当前CPU的中断屏蔽位 disable_irq 是禁用全部cpu中断(只是当前irq) 如果你要禁止所有的中断该怎么办? 在2.6内...

互斥与同步——local_irq_enable与local_irq_disable

互斥与同步——local_irq_enable与local_irq_disable 内核版本:2.6.30 平台:arm 在单处理器不可抢占系统中,使用local_irq_enable和loca...

关于中断处理程序中的关中断函数disable_irq和disable_irq_nosync

disable_irq关闭中断并等待中断处理完后返回, 而disable_irq_nosync立即返回. 那么在中断处理程序中应该使用哪一个函数来关闭中断呢? 在中的按键驱动中, 使用disable...

关于中断处理程序中的关中断函数disable_irq和disable_irq_nosync

disable_irq关闭中断并等待中断处理完后返回, 而disable_irq_nosync立即返回. 那么在中断处理程序中应该使用哪一个函数来关闭中断呢?在中的按键驱动中, 使用disable_i...

关于中断处理程序中的关中断函数disable_irq和disable_irq_nosync

disable_irq关闭中断并等待中断处理完后返回, 而disable_irq_nosync立即返回. 那么在中断处理程序中应该使用哪一个函数来关闭中断呢?在中的按键驱动中, 使用disable_i...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)