This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

关于读取寄存器时间过长导致硬实时Linux中断响应时间极差的问题



关于读取寄存器时间过长导致硬实时Linux中断响应时间极差的问题

 

  1. 问题描述

在调试硬实时Linux系统时发现,小概率情况下读取寄存器GPMC_IRQSTATUS所花时间非常长,需要180us左右才能读取完毕,导致硬实时Linux的中断响应时间变为极差(系统要求小于5us,其它情况下都满足)。而正常时间是纳秒级的。下面有评估板配置说明,正常与不正常时的示波器波形,以及对应的代码。

  1. 评估板配置说明

CPU :AM3358BZCZA100

NAND FLASH: MT29F4G08ABADA

DDR:镁光D9PSH

操作系统:linux-3.2.0

文件系统:UBIFS

  1. 出问题的代码

在arch\arm\mach-omap2\gpmc.c文件中。蓝色代码为怀疑出问题的代码。

int gpmc_read_status(int cmd)

{

int    status = -EINVAL;

u32  regval = 0;

          

extern void my_gpio1_low(void);

extern void my_gpio1_high(void);

extern void my_gpio2_low(void);

extern void my_gpio2_high(void);

extern unsigned long ustimer_get_origin(void);

extern int ustimer_init(void);

extern int omap_get_INTC_THRESHOLD(void);

extern int get_pidx(void);

unsigned long us0,us1;

unsigned long flags;

static int initflag=0;

int  pidx;

#if 0

asm volatile(

"       mrs %0, cpsr    @ arch_local_irq_save\n"

"       cpsid         i"

: "=r" (flags) : : "memory", "cc");

#else

if(!initflag)

{

           ustimer_init();

           initflag =1;

}

//关中断

asm volatile(

"       cpsid i              @ arch_local_irq_disable"

:

:

: "memory", "cc");

 

#endif

          

           //my_gpio1_low();

          

          

 

switch (cmd) {

case GPMC_GET_IRQ_STATUS:

           us0=ustimer_get_origin();

           my_gpio2_high();//置管脚高电平

           status = gpmc_read_reg(GPMC_IRQSTATUS);

           my_gpio2_low();//置管脚低电平

           us1=ustimer_get_origin();

 

                            if((us1-us0)*4/3 > 100)

           {

                    asm volatile(

           "       mrs  %0, cpsr   @ local_save_flags"

           : "=r" (flags) : : "memory", "cc");

                    pidx=get_pidx();

                    dump_stack();

printk("[cmd=%x, %d, %d]=%x   %d\r\n", cmd, (us1-us0)*4/3 , omap_get_INTC_THRESHOLD(), flags, pidx);

           }       

           break;

 

case GPMC_PREFETCH_FIFO_CNT:

           regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);

           status = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);

           break;

 

case GPMC_PREFETCH_COUNT:

           regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);

           status = GPMC_PREFETCH_STATUS_COUNT(regval);

           break;

 

case GPMC_STATUS_BUFFER:

           regval = gpmc_read_reg(GPMC_STATUS);

           /* 1 : buffer is available to write */

           status = regval & GPMC_STATUS_BUFF_EMPTY;

           break;

 

default:

           printk(KERN_ERR "gpmc_read_status: Not supported\n");

}

           {

 

          

           //my_gpio1_high();

          

           #if 0

                    asm volatile(

"       msr cpsr_c, %0         @ local_irq_restore"

:

: "r" (flags)

: "memory", "cc"); 

           #else

           //开中断

           asm volatile(

           "       cpsie i                         @ arch_local_irq_enable"

           :

           :

           : "memory", "cc"); 

           #endif

 

 

           }

return status;

}

  1. 正常时的波形

在上面的代码

my_gpio2_high();//置管脚高电平

         status = gpmc_read_reg(GPMC_IRQSTATUS);

         my_gpio2_low();//置管脚低电平

中, 执行此代码之前已经关闭ARM中断。它们的波形如下(所花时间大概240ns):

 

 

  1. 异常时的波形

 

在上面的代码

my_gpio2_high();//置管脚高电平

         status = gpmc_read_reg(GPMC_IRQSTATUS);

         my_gpio2_low();//置管脚低电平

中, 执行此代码之前已经关闭ARM中断。它们的波形如下(所花时间大概180us):

 

 

 

 

 

6.如何重现此问题

  当在命令行中不断输入cat /proc/interrupts(或其它命令)并按回车,当重复到一定次数时,会出现读取寄存器GPMC_IRQSTATUS所花时间过长的现象(大概180us)。出问题时的堆栈信息如下:

[ 2721.118652] Backtrace:

[ 2721.121246] [<c0017f24>] (dump_backtrace+0x0/0x10c) from [<c04a5a80>] (dump_stack+0x18/0x1c)

[ 2721.130096]  r6:0000038b r5:00000220 r4:00000000 r3:df3f1d00

