中断

2.5.2-rmk5

这是第一个包含一些主要的架构特定子系统重大调整的内核。

首先,它包含对我们处理 MMU TLB 方式的一些相当大的更改。每个 MMU TLB 变体现在都完全单独处理 - 我们有 TLB v3、TLB v4(无写缓冲)、TLB v4(有写缓冲)以及最后 TLB v4(有写缓冲,带有 I TLB 无效条目)。这些函数内部有更多的汇编代码,主要是为了允许将来更灵活地处理 TLB。

其次,是 IRQ 子系统。

2.5 内核将对处理 IRQ 的方式进行重大更改。不幸的是,这意味着会破坏接触 irq_desc[] 数组的机器类型(基本上是所有机器类型),这意味着我们目前拥有的每个机器类型都会被破坏。

让我们举个例子。在带有 Neponset 的 Assabet 上,我们有

          GPIO25                 IRR:2
SA1100 ------------> Neponset -----------> SA1111
                                 IIR:1
                              -----------> USAR
                                 IIR:0
                              -----------> SMC9196

目前的工作方式,所有 SA1111 中断都是相互排斥的 - 如果您正在处理来自 SA1111 的一个中断,而另一个中断进入,您必须等待该中断完成处理才能处理新的中断。例如,SA1111 上的基于 IDE PIO 的中断会排除所有其他 SA1111 和 SMC9196 中断,直到它完成传输多扇区数据,这可能需要很长时间。还要注意,由于我们在 SA1111 IRQ 处理程序中循环,SA1111 IRQ 可以无限期地阻止 SMC9196 IRQ。

新方法带来了几个新想法……

我们引入了“父”和“子”的概念。例如,对于 Neponset 处理程序,“父”是 GPIO25,“子”是 SA1111、SMC9196 和 USAR。

我们还引入了 IRQ“芯片”的概念(主要是为了减小 irqdesc 数组的大小)。这不一定是真正的“IC”;事实上,SA11x0 IRQ 由两个单独的“芯片”结构处理,一个用于 GPIO0-10,另一个用于其余所有。它只是各种操作的容器(也许这会改成一个更好的名称)。该结构具有以下操作

struct irqchip {
        /*
         * Acknowledge the IRQ.
         * If this is a level-based IRQ, then it is expected to mask the IRQ
         * as well.
         */
        void (*ack)(unsigned int irq);
        /*
         * Mask the IRQ in hardware.
         */
        void (*mask)(unsigned int irq);
        /*
         * Unmask the IRQ in hardware.
         */
        void (*unmask)(unsigned int irq);
        /*
         * Re-run the IRQ
         */
        void (*rerun)(unsigned int irq);
        /*
         * Set the type of the IRQ.
         */
        int (*type)(unsigned int irq, unsigned int, type);
};
ack
  • 必需的。对于由 do_level_IRQ 处理的 IRQ,可能与 mask 函数相同。

mask
  • 必需的。

unmask
  • 必需的。

rerun
  • 可选的。如果您对使用此“irqchip”的所有 IRQ 使用 do_level_IRQ,则不需要。通常期望在可能的情况下重新触发硬件 IRQ。如果不可能,可以直接调用处理程序。

type
  • 可选的。如果您不支持更改 IRQ 的类型,则应为空,以便人们可以检测到他们是否无法设置 IRQ 类型。

对于每个 IRQ,我们保留以下信息

  • “禁用”深度(没有 disable_irq()enable_irq() 数量)

  • 指示我们可以对此 IRQ 执行的操作的标志(valid、probe、noautounmask),如前所述

  • IRQ 的状态(probing、enable 等)

  • chip

  • 每个 IRQ 的处理程序

  • irqaction 结构列表

处理程序可以是 3 个标准处理程序之一 - “level”、“edge” 和 “simple”,或者如果您需要执行特殊操作,则可以使用您自己的特定处理程序。

“level”处理程序是我们目前拥有的 - 它非常简单。“edge”知道这种 IRQ 实现的缺陷 - 您需要在处理 IRQ 时保持硬件 IRQ 启用,并且如果处理过程中再次发生 IRQ,则应将进一步的 IRQ 事件排队。“simple”处理程序非常基本,不执行任何硬件操作,也不进行状态跟踪。这对于上面的 SMC9196 和 USAR 之类的东西很有用。

那么,有什么变化?

  1. 机器实现不得写入 irqdesc 数组。

  2. 操作 irqdesc 数组的新函数。前 4 个预计仅对机器特定的代码有用。建议最后一个仅由机器特定的代码使用,但如果绝对必要,可以在驱动程序中使用。

    set_irq_chip(irq,chip)

    设置用于处理此 IRQ 的 mask/unmask 方法

    set_irq_handler(irq,handler)

    设置此 IRQ 的处理程序(level、edge、simple)

    set_irq_chained_handler(irq,handler)

    为此 IRQ 设置“链接”处理程序 - 自动启用此 IRQ(例如,Neponset 和 SA1111 处理程序)。

    set_irq_flags(irq,flags)

    设置 valid/probe/noautoenable 标志。

    set_irq_type(irq,type)

    设置活动 IRQ 边沿/电平。这取代了 SA1111 INTPOL 操作和 set_GPIO_IRQ_edge() 函数。Type 应为 <linux/irq.h> 中定义的 IRQ_TYPE_xxx 之一

  3. set_GPIO_IRQ_edge() 已过时,应替换为 set_irq_type。

  4. 直接访问 SA1111 INTPOL 已弃用。请改用 set_irq_type。

  5. 处理程序应通过正确的芯片特定函数执行对父 IRQ 的任何必要的确认。例如,如果 SA1111 直接连接到 SA1110 GPIO,那么每次重新读取 SA1111 IRQ 状态时都应确认 SA1110 IRQ。

  6. 对于任何没有自己的 IRQ 启用/禁用控件的子项(例如,SMC9196),处理程序必须在调用子处理程序时屏蔽或确认父 IRQ,并且子处理程序应为“simple”处理程序(不是“edge”也不是“level”)。处理程序完成后,应取消屏蔽父 IRQ,并且必须重新检查所有子项的状态是否有待处理的事件。(有关详细信息,请参阅 Neponset IRQ 处理程序)。

  7. fixup_irq() 已消失,arch/arm/mach-*/include/mach/irq.h 也是如此

请注意,这不会解决所有问题 - 其中一些是基于硬件的。在同一父信号(例如 neponset)上混合基于电平和基于边沿的 IRQ 是一个软件解决方案无法为低 IRQ 延迟提供完整答案的领域。