Linux kernel 使用RT补丁的linux内核上的中断性能应该更好吗?

Linux kernel 使用RT补丁的linux内核上的中断性能应该更好吗?,linux-kernel,arm,linux-device-driver,interrupt,Linux Kernel,Arm,Linux Device Driver,Interrupt,在运行linux内核(3.8.13)的Freescales imx.233上,我遇到了一点不一致的IRQ/ISR性能,并使用了CONFIG\u PREEMPT\u RT补丁。 我有点惊讶为什么这个处理器(ARM9,454mhz)连74kHz的IRQ请求都跟不上 在我的内核配置中,我设置了以下标志: CONFIG_TINY_PREEMPT_RCU=y CONFIG_PREEMPT_RCU=y CONFIG_PREEMPT=y CONFIG_PREEMPT_RT_BASE=y CONFIG_HAVE

在运行linux内核(3.8.13)的Freescales imx.233上,我遇到了一点不一致的IRQ/ISR性能,并使用了CONFIG\u PREEMPT\u RT补丁。 我有点惊讶为什么这个处理器(ARM9,454mhz)连74kHz的IRQ请求都跟不上

在我的内核配置中,我设置了以下标志:

CONFIG_TINY_PREEMPT_RCU=y
CONFIG_PREEMPT_RCU=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_RT_BASE=y
CONFIG_HAVE_PREEMPT_LAZY=y
CONFIG_PREEMPT_LAZY=y
CONFIG_PREEMPT_RT_FULL=y
CONFIG_PREEMPT_COUNT=y
CONFIG_DEBUG_PREEMPT=y
在系统上,基本上没有任何运行(由buildroot创建),我将PWM设置为生成74kHz的脉冲,作为中断。 然后在ISR中,我只需触发另一个GPIO输出引脚,并检查输出。 我发现有时候我会错过一个中断- 您可以在此处看到错过的中断:

而且输出引脚的触发似乎有点不一致,输出引脚通常在“5%窗口”内触发,这可能仍然是可以接受的。但我担心,当我开始实现数据传输逻辑,而不是仅仅触发pin时,我可能会遇到进一步的问题

我的简单驱动程序代码如下所示:

#needed includes

uint16_t INPUT_IRQ = 39;
uint16_t OUTPUT_GPIO = 38;

struct test_device *device;

//Prototypes
void irqtest_exit(void);
int irqtest_init(void);
void free_device(void);

//Default functions
module_init(irqtest_init);
module_exit(irqtest_exit);

//triggering flag
uint16_t pulse = 0x1;

irqreturn_t irq_handle_function(int irq, void *device_id)
{
pulse = !pulse;
gpio_set_value(OUTPUT_GPIO, pulse);

return IRQ_HANDLED;
}

struct test_device { 
    int huuhaa;
};

void free_device() {
if (device)
    kfree(device);
}   

int irqtest_init(void) {
    int result = 0;

    device = kmalloc(sizeof *device, GFP_KERNEL);
    device->huuhaa = 10;

    printk("IRB/irqtest_init: Inserting IRQ module\n"); 

    printk("IRB/irqtest_init: Requesting GPIO (%d)\n", INPUT_IRQ); 
    result = gpio_request_one(INPUT_IRQ, GPIOF_IN, "PWM input");

    if (result != 0) {
        free_device();
        printk("IRB/irqtest_init: Failed to set GPIO (%d) as input.. exiting\n", INPUT_IRQ);
        return -EINVAL;
    } 
    result = gpio_request_one(OUTPUT_GPIO, GPIOF_OUT_INIT_LOW , "IR OUTPUT");
    if (result != 0) {
        free_device();
        printk("IRB/irqtest_init: Failed to set GPIO (%d) as output.. exiting\n", OUTPUT_GPIO);
        return -EINVAL;
    } 

    //Set our desired interrupt line as input
    result = gpio_direction_input(INPUT_IRQ);

    if (result != 0) {
        printk("IRB/irqtest_init: Failed to set IRQ as input.. exiting\n");
        free_device();
        return -EINVAL;
    }   

    //Set flags for our interrupt, guessing here..
    irq_flags |=  IRQF_NO_THREAD;
    irq_flags |=  IRQF_NOBALANCING;
    irq_flags |=  IRQF_TRIGGER_RISING;
    irq_flags |=  IRQF_NO_SOFTIRQ_CALL;

    //register interrupt
    result = request_irq(gpio_to_irq(INPUT_IRQ), irq_handle_function, irq_flags, "irq testing", device);

    if (result != 0) {
        printk("IRB/irqtest_init: Failed to reserve GPIO 38\n");
        return -EINVAL;
    } 
    printk("IRB/irqtest_init: insert success\n"); 
    return 0;
}

void irqtest_exit(void) {
    if (device)
        kfree(device);
    gpio_free(INPUT_IRQ);
    gpio_free(OUTPUT_GPIO);

    printk("IRB/irqtest_exit: Removing irqtest module\n");
}


