中断子系统

1       中断处理流程

2       RefLink

link

comment

综述

从硬件的角度, 描述了中断控制器的架构以及多个中断控制器级联的情况

IRQ Domain介绍

描述了如何建立一个map, 以便把HW interrupt ID转换为IRQ Number, 这个过程与dts中的interrupt-controller和interrupts+interrupt-parent属性有关系.

IRQ number和中断描述符

描述了如何初始化irq_desc[]这个池子, 每个irq_desc描述了与这个中断相关的所有信息, 包含High level irq event handler, specific handler等

High level irq event handler

描述High level irq event handler的处理细节

驱动申请中断API

描述驱动如何调用request_threaded_irq注册处理函数.

ARM中断处理过程

描述从硬件产生中断信号的那一刻开始, 整个中断处理的宏观流程. 参见上图.

GIC代码分析

描述了ARM使用的中断控制器Generic Interrupt Controller的硬件结构以及该硬件的驱动代码的详细分析.

softirq

描述softirq的触发和处理逻辑. 介绍了各种context, 如中断上下文等.

 

softirq是指在用软件设定一个标记, 然后在硬件中断函数退出或softirqd这个内核线程中检测该标记, 如果发现标记被设定, 则执行相应的处理函数.  也就是说softirq并未触发任何硬件中断.

 

softirq一般用于中断底半部, tasklet相比, 它可能被多个CPU同时调度运行, tasklet只有被某一个CPU调度运行完毕后才可能被另一个CPU调度运行也就是说在SMP系统中, 可能存在某个sotfirq_handler的多个实例, 但只会存在某个tasklet_handler的一个实例.

 

softirqtasklet其实都是运行在中断上下文中. 它们存在的目的是什么? 在中断的顶半部中, 我们一般会先关中断, 然后处理, 然后开中断, 如果处理过程很耗时, 那这段时间由于中断被关闭, 我们可能丢失一些硬件中断softirq/tasklet存在的意义就是把耗时的处理过程从顶半部提取出来放到softirq_handler, 让顶半部先开中断, 然后在中断流程退出时在调度softirq_handler.

 

另外, softirq_handler在某CPU上运行时, 不可能被另外一个softirq_handler抢占. 也就说某个CPU, softirq_handler的执行是串行化的. tasklet也一样.

tasklet

tasklet是底半部的另一种机制.

 

它本质上是基于softirq机制构建的, 目的是为了方便驱动工程师更便捷的编写底半部代码.

 

但实际来看, 这种便捷性没有太大的必要. Steven Rostedt试图删除所有的tasklet, 把那些要求实时处理的放到softirq里面, 把那些不要实时处理的放入workqueuehandler  threaded http://lwn.net/Articles/239484/, 不过这个patch始终未能进入main line

workqueue

 http://www.wowotech.net/irq_subsystem/workqueue.html

http://www.wowotech.net/irq_subsystem/cmwq-intro.html

http://www.wowotech.net/irq_subsystem/alloc_workqueue.html

http://www.wowotech.net/irq_subsystem/queue_and_handle_work.html

3       FAQs

3.1    Proc interface

通过/proc/interrupts /proc/stat 可查看中断产生的次数. 详见: 10.2.1. The /proc Interface

3.2    使能/禁止中断的API

ref : http://www.makelinux.net/ldd3/chp-10-sect-7.shtml

  • enable_irq(irq_number) /  disable_irq(irq_number) 可以使能/禁止某一个中断.
  • local_irq_enable() / local_irq_disable() / local_irq_save(unsigned long flags) / local_irq_restore(unsigned long flags) 可使能/禁止某个CPU上的所有中断
  • 但是不能禁止所有CPU上的所有中断

3.3    中断处理过程中开关中断的时机与中断抢占嵌套问题

