fix(sg2002, sdhci-cv1800, aic8800): fix WiFi TX throughput via XFER_COMPLETE interrupt - #1914
fix(sg2002, sdhci-cv1800, aic8800): fix WiFi TX throughput via XFER_COMPLETE interrupt#1914Antareske wants to merge 9 commits into
Conversation
Refactor the SDHCI PIO transfer wait path to use hardware interrupt wake for XFER_COMPLETE: - ISR now handles XFER_COMPLETE alongside CARD_INT: masking the signal and invoking a registered PIO wake callback to unblock the waiting task - poll_int_status split into two-phase polling: Phase 1 fast spin (~50us, covers most hardware turnaround), Phase 2 interrupt-driven for XFER_COMPLETE and timed fallback for other status bits - Introduce CallbackSlot (AtomicUsize-backed) to encapsulate ISR-safe function pointer storage with a single Safety contract and zero-value guard - Consolidate NORM_INT_SIG_EN read-modify-write operations into a rmw_norm_sig_en() helper; the RMW is not atomic but self-heals via the XFER_COMPLETE sticky bit re-asserting the level-triggered interrupt line - Remove yield_now from SdhciDelay trait and ArceosDelay; add block_timeout with a sleep-based default fallback - Add debug_assert!(cpu_num() == 1) in the ArceOS glue layer to document the single-core assumption for SIG_EN RMW
Track Phase 1/2 hit rates, wall-clock timing, and iteration counts per interrupt bit (CMD_COMPLETE, XFER_COMPLETE, BUF_WR_READY, BUF_RD_READY). Add now_nanos() to SdhciDelay trait for timestamping, implemented via monotonic_time_nanos() in the ArceOS glue layer. dump_poll_diagnostics() prints the accumulated stats and auto-resets; reset_poll_diagnostics() resets mid-epoch without printing.
…unters" This reverts commit 4f76933.
Insert an atomic fence at the entry of poll_int_status to flush pending MMIO writes out of the CPU store buffer before the Phase 1 spin loop begins. Without the fence, the 1000-iteration (≈50 µs) spin window can miss the status bit because the reads compete with draining buffer writes on the SDHCI bus, delaying the hardware from receiving the data and asserting BUF_WR_READY / CMD_COMPLETE. This explains why the earlier diagnostic-counter instrumentation accidentally fixed TX throughput (1 → 11 Mbps): the now_nanos() → monotonic_time_nanos() call issued a cross-domain MMIO read before entering Phase 1, which acted as a natural store-buffer drain.
… command and error paths - clear_stale_status: mask out XFER_COMPLETE before W1C so it is not destroyed while a PIO waiter is blocked in poll_int_status Phase 2. - poll_int_status error path: selective W1C of error bits and current wait bit, preserving CARD_INT. - poll_int_status: add trace log when falling back to Phase 2 polling for non-XFER_COMPLETE bits. - Document single-waiter contract on SdhciDelay::block_timeout and the SDHCI_PIO_WQ invariant to make the lost-wake bound explicit.
On error/timeout exits for non-XFER waits (e.g. BUF_RD_READY), the W1C only cleared ERROR | waited_bit — XFER_COMPLETE could be left set and leak into the next transfer's wait_transfer_complete as a false early success. Now unconditionally W1C XFER_COMPLETE alongside the error and wait bits; W1C of an unset bit is a hardware no-op, so this is always safe.
…or consistency Since the existing comments in this crate are predominantly in Chinese, translate the English comments introduced on this branch to match.
There was a problem hiding this comment.
本 PR 将 SG2002/AIC8800 的 PIO 传输完成从让出轮询改为 XFER_COMPLETE 中断唤醒,并为 RX kicker、选择性 W1C、运行时 glue 和 ITS 描述补充配套改动。变更触及 SDHCI 完成语义与板级 WiFi 工作流,功能开发准则适用;实现仍局限于现有驱动核心与 ArceOS glue,未新增对外 API。
阻塞问题:XFER_COMPLETE 的 WaitQueue 等待存在丢唤醒窗口,导致实际完成路径可退化为完整 10ms timeout,不能满足本 PR 的中断即时唤醒目标;详见行内评论。
验证:cargo fmt --all --check 通过;cargo clippy --manifest-path components/sdhci-cv1800/Cargo.toml --all-features -- -D warnings 通过,cargo test --manifest-path components/sdhci-cv1800/Cargo.toml --all-features 通过(0 tests);aic8800 的同等 clippy 通过、测试 4/4 通过。axruntime --all-features 因基线中 userspace 与 kernel TLS 不兼容而在 ax-cpu 失败,未把它归因于本 PR。该 head 在 rcore-os/tgoskits 未报告 check run 或传统 commit status;当前环境也无法复现 LicheeRV Nano 的板卡运行。
已检查历史审查与 PR 评论:没有已有审查或讨论需要处理。已检查 base 与开放 PR 搜索结果:未发现除本 PR 外的同一 sdhci-cv1800/aic8800/SG2002 WiFi 实现,未见重复或合并冲突风险。
待修复后请增加能覆盖“ISR 在 waiter 入队前发生”的确定性回归验证,并在实际 SG2002 工作流上重跑上传、下载和双向测试。
Powered by gpt-5.6-terra
|
|
||
| if use_irq { | ||
| irq::unmask_xfer_complete_signal(); | ||
| let _timed_out = crate::runtime::delay().block_timeout(PHASE2_STEP_MS); |
There was a problem hiding this comment.
阻塞:这里仍有丢唤醒窗口。unmask_xfer_complete_signal() 后、block_timeout() 将任务加入 WaitQueue 前,传输可能完成;ISR 会屏蔽 XFER 信号并调用 notify_one_from_irq(),但队列为空时该通知不会被保存。随后任务只能等满 10ms timeout 才在 recheck 中看到 sticky bit,微秒级完成路径会退化。请用 ISR 发布的 pending/completion 状态配合条件等待,或把清状态、开信号、检查和入队纳入不会丢事件的同步协议,保证 ISR 先发生时等待方不会睡过该事件。
使用 XFER_COMPLETE 中断修复 SG2002 WiFi 上行吞吐量
背景
@BattiestStone4
SG2002 (LicheeRV Nano) 的 aic8800 WiFi 模组通过 SDIO 接口与 SoC 通信,SDHCI 驱动使用 PIO 模式,PIO 传输完成等待(
poll_int_status)采用两阶段轮询:yield_now()让出 CPU 后重新检查 INT_STATUS上行方向存在严重吞吐问题,见 StarryOS WiFi 上行吞吐排查报告 (@BattiestStone4)。报告发现,硬件在 t≈250µs 就发完帧并置好了 XFER_COMPLETE。本 PR 认为可以通过使能 XFER_COMPLETE 的中断来控制 CPU 返回驱动以修复上行吞吐量极低的问题,无需让出时间片或忙等 XFER_COMPLETE 置位。
方案与改动
核心思路:用 XFER_COMPLETE 硬件中断替代
yield_now()——任务阻塞在 WaitQueue,硬件完成传输后 ISR 立即唤醒,唤醒延迟从约 48ms 降至微秒级。1. 修复 WiFi 启动
aic8800 RX 线程的周期性 kicker 原先仅在 dual-pipe 模式下启动。改为无条件启动 10ms kicker,作为 ISR 驱动 RX 响应路径不可靠时的兜底,确保入站帧不丢失。此改动使得单通道的 aic8800D80 WiFi 芯片可在 starryos 启动时顺利初始化 AP 模式。
2. XFER_COMPLETE 中断
在 Phase 2 中使能 XFER_COMPLETE 中断信号,任务通过
block_timeout阻塞在 WaitQueue,硬件完成时 SDHCI ISR 写NORM_INT_SIG_EN清零 XFER_COMPLETE 使能位并调用notify_one_from_irq唤醒任务,任务醒来后在poll_status_once中读到 XFER_COMPLETE 已置位,W1C 清除后返回。XFER_COMPLETE 是 sticky bit,若 ISR 提前 W1C 清除,任务醒来看到状态为 0 会误判未完成,所以 ISR 只 mask 信号不碰状态位,清除统一由
poll_status_once(poll_int_status内)执行。此前
clear_stale_status在每条命令前 W1C 清理 INT_STATUS 残留位,在实现了 XFER_COMPLETE 中断后会误清 XFER_COMPLETE ,故清理残留位时过滤该位。此外,非 XFER 等待的错误/超时退出路径也需要处理未受理的 XFER_COMPLETE,否则会被下一次wait_transfer_complete当成提前成功,因此改为退出路径加清。3. Store Buffer Fence
PIO 写
SDHCI_BUFFER后,写操作可能会被 CPU store buffer 暂存而非直接输出到总线(SDHCI 寄存器是 MMIO,CPU 有可能会乱序执行不同内存地址的操作)。若pio_write操作被暂存,进入 Phase 1 后 CPU 自旋读INT_STATUS,妨碍滞后的pio_write及时输出到总线(竞争总线),硬件收到pio_write并置位INT_STATUS的时间被推迟,导致 Phase 1 的 50µs 窗口可能在硬件就绪前过期。实测表现如此,上行吞吐极小(略好于引入 XFER_COMPLETE 中断之前)。在 Phase 1 入口加
fence(SeqCst)排空 store buffer 再轮询。原本的yield_now()没这个问题,其任务切换的mret自带 fence 语义,换成阻塞等待后需要显式补上。测试结果
平台:LicheeRV Nano SG2002,网卡:aic8800D80
纯上传(TX)
纯下载(RX)
双向
改动内容
提交列表
fix&test(sg2002,wifi): fix wifi boot & include sg2002 wifi configfix(sdhci-cv1800): add interrupt-driven PIO transfer completionfix(sdhci-cv1800): drain store buffer before Phase 1 MMIO pollingfix(sdhci-cv1800): use selective W1C to preserve XFER_COMPLETEfix(sdhci-cv1800): consume XFER_COMPLETE in error and timeout exit pathschore(sdhci-cv1800): translate newly-introduced comments to Chinesechore(sg2002): remove aic8800-wifi feature from licheerv-nano-sg2002 base config改动文件
components/aic8800/src/fdrv/thread/rx.rscomponents/sdhci-cv1800/src/irq.rscomponents/sdhci-cv1800/src/lib.rscomponents/sdhci-cv1800/src/regs.rscomponents/sdhci-cv1800/src/runtime.rsos/arceos/modules/axruntime/src/wifi_glue.rsos/StarryOS/configs/board/licheerv-nano-sg2002.its