int irqtest_open(struct inode *inode, struct file *filp) {return 0;}
int irqtest_release(struct inode *inode, struct file *filp) {return 0;}
在系统中,在加载驱动程序后,我注册了以下中断:

# cat /proc/interrupts 
       CPU0       
 16:      36379         -  MXS Timer Tick
 17:          0         -  mxs-spi
 18:       2103         -  mxs-dma
 60:          0  gpio-mxs  irq testing
118:          0         -  mxs-spi
119:          0         -  mxs-dma
120:          0         -  RTC alarm
124:          0         -  8006c000.serial
127:      68050         -  uart-pl011
128:        151         -  ci13xxx_imx
Err:          0
我想知道我向IRQ申报的旗帜是否好?我注意到,使用这种配置,我无法再访问控制台,所以内核现在似乎完全被服务这个74kHz触发器消耗掉了。。这不可能是对的? 我想这对我来说没什么大不了的,因为这只是在数据传输期间,但我仍然觉得我做错了什么

另外,我想知道用ioremap映射寄存器,并用直接内存写入触发输出是否更有效

有什么方法可以提高中断的优先级吗?或者我可以在数据传输期间(约400ms)锁定内核,并以其他方式为输出生成计时


编辑:忘记在问题中添加/proc/interrupts输出…

您可以看看我的同事Maxime Ripard在类似SoC(i.mx28)上使用FIQ做了什么:

尝试以下标志:

int irq_flags;
...
irq_flags = IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME
我有一个内核3.8.11,找不到IRQF\u NO\u SOFTIRQ\u调用define。只有3.8.13节?
我也没有看到irq_标志定义。它在哪里?

您在这里体验到的是中断抖动。这在Linux上是意料之中的,因为内核会定期禁用各种任务的中断(输入自旋锁、处理中断等)

这将发生,无论您是否有抢占,所以期望通过常规中断生成74kHz信号是非常不现实的

现在,ARM具有更高优先级的中断,称为FIQ,它永远不会被屏蔽或禁用

Linux不使用FIQ,也不是为了处理FIQ可以使用的事实而构建的,因此您将无法使用通用内核框架

然而,从Linux驱动程序开发的角度来看,只要记住这一点,就没有什么不同:您必须编写一个处理程序,并将其与IRQ关联。您还必须插入中断控制器,使其为您想要使用的中断生成FIQ(关于如何更改它的详细信息取决于平台。一些平台有这样做的功能(如imx25和mxc_set_irq_FIQ),而另一些平台没有。imx23/28没有,因此您必须手动操作)

设置fiq处理程序的函数只能与程序集编写的处理程序一起工作,因此您必须在程序集中重写处理程序(使用当前代码,这应该很简单)


您可以在Alexandre posted()的博客文章中获取更多详细信息,在那里您可以找到关于如何将所有内容结合在一起的工作代码、示例和解释。

请参阅,因为这可能会引起您的兴趣。@artlessnoise感谢您的回复。这看起来确实很有趣,但我似乎无法导入这个mxc_集_irq_fiq。。(尽管我导入了asoc imx ssi.h,但编译器警告它mxc_set_irq_fiq未定义),模块无法加载。。你提到的另一个问题,他似乎也使用直接寄存器写入,也许我也应该避免使用通用GPIO库..这些符号在中导出。只需声明
extern int mxc_set_irq_fiq(unsigned int irq,unsigned int type)
extern int imx\u irq\u set\u优先级(无符号字符irq,无符号字符优先级)并使用它们。它看起来像是
imx\u irq\u set\u priority()
被公开了,用它来改变你的irq是很容易的。确保在kernel.config中设置MXC_IRQ_previor。我会使用GPIO库,因为其他驱动程序/模块可能会修改管脚。如果你不参加比赛,你可以参加比赛。即,一个驱动程序设置GPIO2-3,另一个正在清除GPIO2-5,另一个正在设置GPIO2-17。如果您知道只有您的驱动程序可以使用该组中的所有活动GPIO,那么您可以直接使用它。@artlessnoise当我将平台从MXS更改为MXC时,我再也无法启动内核(它已挂在u-boot中,试图加载内核,甚至没有显示“解压缩linux”),我想mx23的一些配置出了问题。。我将irqcommon.c和.h从mach-imx复制到mach-mxs,构建,然后我能够针对它编译驱动程序,但调用
mxc\u-set\u-irq\u-fiq(INPUT\u-irq,1)返回-38。。在我注册了IRQAlexandre后,我正在试着给它打电话,谢谢你的链接!有趣的是,当使用正常的IRQ:s时,他在Saleae中的输出是多么相似,我猜他遇到了完全相同的问题!然而,这些linux驱动程序我还是新手,我似乎不明白如何在我的驱动程序中实现这一点。。在本例中,您的同事正在使用用户土地应用程序,对吗?他用汇编语言写代码?有完整的例子吗?我可以自私地请你让他在这里评论这个问题吗?谢谢你的回答。该定义随配置抢占补丁集一起提供。我尝试了建议标志,不幸的是,我得到了与以前相同的结果。。。我想也许是因为某种原因