[ 2721.136047] [<c04a5a68>] (dump_stack+0x0/0x1c) from [<c002149c>] (gpmc_read_status+0xe4/0x144)

[ 2721.145080] [<c00213b8>] (gpmc_read_status+0x0/0x144) from [<c02a8704>] (omap_dev_ready+0x18/0x7c)

[ 2721.154449]  r8:c09711c8 r7:0003b1c1 r6:c06bcd88 r5:df259810 r4:df259810

[ 2721.161499] [<c02a86ec>] (omap_dev_ready+0x0/0x7c) from [<c02a2ad8>] (nand_wait+0xc0/0x150)

[ 2721.170227]  r4:df259a28 r3:c02a86ec

[ 2721.173980] [<c02a2a18>] (nand_wait+0x0/0x150) from [<c02a1f58>] (nand_write_page+0x78/0xc0)

[ 2721.182800]  r8:00006c46 r7:df437000 r6:00000000 r5:df259810 r4:df259a28

[ 2721.189666] r3:c02a2a18

[ 2721.192413] [<c02a1ee0>] (nand_write_page+0x0/0xc0) from [<c02a2634>] (nand_do_write_ops+0x1e4/0x3a8)

[ 2721.202056]  r8:00006c46 r7:df259810 r6:df259a28 r5:00000800 r4:00000800

[ 2721.209106] [<c02a2450>] (nand_do_write_ops+0x0/0x3a8) from [<c02a3a10>] (nand_write+0x7c/0xa8)

[ 2721.218200] [<c02a3994>] (nand_write+0x0/0xa8) from [<c029789c>] (part_write+0x68/0x90)

[ 2721.226593] [<c0297834>] (part_write+0x0/0x90) from [<c02b6a98>] (ubi_io_write+0x64/0xc0)

[ 2721.235137]  r7:00003000 r6:00000800 r5:00000000 r4:00000175

[ 2721.241088] [<c02b6a34>] (ubi_io_write+0x0/0xc0) from [<c02b536c>] (ubi_eba_write_leb+0x74/0x68c)

[ 2721.250366]  r8:df2e1000 r7:00000000 r6:df259000 r5:000001a2 r4:00000175

[ 2721.257415] [<c02b52f8>] (ubi_eba_write_leb+0x0/0x68c) from [<c02b45f4>] (ubi_leb_write+0xe8/0x104)

[ 2721.266876] [<c02b450c>] (ubi_leb_write+0x0/0x104) from [<c01a6b6c>] (ubifs_leb_write+0x40/0xa4)

[ 2721.276092]  r7:000001a2 r6:00002000 r5:df3f6000 r4:df3f6000

[ 2721.282012] [<c01a6b2c>] (ubifs_leb_write+0x0/0xa4) from [<c01a7228>] (ubifs_wbuf_sync_nolock+0x74/0x130)

[ 2721.292022]  r7:000006f8 r6:00000800 r5:df3f6000 r4:df3f7d30

[ 2721.297973] [<c01a71b4>] (ubifs_wbuf_sync_nolock+0x0/0x130) from [<c01a745c>] (ubifs_bg_wbufs_sync+0x104/0x154)

[ 2721.308532]  r7:df3f7d30 r6:00000002 r5:00000130 r4:df3f6000

[ 2721.314483] [<c01a7358>] (ubifs_bg_wbufs_sync+0x0/0x154) from [<c01aeafc>] (ubifs_bg_thread+0x9c/0x118)

[ 2721.324310] [<c01aea60>] (ubifs_bg_thread+0x0/0x118) from [<c0056014>] (kthread+0x8c/0x94)

[ 2721.332977] [<c0055f88>] (kthread+0x0/0x94) from [<c004087c>] (do_exit+0x0/0x65c)

[ 2721.340789]  r6:c004087c r5:c0055f88 r4:df02dd84

 

 

  • 你是在RT Linux上才测出这个问题么?普通Linux有这个问题么?

  • 我们的Linux(普通Linux修改而来)跟RT Linux类似,支持硬实时(小于5微秒),但是更简单,只支持中断级别的实时响应。在我们的测试环境中,运行一个100微秒的定时器(中断优先级最高),在定时中断中翻转IO管脚,发现大多数情况是很准的,偶尔会犹豫出现大偏差。根据我们的跟踪,问题就是出现在读取寄存器GPMC_IRQSTATUS过长导致。至今还没有查出读取寄存器GPMC_IRQSTATUS过长的原因。不知有什么方法可以解决这个问题?谢谢!

  • 除了读取寄存器GPMC_IRQSTATUS过长,有尝试读取其他寄存器吗? 情况是否一样?

    Nand flash的clock是多少?

  •     读取其它寄存器暂时没有发现读取时间过长的问题。另外读取寄存器GPMC_IRQSTATUS,是有时候会过长(在写nandflash的时候),不是总是很长。你说的Nand flash的clock,不是很明白是什么意思?Nand flash没有与clock相关的管脚。