一种Linux下共享中断的处理方法

前段时间调试一款芯片的时候,碰到一个奇怪的问题:只要在板卡上插入一个PS2键盘,启动内核时系统就可能会进入串口中断函数去执行,过一会系统就panic不往下继续执行。后来经过分析出现问题时的panic的堆栈,借助EJTAG工具,读到这个时候的串口的中断状态位,竟然发现串口并没有真正产生中断。那么,串口本身没有中断,内核怎么又会跑到串口的中断服务函数去执行呢?

我们知道Linux的中断可以分为I/O 中断 、时钟中断和处理器核间中断。其中I/O中断是Linux 系统响应外部IO事件的重要方式。尽管不同的平台和体系结构实现的方法不一样,但是都支持不同的设备共享同一个中断向量 。例如在PCI的总线结构中,几个设备可以共享同一个IRQ线,也即它们共享一个中断号,各自的中断服务例程挂在这个中断号上。当CPU响应这个IRQ时,会逐一检查挂在这个中断向量上的例程,并且执行那些真正有中断的例程。但是串口明显不属于PCI,不可能用到PCI的中断线和中断引脚寄存器,那又是什么原因导致kernel panic呢?

带着上面的这些问题,和硬件工程师和芯片设计的同事深入讨论了各种可能性,最后结合芯片板卡原理图,发现这个板子上的低速设备都集成在芯片内部,这些低速设备包括串口、LPC只是控制器、SPI控制、I2C控制器、NAND控制器等,其中CPU UART和LPC的中断信号都路由到同一个CPU的中断引脚。 具体的连接图如下所显:

通过上图最左侧的部分可以看到,CPU UART和CPU LPC控制器的中断请求信号经过逻辑或后,输出到了CPU 芯片内Interrupt Pending Bit2。一旦CPU检测到任何一个Interrupt Pending位被设置起来,它就会根据约定的顺序逐一查询各个Interrupt Pending Bit,并且执行中断路由到这个bit上的设备驱动的中断服务例程。

在老版本的板卡设计中,CPU LPC上没有接任何设备,当时没有碰到前面提到的问题。后来,由于客户的需求,板卡上CPU LPC端口上可以连接PS2 键盘和鼠标,问题也随之暴露。因此,我猜测问题的根源是由于没有对共享IP2的连接到LPC上的设备的中断进行处理。按照这一思路,检查了之前的中断分发处理函数,发现果然在处理IP2时,只调用了do_irq(58)。参考内核中串口驱动的代码可以知道,第一个CPU UART的中断号默认是58。因此在这种情况下一旦接入的PS2键盘或鼠标发出中断信号,现有的代码就会不分青红皂白地去执行do_irq(58)。显然,这不是期望的行为,需要查询各自的中断状态位来检测到底该响应那个设备的中断。在最新的Linux 4.2内核主干分支里,我们仍然可以找到这部分有待完善的代码:arch/mips/loongson64/loongson-3/irq.c:

void mach_irq_dispatch(unsigned int pending)

{

if (pending & CAUSEF_IP7)

do_IRQ(LOONGSON_TIMER_IRQ);

#if defined(CONFIG_SMP)

else if (pending & CAUSEF_IP6)

loongson3_ipi_interrupt(NULL);

#endif

else if (pending & CAUSEF_IP3)

ht_irqdispatch();

else if (pending & CAUSEF_IP2)

do_IRQ(LOONGSON_UART_IRQ);

else {

pr_err("%s : spurious interrupt\n", __func__);

spurious_interrupt();

}

}

另外,该芯片中LPC上的中断信号是电平触发,根据LPC配置寄存器的定义,当中断完成之后,需要清除LPC SIRQ,这就需要添加响应的中断ack和eoi等函数。与此相反的是,兼容NS16550A的串口上的中断是边沿触发,不需要程序去清除:当传输保存寄存器为空时,串口的ISR的bit 1会被设置起来,一旦写数据到传输保存寄存器,这个bit就会被清掉;当接收FIFO中字符的个数达到trigger的水平时,ISR的bit 2会被设置起来,直到程序读接收FIFO。

根据上面的两点思路,修改了响应的代码,重新编译内核,重新做了大量测试,没有再复现前文提到的问题。通过这个例子,我们可以看到:除了PCI中断这种共享中断向量的机制之外,还有不同物理设备的中断信号路由到同一个中断引脚但使用不同中断号的情况。针对这种情况。工程师需要综合芯片结构、硬件连接、中断路由及内核中断处理流程,全面考虑各种情况,给出完善、健壮的解决方案。但比较这两者的异同之后,不难发现其实本质还是一样的:不管中断号是否一样,任何路由到CPU内部中断或者外部中断控制器上的设备,都应享用被服务的机会,不能遗漏。

