关于读取寄存器时间过长导致硬实时Linux中断响应时间极差的问题
问题描述
在调试硬实时Linux系统时发现,小概率情况下读取寄存器GPMC_IRQSTATUS所花时间非常长,需要180us左右才能读取完毕,导致硬实时Linux的中断响应时间变为极差(系统要求小于5us,其它情况下都满足)。而正常时间是纳秒级的。下面有评估板配置说明,正常与不正常时的示波器波形,以及对应的代码。
评估板配置说明
CPU :AM3358BZCZA100
NAND FLASH: MT29F4G08ABADA
DDR:镁光D9PSH
操作系统:linux-3.2.0
文件系统:UBIFS
出问题的代码
在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;
}
正常时的波形
在上面的代码
my_gpio2_high();//置管脚高电平
status = gpmc_read_reg(GPMC_IRQSTATUS);
my_gpio2_low();//置管脚低电平
中, 执行此代码之前已经关闭ARM中断。它们的波形如下(所花时间大概240ns):
异常时的波形
在上面的代码
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] [] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c)
[ 2721.130096] r6:0000038b r5:00000220 r4:00000000 r3:df3f1d00
[ 2721.136047] [] (dump_stack+0x0/0x1c) from [] (gpmc_read_status+0xe4/0x144)
[ 2721.145080] [] (gpmc_read_status+0x0/0x144) from [] (omap_dev_ready+0x18/0x7c)
[ 2721.154449] r8:c09711c8 r7:0003b1c1 r6:c06bcd88 r5:df259810 r4:df259810
[ 2721.161499] [] (omap_dev_ready+0x0/0x7c) from [] (nand_wait+0xc0/0x150)
[ 2721.170227] r4:df259a28 r3:c02a86ec
[ 2721.173980] [] (nand_wait+0x0/0x150) from [] (nand_write_page+0x78/0xc0)
[ 2721.182800] r8:00006c46 r7:df437000 r6:00000000 r5:df259810 r4:df259a28
[ 2721.189666] r3:c02a2a18
[ 2721.192413] [] (nand_write_page+0x0/0xc0) from [] (nand_do_write_ops+0x1e4/0x3a8)
[ 2721.202056] r8:00006c46 r7:df259810 r6:df259a28 r5:00000800 r4:00000800
[ 2721.209106] [] (nand_do_write_ops+0x0/0x3a8) from [] (nand_write+0x7c/0xa8)
[ 2721.218200] [] (nand_write+0x0/0xa8) from [] (part_write+0x68/0x90)
[ 2721.226593] [] (part_write+0x0/0x90) from [] (ubi_io_write+0x64/0xc0)
[ 2721.235137] r7:00003000 r6:00000800 r5:00000000 r4:00000175
[ 2721.241088] [] (ubi_io_write+0x0/0xc0) from [] (ubi_eba_write_leb+0x74/0x68c)
[ 2721.250366] r8:df2e1000 r7:00000000 r6:df259000 r5:000001a2 r4:00000175
[ 2721.257415] [] (ubi_eba_write_leb+0x0/0x68c) from [] (ubi_leb_write+0xe8/0x104)
[ 2721.266876] [] (ubi_leb_write+0x0/0x104) from [] (ubifs_leb_write+0x40/0xa4)
[ 2721.276092] r7:000001a2 r6:00002000 r5:df3f6000 r4:df3f6000
[ 2721.282012] [] (ubifs_leb_write+0x0/0xa4) from [] (ubifs_wbuf_sync_nolock+0x74/0x130)
[ 2721.292022] r7:000006f8 r6:00000800 r5:df3f6000 r4:df3f7d30
[ 2721.297973] [] (ubifs_wbuf_sync_nolock+0x0/0x130) from [] (ubifs_bg_wbufs_sync+0x104/0x154)
[ 2721.308532] r7:df3f7d30 r6:00000002 r5:00000130 r4:df3f6000
[ 2721.314483] [] (ubifs_bg_wbufs_sync+0x0/0x154) from [] (ubifs_bg_thread+0x9c/0x118)
[ 2721.324310] [] (ubifs_bg_thread+0x0/0x118) from [] (kthread+0x8c/0x94)
[ 2721.332977] [] (kthread+0x0/0x94) from [] (do_exit+0x0/0x65c)
[ 2721.340789] r6:c004087c r5:c0055f88 r4:df02dd84