如果待处理的字符超过256个,为什么8250 UART驱动程序不唤醒TTY?


8

这种if条件的动机是什么void serial8250_tx_chars(struct uart_8250_port *up)

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    uart_write_wakeup(port);

自Linux 1.1.13(1994年5月)以来一直存在,并且在大多数UART驱动程序中都重复使用。

背景:定制的Linux 3.4.91,ARMv7上的嵌入式系统,UART端口0配置为38400波特,I / o使用16字节FIFO。在我们的设置中,所有这些都无法更改。

当的printf-ING 非常沉重经由UART在控制台上,内部的4kB缓冲液(UART_XMIT_SIZE)填满,然后的用户空间进程直到缓冲器被清空(这需要在38400波特1秒!)。然后,此行为重复。这是因为n_tty_write()当缓冲区已满时,函数将进入睡眠状态,并且由于上述问题而无法长时间唤醒。

如果只删除此检查,我会发现它更自然,更有效。然后,printfs将尽快填充缓冲区,然后以清空缓冲区的速度继续,而不是我观察到的突发处理。

在我的环境中,它可以正常工作,但我肯定会丢失或误解某些东西。当前实施必须有一个理由。如果我消除这种状况,会有副作用吗?

作为附带的问题:是否有配置选项来调整此行为,例如使printf总是立即返回并在缓冲区已满时丢弃输出?


对此一无所知,我的直觉是:这是一个普通的Linux串行控制台设置。我与那些使用标准x86硬件的人员合作。对于直接串行连接,我始终必须使用硬件流控制。可能是个主意。
vasquez

1
效率可能存在差异。为什么不将WAKEUP_CHARS设置为UART_XMIT_SIZE-128之类的呢?
James Youngman'3

@JamesYoungman实际上,这也是我最终要做的。干杯!
Hans W. Heckel

Answers:


2

这是一种效率措施。CPU的运行速度比串行端口快得多,如果内核每次在缓冲区中有一点空间时都让用户空间进程运行,它将最终导致访问用户空间并返回每个数据字节。那非常浪费CPU时间:

$ time dd if=/dev/zero of=/dev/null bs=1 count=10000000
10000000+0 records in
10000000+0 records out
10000000 bytes (10 MB, 9.5 MiB) copied, 5.95145 s, 1.7 MB/s

real    0m5.954s
user    0m1.960s
sys     0m3.992s

$ time dd if=/dev/zero of=/dev/null bs=1000 count=10000
10000+0 records in
10000+0 records out
10000000 bytes (10 MB, 9.5 MiB) copied, 0.011041 s, 906 MB/s

real    0m0.014s
user    0m0.000s
sys     0m0.012s

上面的测试甚至不是读写真实的设备:整个时间差就是系统在用户空间和内核空间之间跳动的频率。

如果用户空间不想被阻止,它可以使用非阻塞I / O,或者可以检查使用select()调用以查看是否有足够的空间写入设备...如果没有,可以将其转储。剩下的放入自己的缓冲区并继续处理。诚然,这确实使事情变得复杂,因为现在您必须刷新一个缓冲区...但是,如果您使用的是stdio,无论如何通常都是如此。


这支持@James关于效率的评论。现在对我来说更有意义。谢谢,还有数字!
汉斯·W·赫克尔

应当注意,从内核2.6开始,此问题引用的代码通常出现在较低层的驱动程序(例如UART驱动程序)中。这些驱动程序提供了更高的层,serial_core,与硬件进行交互的方式。它是实际与用户空间交互的串行核心(除非硬件驱动程序实现它自己的ioctl或类似的东西)。我相信受访者的答案仍然成立。
安德鲁·法兰加
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.