我们的团队正在使用embedded式处理器(Phytec LPC3180,ARM9)。 我们devise了一块在LPC3180的I2C总线上包含四个MAX3107 uart芯片的电路板。 如果有问题,我们正在运行内核2.6.10,这个处理器的最新版本(这个产品的支持并不是很好,我们不得不开发或修复由Phytec提供的许多驱动程序,Phytec似乎没有兴趣升级这个产品的linux代码(特别是内核版本),这太糟糕了,因为LPC3180是一个很好的设备,特别是在低功耗的embedded式产品中,不需要以太网, (由于以太网控制器芯片的相关功耗),现在安装的处理程序(由其他人开发)基于上半部分处理程序和下半部分工作队列方法。
当I2C总线上的四个器件之一(MAX3107 UART芯片)接收到一个字符时,它会产生一个中断。 所有四个MAX3107芯片的中断线是共用的(漏极开路下拉),线连接到configuration为电平中断的3180的GPIO引脚。 当其中一个3017产生一个中断时,会执行一个处理程序(粗略地)进行以下处理:
spin_lock_irqsave(); disable_irq_nosync(irqno); irq_enabled = 0; irq_received = 1; spin_unlock_irqrestore() set_queued_work(); // Queue up work for all four devices for every interrupt // because at this point we don't know which of the four // 3107's generated the interrupt return IRQ_HANDLED;
请注意,这是我觉得有点麻烦,中断不能重新启用之前离开上面的代码。 相反,驱动程序是这样编写的,以便下半部分工作队列任务(使用“enable_irq(LPC_IRQ_LINE)函数调用”)重新启用中断。由于工作队列任务不在中断环境中运行,我相信他们可能会睡眠,我认为这是一个中断处理程序的坏主意。
上述方法的基本原理如下:1.如果四个MAX3107 UART芯片中的一个接收到一个字符并产生一个中断(例如),则中断处理程序需要确定四个I2C器件中哪一个实际上引起中断。 然而,很显然,在上半部分中断处理程序的上下文中,不能读取I2C设备,因为I2C读取可以睡眠,对于中断处理程序上半部分来说,这是不适当的。 2.解决上述问题(即哪个设备引起中断)的方法是禁用中断,并退出上半部处理程序,之后,非中断上下文代码可以查询I2C总线上的四个设备中的每一个设备找出接收到的字符(因此产生中断)。 3.一旦下半部处理器判断哪个器件产生了中断,下半部分代码将禁止该芯片上的中断,从而不会再触发到LPC3180的中断线。 在这样做之后,它读取串行数据并退出。
这里的主要问题似乎是没有办法从中断处理程序的上半部分查询四个MAX3107 uart芯片。 如果上半部分在返回之前简单地重新启用中断,则会导致同一个芯片再次产生中断,我认为,导致上半部分禁止中断,调度下半部分工作队列并禁用中断仅仅发现自己回到了同一个地方,因为在下半部分代码到达引起中断的芯片之前,发生了另一个中断,等等。
任何意见处理这个驱动程序将不胜感激。 我真的不喜欢允许中断在驱动程序的上半部分被禁用的想法,但在现有的上半部分驱动代码之前不能被重新启用。 这似乎并不安全。
谢谢,
吉姆
PS:在我的阅读中,我发现了线程中断作为处理上述需求的一种手段(至less这是我对网站文章的解释,例如http://lwn.net/Articles/302043/ )。 我不确定Phytec提供的2.6.10内核是否包含线程中断函数。 我打算在接下来的几天看看这个。
如果你的代码被正确写入,在处理之前的中断完成之前,如果一个设备发出中断应该没有关系,并且你不希望在上半部分进行阻塞操作,但是阻塞操作在下半部分,其实这是他们存在的部分原因!
在这种情况下,我会建议一种方法,上半部分只安排下半部分,然后下半部分在所有4个设备上循环,并处理任何待处理的请求。 可能是多个设备需要处理,或者没有。
更新:确实,您可能会通过负载测试使系统过载,并且可能需要对软件进行优化以处理重负载。 另外我没有一个3180和四个3107(或类似)的我自己来测试这个,所以我在理论上讲,但我不清楚为什么你需要关闭中断。
一般来说,当一个硬件设备断言一个中断,它将不会断言另一个,直到当前的一个被清除。 所以你有4个设备共享一个int行:
当清除中断时,器件将被允许触发另一个中断,但不是之前。
有关此特定设备的更多详情:
看来,这个器件(MAX3107)有一个128字的缓冲区,默认情况下,每一个单词后都会中断。 但似乎你应该能够通过设置FIFO级寄存器来更好地利用缓冲区。 然后,只有在字数已经达到rx的时候才会中断(或者如果您将tx FIFO填充到阈值以上,那么您应该减慢发送速度(即软件中的缓冲区))。
看来这个想法是基本上从设备上周期性地取出数据(可能是每隔100ms或10ms,或者看起来对你有用的任何东西),然后只有中断作为警告,说明你已经越过了一个阈值,这可能会调度周期性功能立即执行,或增加调用的速度。
中断是启用和禁用的,因为我们使用基于等级的中断,而不是基于边缘的。 吉姆,在驱动程序代码标题中明确解释了这些的后果。
需要基于等级的中断来避免在到达另一个UART之后立即丢失到达一个UART的字符的边缘中断:第一个服务有效地消除第二个字符,从而使第二个字符丢失。 事实上,当驱动程序> 1个UART被执行时,这个驱动程序的初始边缘中断版本正是如此。
目前的计划有没有被发现的失败?
问候,司机作者(别人)