Note : 下来描述个依据上面文章的个人总结, 并未在实际代码中验证, 后续发现错误在修正.

  1. interrupt controller通过IRQ assert CPU CPU读取HW interrupt ID , 然后ack controller
    • 这段时间, 由于CPU还未ACK, 因此IRQ line一直处于assert状态, 也就是说CPU侧只收到了一次中断信号.
    • CPU ACK之前, 如果有更高优先级的中断产生, 则中断控制器直接把interrupt ID修改为高优先级中断的ID, 这样当CPU读取HW interrupt ID, 读到的就是高优先级中断的ID.

那这种情况下低优先级的那次中断是不是丢失了呢不会, interrupt controller会记录这个状态, CPU处理完高优先级的中断时, 会发送EOIcontroller,  controller收到EOI, 会再次assert CPU, 这次上报的是之前那个低优先级中断的ID.

  1. cpuack顶半部执行完毕
    • CPU ack, controllerdeassert. 此时如果有新的中断产生, 并且中断没有被软件禁止, controller是有能力重新assert CPU.
    • 对于电平触发的中断, CPUack的同时会mask这个中断, mask意味着暂时禁止了本中断(必须mask的原因是电平信号是一直有效的, 如果不mask, 一旦ack, controller马上又会assert CPU, 这显然是一次误报) . 当中断顶半部执行完毕, 会重新unmask该中断换句话说, 对于电平触发中断, 在整个顶半部的执行过程中, 本中断都是被禁止的.
    • 对于边沿触发的中断, CPU只会ack, 这就意味着ack, 顶半部执行过程中, 如果再次产生了同一个中断, controller会重新assert CPU.  不过由于前一个中断还没有EOI, 因此controller可能会assert 另一个CPU (例如CPU2). CPU2在处理此次中断时, 由于检测到CPU1正在处理同一个中断, 因此CPU2只是会设置一下pending标志, 然后ack & mask该中断, 注意此时mask. CPU1在处理完第一次中断事件的顶半部后, 会检测pending标志, 如果被设置, CPU1会再执行一次顶半部, 等第二次顶半部执行完毕后, unmask中断并退. 换句话说, 对于边沿触发中断, 在整个顶半部执行过程中, 中断可能且仅可能被多触发一次详见High level irq event handler.
    • 不管是哪种触发方式, 当CPU ack后, 在顶半部的执行过程中, 都是可能被高优先级的中断抢占的.
  2. 底半部执行过程中

设计底半部的一个原因就是为了尽快打开中断, 以免中断丢失. 因此在底半部的处理过程中是可能被同优先级或高优先级的中断打断的.

有几个不同点是:

  • 对于tasklet, 即使由于短时间内产生了多个中断导致它被调度了多次, 最终运行的时候也只有一次而且当它已经开始运行后, 由于中断而在此被调度时, 即使在SMP的情况下, 也只有等到第一次运行完毕后才能执行后面的调度. 也就是说tasklet在整个系统内部都是串行处理的.
  • 对于softirq, 在同一个CPU, 它是串行运行的. 但是在SMP的情况下, 它可能在多个CPU上并行运行.
  • 对于workqueuethreaded handler, 被调度几次就会运行几次, 即使在同一个CPU上有可能存在多个实例并行运行.

3.4    中断处理函数(handler)的注意事项

http://www.makelinux.net/ldd3/chp-10-sect-3.shtml : 10.3. Implementing a Handler

  • A handler can't transfer data to or from user space, because it doesn't execute in the context of a process
  • Handlers also cannot do anything that would sleep, such as calling wait_event, allocating memory with anything other than GFP_ATOMIC, or locking a semaphore.
  • Finally, handlers cannot call schedule.

3.5    中断中不能睡眠的真正原因

3.6    为什么中断执行过程越快越好

这里说的越快越好是针对顶半部.

因为在顶半部执行过程中电平触发类型的中断是会被mask, 边沿触发类型的只会多接收一次, 然后也会被mask. 如果顶半部执行时间过长, 那么就可能丢失中断.

另外, 中断的优先级比任何进程的优先级都要高, 在中断执行过程中, 是不会进行进程调度的, 如果其耗时过长, 会影响调度的实时性, 进而会让用户觉得卡顿.

posted @ 2020-12-13 17:45  johnliuxin  阅读(175)  评论(0)    收藏  举报