Linux中断处理驱动设计

来源:互联网 发布:JavaScript this 编辑:程序博客网 时间:2024/05/16 16:19

首先需要明白的是中断是为了充分利用CPU而产生了,为了将CPU从无效的轮询进行释放出来而设计的中断;

中断信号的流向为外设到CPU

中断是对驱动层的一个概念,对应用程序是透明的,一般是应用程序通过系统调用执行到驱动函数,然后驱动函数为了等待IO而休眠了应用进程;

中断一般的设计流程是:在初始化的时候进行探测得到该外设能使用的中断信号线,然后在第一次打开的时候进行注册中断信号,在最后一次不要进行使用的时候进行释放中断

在初始化探测中断阶段有三种方式:一种是类似PCI设备会在寄存器中存放该外设需要使用的中断信号线,在这种情况下直接探测读取外设寄存器即可;一种是使用内核函数;另外一种是DIY探测函数;

内核函数是首先进行为可能的中断号进行注册中断处理函数,然后进行调用probe_irq_on,之后外设进行启用中断报告、清楚中断位、启用中断、关闭中断、最后调用probe_irq_off函数,这主要探测思想是:绑定该中断信号线,如果发送中断能被该外设进行检测到,则说明该外设使用的就是该中断信号线,否则就不是,这个探测的重点是:确定了外设已经分配了中断信号线,但是现在驱动层不知道该外设使用的是那个中断信号线。所以需要通过发生中断然后检测是否是该中断信号线。

DIY中断信号线方式的思想是一致的,但是因为中断信号线不能应用在中断共享的情况下,同时为了更好的发挥对外设的了解,可以自己进行缩小可能的探测范围,因为内核探测函数是探测probe_irq_on返回的未使用中断信号,内核并不知道外设可能使用的中断信号,仅仅使用一种通用的方式来进行探测。故进行自己定义探测函数;

DIY探测主要是将外设比较可能使用的中断号进行注册,然后使用一个标识,判断是否是该中断信号线,然后进行启动中断报告、清中断位、中断申请、关中断,检测标识这个流程。如果检测到标识为正则说明外设就是使用的这个中断信号线。最后进行释放因为探测而注册的中断应用程序

探测得到外设使用的中断信号线,则在第一次open的时候进行注册中断。然后实现中断处理函数

首先是明白X86内核一个中断处理的流程。

1.将中断编号入栈调到一个公共端,调用do_IRQ函数

2.do_IRQ函数首先应答中断,获取一个自旋锁,防止其他CPU处理该中断,然后清楚状态位,寻找该中断号对应的处理函数,(查找中断向量表,得到中断向量)

3.如果没有处理函数,则什么也不做,自旋锁释放,处理软中断完就返回

4.如果有处理函数,则调用处理函数,并进行一些清理工作,接着运行软中断,最后返回到常规工作

这里值得注意的是软中断的执行时刻,是在返回常规工作之前进行执行的。

接着就是中断处理的设计了,因为中断处理函数是在中断上下文进行处理的,所以不能向应用空间进行传递数据、不能休眠、不能通过调用schdule函数放弃CPU

中断处理的职责主要是:将中断接受的信息反馈给设备,即清中断,一般在中断处理函数最后;对外设申请中断的数据进行读写;唤醒等待该外设数据的进程。

因为中断一般是CPU和外设之间数据的传送,所以基本是readwrite涉及中断,具体实现就是:

read操作:在进行读取数据的时候因为数据还没有到来,此时一般的处理则是手动让该进程休眠,使用DEFINE_WAIT定义休眠入口,然后使用prepare_to_wait执行休眠,核对休眠条件不成立调用schdule()放弃CPU实现真正休眠,最后调用finish_wait执行状态的清理。此时该进程休眠了,而数据的填充一般是中断处理函数来读取外设中的数据,然后唤醒该进程的。最后在read操作读取中断处理填充得到的数据copy_to_user到用户空间。这没有完全和中断处理进行一个直接的挂钩,而是体现在进程休眠和唤醒这个过程中。

write操作:对于write操作一般分两种情况,一种是数据量比较小,直接将数据进行写到控制器就行了,无需管中断与否;另外一种就是操作时间比较长,比如需要确保控制器将数据写到存储设备中,当数据进行写到存储设备时控制器通过中断进行告知驱动,此时则需要进行wait_eevent_interrupter函数实现一个标识,在write操作中等待标识为真,然后中断处理函数修改该标识为真;第三种情况就是为了提高系统性能,一般会使用数据缓冲区,write操作将数据写入到缓冲区,然后在中断时间将数据进行彻底的写入到外设中(这个前提是存在当外设准备好接受数据或者对成功的数据传送进行应答时外设会发出中断的前提下,该设备会通过中断的方式来通知系统他们对缓冲区的处理结束。这里看似两次中断,但是一般无需通知系统外设准备接受数据,而是系统直接将数据写到外设,在使用DMA的情况下则会对缓冲区处理结束使用中断通知)。

对于写缓冲的设计,首先是控制对缓冲区的访问,因为首先write需要将数据进行填充到缓冲区,然后是DMA等需要消费缓冲区,从而设计到一个并发的情况,此时使用信号量进行控制并发。另外就是对消费端变量的访问使用自旋锁(性能更高?)来控制消费指针移动和是否激活标识的访问。

写缓冲主要的设计思路为:首先是持有信号量对缓冲区的写入(没有足够的空间则等待),然后是将数据写入到缓冲区,然后是持有自旋锁来控制将缓冲区数据写入到外设,这个是实际写入到外设的操作,然后唤醒等待缓冲区空闲空间的进程

从设计可以发现,write操作其实并没有使用中断,仅仅是控制了缓冲区的并发访问过程。而实际中断处理是根据实际的需求进行执行逻辑的,比如如果在需要数据时发送中断,则中断处理则将数据进行写入就行。

另外需要注意的就是中断处理的上下半部职责的划分:一般上部分需要执行快速操作,即直接将中断发生时通知CPU取数据的外设数据取到缓冲区就行,因为中断处理需要进行应答中断,应答完中断外设会继续忘设备控制器缓冲区填数据,不及时取走容易造成数据丢失或者杂揉,然后调用低半部就行;低半部则进行其他的必要操作,比如唤醒进程,启动其他的IO操作等,通过软中断的执行时机可以知道或者唤醒时机可以知道,休眠进程会在底半部处理完数据之后才醒,这样可以保证唤醒后的进程有新数据处理不至于马上再次休眠或者处理老数据

 

 

 

 

0 0