郁闷的串口中断 nobody cared

这几天碰到一个很奇怪的问题, kernel 启动的时候,会碰到 抱怨 irq 19: nobody cared. 这个中断是串口中断. 而且我确认串口是可以work的. 因为在 early console->console 已经成功了. 

经过一番搜索, 发现把kernel_init 函数中的 

/* Open the /dev/console on the rootfs, this should never fail */ 
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) 
printk(KERN_WARNING "Warning: unable to open an initial console.\n"); 
注释掉就可以ok. 看来问题是 在 sys_open((const char __user *) "/dev/console" 中. 

我的问题是: 到这里的时候, rootfs 还没有被 mount上(我的rootfs是放在USB上面的),我加了一些log,发现在 打开/dev/console后才会 去mount USB的rootfs. 那么这个时候去open /dev/console, 一定会失败了. 但是 注释说 , this should never fail. 是不是在mount rootfs之前,kernel 会创建这个设备? 在那里创建的? 


NET: Registered protocol family 17 
NET: Registered protocol family 15 
Registering platform devices 
irq 19: nobody cared (try booting with the "irqpoll" option) 
Call Trace: 
[<ffffffff80211150>] dump_stack+0x8/0x34 
[<ffffffff80299ec4>] __report_bad_irq+0x44/0xe8 
[<ffffffff8029a0f0>] note_interrupt+0x188/0x250 
[<ffffffff8029aa7c>] handle_percpu_irq+0xb4/0xe0 
[<ffffffff80216fd4>] do_IRQ+0x2c/0x40 
[<ffffffff80200400>] ret_from_irq+0x0/0x4 
[<ffffffff80244430>] __do_softirq+0x98/0x270 
[<ffffffff802446a8>] do_softirq+0xa0/0xc8 
[<ffffffff80244784>] irq_exit+0xb4/0xd8 
[<ffffffff80200400>] ret_from_irq+0x0/0x4 
[<ffffffff80299028>] __setup_irq+0x1f8/0x440 
[<ffffffff80299394>] request_threaded_irq+0x124/0x188 
[<ffffffff804a0fac>] serial8250_startup+0xb6c/0xca8 
[<ffffffff804982ec>] uart_startup+0x74/0x290 
[<ffffffff8049b0a0>] uart_open+0x190/0x648 
[<ffffffff8046f388>] tty_open+0x288/0x850 
[<ffffffff802e7f14>] chrdev_open+0x1e4/0x370 
[<ffffffff802e02e0>] __dentry_open+0xf0/0x348 
[<ffffffff802f5578>] do_last+0x720/0xa10 
[<ffffffff802f5a58>] do_filp_open+0x1f0/0x670 
[<ffffffff802e1d4c>] do_sys_open+0x9c/0x1d8 
[<ffffffff80854228>] kernel_init+0x130/0x1b4 
[<ffffffff802178f8>] kernel_thread_helper+0x10/0x18 

handlers: 
[<ffffffff8049f918>] (serial8250_interrupt+0x0/0x188) 
Disabling IRQ #19 
irq 19: nobody cared (try booting with the "irqpoll" option) 
Call Trace: 
[<ffffffff80211150>] dump_stack+0x8/0x34 
[<ffffffff80299ec4>] __report_bad_irq+0x44/0xe8 
[<ffffffff8029a0f0>] note_interrupt+0x188/0x250 
[<ffffffff8029aa7c>] handle_percpu_irq+0xb4/0xe0 
[<ffffffff80216fd4>] do_IRQ+0x2c/0x40 
[<ffffffff80200400>] ret_from_irq+0x0/0x4 
[<ffffffff80244430>] __do_softirq+0x98/0x270 
[<ffffffff802446a8>] do_softirq+0xa0/0xc8 
[<ffffffff80244784>] irq_exit+0xb4/0xd8 
[<ffffffff80200400>] ret_from_irq+0x0/0x4 
[<ffffffff80299028>] __setup_irq+0x1f8/0x440 
[<ffffffff80299394>] request_threaded_irq+0x124/0x188 
[<ffffffff804a0fac>] serial8250_startup+0xb6c/0xca8 
[<ffffffff804982ec>] uart_startup+0x74/0x290 
[<ffffffff8049b0a0>] uart_open+0x190/0x648 
[<ffffffff8046f388>] tty_open+0x288/0x850 
[<ffffffff802e7f14>] chrdev_open+0x1e4/0x370 
[<ffffffff802e02e0>] __dentry_open+0xf0/0x348 
[<ffffffff802f5578>] do_last+0x720/0xa10 
[<ffffffff802f5a58>] do_filp_open+0x1f0/0x670 
[<ffffffff802e1d4c>] do_sys_open+0x9c/0x1d8 
[<ffffffff80854228>] kernel_init+0x130/0x1b4 
[<ffffffff802178f8>] kernel_thread_helper+0x10/0x18 

 

grep了一把, 发现是在 drivers/char/tty_io.c 中 创建 /dev/console. 

那为什么会open的时候有问题呢? 继续debug 

3128 static int __init tty_init(void) 
3129 { 
3130 cdev_init(&tty_cdev, &tty_fops); 
3131 if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || 
3132 register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) 
3133 panic("Couldn't register /dev/tty driver\n"); 
3134 device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, 
3135 "tty"); 
3136 
3137 cdev_init(&console_cdev, &console_fops); 
3138 if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || 
3139 register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) 
3140 panic("Couldn't register /dev/console driver\n"); 
3141 device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, 
3142 "console"); 


