ARM A7 Linux原始中断处理可能吗?

时间:2016-08-12 23:12:51

标签: c linux linux-kernel irq

我想编写一个用于控制Linux中步进电机的开源核心驱动程序。在这种情况下,尤其是3D打印机。

基本思想是驱动程序在一个IO端口上保留引脚,然后立即操作这些引脚。它接收一个充满“切换,切换”值的缓冲区,然后使用硬件计时器将这些值发送到端口。

现在的问题是:有没有办法尽快处理特定的硬件中断?

有问题的芯片是Allwinner H3,我正在使用所述芯片的TMR1资源(IRQ 51)。我可以很好地使用它,它也可以用作中断:

static irqreturn_t stepCore_timer_interrupt(int irq, void *dev_id)
{
        writel(TMR1_IRQ_PEND, TMR_IRQ_ST_VREG);
        icnt++;

        porta_state = readl(PA_VDAT);
        porta_state &= porta_mask;

        if(icnt & 0x00000001)
        {
            porta_state |= 0x00000001;
        }

        writel(porta_state, PA_VDAT);

        return IRQ_HANDLED;
}

static struct irqaction stepCore_timer_irq = {
        .name = "stepCore_timer",
        .flags = IRQF_DISABLED | IRQF_NOBALANCING , IRQF_PERCPU,
        .handler = stepCore_timer_interrupt,
        .dev_id = NULL,
};

static void stepCore_timer_interrupt_setup(void)
{
    int ret;
    u32 val;

    writel( 24000000, TMR1_INTV_VALUE_VREG );
    writel( ( TMR1_MODE_CONTINUOUS | TMR1_CLK_PRES_1 | TMR1_CLK_SRC_OSC24M ), TMR1_CTRL_VREG );

    ret = setup_irq(SUNXI_IRQ_TIMER1, &stepCore_timer_irq);
    if (ret)
            printk("%s: ERROR: failed to install irq %d\n", __func__, SUNXI_IRQ_TIMER1);
    else
            printk("%s: irq %d installed\n", __func__, SUNXI_IRQ_TIMER1);

    ret = irq_set_affinity_hint(SUNXI_IRQ_TIMER1, cpumask_of(3));
    if (ret)
            printk("%s: ERROR: failed to set irq affinity for irq %d\n", __func__, SUNXI_IRQ_TIMER1);
    else
            printk("%s: set irq affinity for irq %d\n", __func__, SUNXI_IRQ_TIMER1);
    /* Enable timer0 interrupt */
    val = readl(TMR_IRQ_EN_VREG);
    writel(val | TMR1_IRQ_EN, TMR_IRQ_EN_VREG);

}

TMR1未被使用(事实上,我必须自己添加),到目前为止还可以。但是,在处理相当简单的IRQ例程时存在相当长的延迟。由于我想生成一些可用于3D打印机的代码,我非常喜欢更“稳定”的定时器中断。

所以,我的问题是:有没有办法在Linux中拥有一个具有最高优先级的非常短的IRQ例程?甚至根本不关心Linux调度程序,只是“做它的事情”?基本上是一个原始的IRQ处理程序,忽略Linux认为它应该是什么?

无论如何,它运行的核心专门用于完成该任务。处理程序将尽可能短:从数组中获取u32,将其写入端口,完成。

最好我希望有一些东西可以忽略Linux的其余部分。是的,我知道这不是办法。但这是针对一个相当特殊的情况,所以我对调整常规内核源代码以满足这些需求没有任何疑虑。

哦,这提醒我,内核是3.4.112,带有合适的preempt-rt补丁。

非常感谢任何帮助。

问候,

克里斯

2 个答案:

答案 0 :(得分:0)

以下是此问题的一般解决方案。您可以编写一个内核模块,它将覆盖现有的中断处理例程,并将被您自己的例程替换,您可以在其中处理您感兴趣的irq并将所有irq重定向到现有的内核中断处理例程。对于x86 arch,您可以获得低级CPU指令,以获取中断描述例程的现有地址(lidt)。我相信它也应该可以用于ARM。现在,Linux具有CPU隔离技术isolcpus,通过利用这种技术,您可以将CPU从调度程序域中取出,即在该特定CPU上不会调度任务,直到您指定要在该特定CPU上运行的任务(使用taskset)。将CPU从调度程序域中取出后,可以通过/proc/irq/IRQ_NUMBER/smp_affinity的隔离CPU来获取对中断的仿射技术的帮助。现在,所有的中断都将由这个隔离的CPU处理,并且100%专用于该中断。使用您自己的IRQ例程,您可以完全控制中断处理。

希望这会有所帮助!

答案 1 :(得分:0)

您是否考虑过使用FIQ。我们有一篇关于它的博客文章: http://free-electrons.com/blog/fiq-handlers-in-the-arm-linux-kernel/