下一页 上一页 目录

17. 中断问题详情

虽然 故障排除 章节按症状列出了问题,但本节解释了如果中断设置不正确会发生什么。本节帮助您了解症状的原因、可能由同一问题引起的其他症状以及如何处理它。

17.1 中断问题的类型

“setserial”程序将向您展示串行驱动程序认为中断是如何设置的。如果串行驱动程序(和 setserial)设置正确,那么关于中断的一切都应该没问题。当然,设备必须存在 /dev/ttyS,并且即插即用(或跳线)必须在硬件中设置地址和 IRQ。Linux 不会故意允许中断冲突,如果您尝试执行任何会造成冲突的操作,您将收到“设备或资源忙”错误消息。

由于内核试图避免中断冲突,并且如果您尝试创建冲突,会给您“资源忙”消息,那么中断冲突是如何发生的呢?很简单。“setserial”可能设置错误,并且错误地预测不会发生冲突,但实际上会根据硬件中的设置发生真正的冲突。当这种情况发生时,不会出现“...busy”消息,但会实际发生冲突。性能可能会非常慢。两个设备将在同一条线路上发送相同的中断信号,CPU 会错误地认为中断仅来自一个设备。这将在以下章节中详细解释。

当您为两个设备分配相同的 IRQ 时,只要两个设备都未使用,Linux 就不会抱怨。当每个设备启动(初始化)时,它都会向 Linux 请求允许使用其硬件中断。Linux 会跟踪哪个中断分配给了谁,如果您的中断已被使用,您将看到此“... busy”错误消息。因此,如果两个设备使用相同的 IRQ,并且您仅启动其中一个设备,则一切正常。但是,当您下次尝试启动第二个设备时(不退出第一个设备),您会收到“... busy”错误消息。

17.2 错误设置或冲突中断的症状

症状取决于您是否拥有带有 FIFO 缓冲区的现代串口或没有 FIFO 缓冲区的过时串口。了解过时串口的症状也很重要,因为有时现代串口看起来也会表现出这种症状。

对于过时的串口,每隔几秒钟才通过一个字符。这太慢了,以至于看起来几乎像什么都没工作(特别是如果通过的字符是不可见的(例如空格或换行符))。对于带有 FIFO 缓冲区的现代端口,您可能会看到每隔几秒钟最多爆发 16 个字符。

如果您的端口上有调制解调器并拨打了一个号码,它似乎可能无法连接,因为 CONNECT 消息可能无法通过。但是经过长时间的等待,它最终可能会连接,您可能会看到登录消息的一部分(或类似内容)。来自您连接端的响应可能会延迟,以至于另一端放弃并断开您的连接,从而导致 NO CARRIER 消息。

如果您使用 minicom,一个常见的测试方法是键入最简单的“AT”命令,看看调制解调器是否响应。正常情况下(如果中断正常),键入 at<enter> 应该立即收到调制解调器的“OK”响应。如果中断错误,您键入 at<enter> 可能会看不到任何东西。但是大约 10 秒后,您会看到光标下降一行。正在发生的事情是 FIFO 的行为就像它只能容纳一个字节。“at”您键入的内容导致它溢出,并且两个字母都丢失了。但是最后的 <enter> 最终通过了,您通过注意到光标跳到下一行来“看到”这个不可见的字符。如果您要键入一个字母,然后等待大约 10 秒钟,您应该看到它回显到屏幕上。如果您的打字速度低于每分钟一个单词,这很好 :-)

17.3 错误设置的中断

如果您不理解中断的作用,请参阅 中断。如果串口在硬件中设置了一个 IRQ,但在设备驱动程序中设置了另一个 IRQ,则设备驱动程序将不会捕获串口发送的任何中断。由于串口使用中断来调用其驱动程序来服务端口(从其 16 字节接收缓冲区中获取字节或在其发送缓冲区中放入另外 16 字节),因此人们可能会期望串口根本无法工作。

但它仍然可能以某种方式工作。为什么?嗯,除了服务端口的中断方法之外,还有一种未记录的慢速轮询方法,不需要中断。它的工作方式是,设备驱动程序会定期检查串口,看看它是否需要任何东西,例如它是否有需要从其接收缓冲区中获取的一些字节。如果中断不起作用,串行驱动程序会退回到这种轮询方法。但是这种轮询方法并非旨在用作中断的替代品。它太慢了,不实用,并且可能导致缓冲区溢出。它的目的可能是让事情在丢失或未能正确执行一个中断时重新开始运行。它对于向您展示中断已失败也很有用。不要将这种慢速轮询方法与对 IRQ 设置为 0 的端口进行操作的快速轮询方法混淆。

对于 16 字节的发送缓冲区,将发送 16 个字节,然后它将等待下一次轮询(几秒钟后)发生,然后再发送接下来的 16 个字节。因此,传输速度非常慢,并且以小块形式进行。接收也很慢,因为接收缓冲区接收到的字节可能会在那里停留几秒钟,直到被轮询。