http://lists.openwall.net/linux-kernel/2010/03/03/197 

这段代码看来是 3/3 kernel中刚改过的. 原来 打开 /dev/console 是在 init_post 中做的. 

感觉你遇到的问题,跟我的类似阿。 
我也不知道,什么时候,谁在/dev下创建的设备。 

其实谁创建的,我知道,是udev线程创建的。关键谁让udev创建的? 
LVM,块设备,设计到很多东西。 

这个问题 今天解决了。 

现在看一下表面现象: 表面现象是 irq 19没有人 care。 那么我们的第一反应是:irq 19的中断处理函数没有注册。 
但是从kernel给出的信息又说明它找到了handlers: 
[<ffffffff8049f918>] (serial8250_interrupt+0x0/0x188) 
因此,没有注册irq 19的中断处理程序的推理不成立。 

那么继续想一下,kernel是如何判断这个irq没有人care呢? 具体的代码在note_interrupt 里面。kernel 会记录某一个irq没有被处理的次数。如果在某一段时间里面这个irq没有被处理达到一个大的阀值,kernel 就认为这个irq没有人care。 因此,实际上,这个错误信息是: irq 19 在很长的时间里面没有人处理。 

那再回到具体的平台中。平台的IRQ 19是UART,这个中断是连接到MIPS CPU的IP3。熟悉MIPS的同学都知道,中断由 MIPS CPU的中断处理程序再根据具体的中断引脚 调用具体的doIRQ。 比如,在MIPS 中断处理中,如果发现IP3被 set,就会调用 IRQ(19)。当然不同的平台中断的路由不一样,但是大体的思路是一样的。 

跟踪代码,发现代码进入了MIPS的中断处理函数,也确实判断了IP3被set,然后也调用了 doIRQ(19)。但是,为什么kernel 认为这个中断没有人处理呢? 实际上,代码也进了 serial8250_interrupt。 这个函数会读 串口的IIR寄存器,这个寄存器反应了串口的中断状态,读出来的值是 0x1,也就是 NO INTERRUPT PENDING. 因此,会认为当前没有串口发生,跳出中断处理函数。 从而导致kernel 认为该中断没有处理。 

那么就有个问题。 刚才说 串口中断是接到CPU 的IP3上面。先是cpu认为IP3被set,然后才调用串口中断处理程序。 如果没有串口中断,为什么CPU的IP3会被set,从而MIPS CPU认为当前有中断发生呢?这个是核心所在。 查了一些设定发现,对于龙芯的北桥设定有问题,导致 MIPS CPU的 IP2和IP3一直被set,也就是一直认为有中断发生。 由于在 sys_open((const char __user *) "/dev/console", O_RDWR, 0) 前,串口并没有使用中断因此没有问题。 但是一旦 串口采用中断了以后,立刻问题就出现了。 重新设置了龙芯的北桥后,问题解决。 

两个结论: 
(1) 要抓住问题的核心。有点时候kernel的错误信息有一些误导。 
(2) 串口只有在进入user land前才使用中断。 

结贴。 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值