改进 RISC-V 平台 UART 及中断处理 #54
Replies: 3 comments
-
临时解决方案1:强制uart轮询:
|
Beta Was this translation helpful? Give feedback.
-
临时解决方案2:bug的uart_16550 crate 的 MmioSerialPort::init() 方法使用非 volatile 的 core::ptr::write() 来写入所有 MMIO 寄存器。Rust 编译器在 release 优化模式下,将 MCR(Modem Control Register)的写入优化掉了,导致 OUT2 位(bit 3)保持在上电默认值 0。 在 16550 UART 中,MCR.OUT2 是中断输出的门控位 — 当 OUT2 = 0 时,UART 即使检测到接收数据,也不会向 PLIC 发出中断信号。这就是为什么 PLIC 从未看到 UART 中断。 修复方案(console.rs,仅 1 行核心修改): console.rs FCR (offset 2) = 0x01: FIFO 使能,1字节触发 riscv64: ls、echo hello、uname -a 三个命令全部通过 UART IRQ 成功输入执行 |
Beta Was this translation helpful? Give feedback.
-
彻底解决方案:如果 tgoskits中starryos依赖的uart_16550从0.4.0升级 v0.5.0 后,uart.init() 中的 所有 寄存器写入(包括 MCR.OUT2)都会通过 volatile 路径执行,编译器无法优化掉,我刚才的 workaround(手动 write_volatile)就不需要了。 不过需要注意:v0.5.0 的 API 完全变了(major version bump),集成需要适配新 API。如果暂时不想大改,当前的临时解决方案2:最小修复(3 行 write_volatile)是最稳妥的方案。如果能都升级,那是比较彻底的方法。 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
目前在 RISC-V 架构的多个平台的测试中发现一些与 UART 中断相关问题,先列举如下:
LOG=trace或LTO=y时无法工作LOG=trace时表现为中断风暴,初步确认是处理中断不及时导致的,可能需要做一个缓冲区LTO=y时表现为不触发外部中断,目前还不知道原因LOG=trace的问题相似,但是仍存在其他问题:uart_16500提供的init函数时,每次从IIR中读到的标识为0xcc,读取缓冲区后仍然会触发中断,且IIR中读到一个很奇怪的值0xc7,按照 UART 规范,最低位为 0b1 应该表示没有发生中断才对init过程进行魔改,删除大部分寄存器初始化而只初始化中断,则行为正常,只在数据到来时触发中断且IIR读出来是0xc4关于中断处理时机问题:在 #49 之前,我们把 waker 的唤醒直接插入到了axplat 调用的中断处理程序中,而这个 PR 之后,我把它挪到了 axplat 处理完毕之后。理论上不应该影响处理的及时性,因为在处理期间 irq 都处于关闭状态才对,所以任务应该还是正常唤醒了,多了一个 log 后导致调度到 tty-reader 任务的延时变长了?目前想到的可能的解决方案就是在 uart 上接一个缓冲区。
关于初始化:在物理设备上 OS 启动时 u-boot、sbi 等应该已经把 uart 早都初始化好了,我们最多开个中断就够了,其他的fifo什么的确实都可以删掉(也说明 u-boot 在这个板子上也没启用 fifo)
关于后续改进:crates-io 上有一万个 uart。。。我们现在用的是下载量最多的 uart_16550,之前用过 ns16550a 但是它不开中断所以换了,最近调研这个问题的过程中也参考过 some-serial,
但是这个依赖树直接吓哭了还没弄清楚更多细节,先留一个 discussion 了,之后再开 issue
Beta Was this translation helpful? Give feedback.
All reactions