时间: 2024-09-27 01:03:08

一种Linux下共享中断的处理方法的相关文章

在Linux下的中断方式读取按键驱动程序

// 在Linux下的中断方式读取按键驱动程序 //包含外部中断 休眠 加入poll机制 // 采用异步通知的方式 // 驱动程序发 ---> app接收 (通过kill_fasync()发送) // 为了使设备支持异步通知机制,驱动程序中涉及以下3项工作: // 1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID. // 不过此项工作已由内核完成,设备驱动无须处理. // 2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序

让你提前认识软件开发(51):VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改

第3部分 软件研发工作总结 VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改 [文章摘要] Pclint是一种C/C++软件代码静态分析工具.它是一种更加严格的编译器,能够发现普通编译器所不能发现的代码中的很多问题,因此被广泛应用于软件开发项目中. 本文介绍了如何在VC++集成开发环境中配置Linux下的Pclint工程,给出了C语言中pclint规则A检查的常见错误,并描述了对应的修改办法. [关键词] VC++  Pclint  配置  操作  修改 1. 前言 P

linux下repair filesystem模式修复方法

第一种情况:非正常关机引起的磁盘分区问题 不能正常进入系统 如下问题一般是如何引起和应该怎么样解决呢?Finding module dependencies;modprobe:modprobe:can't locate module block-major-3fsck.ext3Possibly non-existent or swap device?such device or address while trying to open /dev/hdb1/boot: clena, 41/2610

Linux下Git和GitHub使用方法总结 (码云)

初学先记住这几条,其他慢慢研究. 下面讲如何用码云完成一个项目的提交, 我的步骤 https://git.oschina.net/phpervip/qianzhu(此例:一个企业模板): 先在码云上注册一个帐号. 然后新建项目,就有一个git地址. 本地进入你的项目目录. 初始化项目->建远程连接->获取项目->添加版本->版本提交->远程提交 git init git remote add origin https://git.oschina.net/phpervip/qi

Linux下Git和GitHub使用方法总结

来源:Linux下Git和GitHub使用方法总结 1 Linux下Git和GitHub环境的搭建 第一步: 安装Git,使用命令 “sudo apt-get install git” 第二步: 到GitHub上创建GitHub帐号 第三步: 生成ssh key,使用命令 “ssh-keygen -t rsa -C "[email protected]"”,your_email是你的email 第四步: 回到github,进入Account Settings,左边选择SSH Keys,

linux下恢复误删除的文件方法(ext2及ext3)

linux下恢复误删除的文件方法(ext2及ext3) 2009-12-19 15:23:47 分类: LINUX 如果是ext2文件系统的,直接用debugfs是可以恢复出来的,但对于ext3,debugfs就无能为力了,好在我们有了ext3grep这个开源工具(http://code.google.com/p/ext3grep/)! 对于ext2 1.在/data(/dev/sdb)上创建并删除测试文件(作测试目的以plantodelete为例) #vi plantodelete 输入Thi

Linux下清理内存和Cache方法

Linux下清理内存和Cache方法 /proc/sys/vm/drop_caches 频繁的文件访问会导致系统的Cache使用量大增 $ free -m total used free shared buffers cached Mem: 3955 3926 28 0 55 3459 -/+ buffers/cache: 411 3544 Swap: 5726 0 5726 free内存减少到几十兆,系统运行缓慢 运行sync将dirty的内容写回硬盘 $sync 通过修改proc系统的dro

linux下重新定位svn url方法

linux下重新定位svn url方法: 如果更换了SVN服务器,就需要重新定位,指向新的svn url. 重新定位命令:svn switch --relocate 原svn地址 新svn地址. 查看原svn路径方法:svn info linux下重新定位svn url方法

Linux下tail命令的使用方法

Linux下tail命令的使用方法.linux tail命令用途是依照要求将指定的文件的最后部分输出到标准设备,通常是终端,通俗讲来,就是把某个档案文件的最后几行显示到终端上,假设该档案有更新,tail会自己主动刷新,确保你看到最新的档案内容.一.tail命令语法tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]参数解释:-f 该参数用于监视File文件增长.-c Number 从