这解释了为什么您需要这么长时间才能看到您键入的内容。当您向调制解调器键入例如 AT 时,AT 会通过串口发送到调制解调器。然后调制解调器将 AT 通过串口回显到屏幕。因此,AT 字符必须两次通过串口。通常,这种情况发生得非常快,以至于 AT 似乎与您在键盘上敲击按键的同时出现在屏幕上。由于串口的慢速轮询延迟,您可能要等到 15 秒后才能看到您键入的内容。即使这样,您也经常看不到您键入的所有内容,而只能看到前几个字符。

16 字节接收缓冲区溢出怎么办?这将在外部调制解调器上发生,因为调制解调器只是以高速发送到串口,这很可能导致 16 字节缓冲区溢出。但对于内部调制解调器,串口在同一张卡上,并且它很可能会在将接收到的字节放入其中之前检查这个 16 字节接收缓冲区是否有更多字节的空间。在这种情况下,不会发生接收缓冲区的溢出,但文本只会以 16 字节的块形式出现在屏幕上,间隔几秒钟。

即使使用外部调制解调器,您也可能不会发生溢出。如果仅发送少量字符(少于 16 个),则不会发生溢出,因为缓冲区可能还有空间容纳它们。但是,尝试从调制解调器向屏幕发送更多字节可能会导致溢出。但是,如果时机合适,超过 16 个(没有间隔)也可以通过而不会发生溢出。例如,假设从外部电缆向端口发送了 32 字节的突发数据。轮询可能恰好在接收到前 16 个字节后发生,因此它可以正确拾取这 16 个字节。然后将有空间容纳接下来的 16 个字节,从而使整个 32 个字节都通过。虽然这种情况不太可能发生,但 17 到 31 个字节通过的类似情况更有可能发生。但更可能的是,只有偶尔的 16 字节块可以通过,并可能丢失数据。

如果您有一个只有 1 字节缓冲区的过时串口(或者它被错误地设置为像 1 字节缓冲区一样工作),那么情况将比上述描述的更糟,并且只有偶尔一个字符可以通过端口。除了最后接收到的字符外,每个接收到的字符都会导致溢出(并丢失)。此字符很可能只是换行符,因为这通常是在发送到屏幕的一连串字符中最后发送的字符。因此,您可能会向调制解调器键入 AT<return>,但永远不会在屏幕上看到 AT。您在几秒钟后看到的只是光标下降一行(换行符)。我曾经遇到过一个 16 字节的 FIFO 缓冲区,它的行为就像一个 1 字节的缓冲区。

当通信程序启动时,它期望中断工作正常。它不适合使用这种类似慢速轮询的运行模式。因此,可能会发生各种错误,例如错误地设置串口和/或调制解调器。它可能无法意识到何时建立了连接。如果脚本用于登录,则可能会由于轮询延迟而失败(由超时引起)。

17.4 中断冲突

当两个设备具有相同的 IRQ 号码时,称为共享中断。在某些情况下,这种共享可以正常工作。从内核版本 2.2 开始,ISA 串口如果硬件为此设计,可以与其他串口共享中断。PCI 总线上的设备可以与其他 PCI 总线上的设备共享相同的 IRQ 中断(前提是软件支持此功能)。在其他可能发生冲突的情况下,如果具有相同 IRQ 的两个设备永远不同时“使用”,则应该没有问题。更准确地说,“使用中”实际上意味着“打开”(在程序员术语中)。在上述例外情况之外(除非特殊的软件和硬件允许共享),否则不允许共享,并且如果尝试共享,则会发生冲突。

即使两个具有冲突 IRQ 的进程同时运行,其中一个设备的 interrupts 很可能被其设备驱动程序捕获并可能正常工作。另一个设备的 interrupts 不会被正确的驱动程序捕获,并且很可能表现得像一个中断设置错误的进程。有关更多详细信息,请参阅 错误设置的中断

17.5 解决中断问题

如果您遇到如上所述的非常缓慢的响应,那么一个测试是将 IRQ 更改为 0(使用快速轮询而不是中断),看看问题是否消失。请注意,由于 IRQ=0 引起的轮询比由于错误中断引起的慢速“轮询”快几个数量级。如果 IRQ=0 似乎解决了问题,那么很可能中断存在问题。使用 IRQ=0 非常消耗资源,只是一种临时修复。您应该尝试找出中断问题的原因,而不是永久使用 IRQ=0。

检查 /proc/interrupts 以查看 IRQ 当前是否被另一个进程使用。如果它被另一个串口使用,您可以尝试“top”(键入 f 然后启用 TTY 显示)或“ps -e”来找出哪些串口正在使用。如果您怀疑 setserial 的 IRQ 错误,请参阅 我的串口的当前 IO 地址和 IRQ 是什么?


下一页 上一页 目录