2月技术报告-周雨

目标与问题

主要目标

  1. 阅读 RKNPU 驱动相关源码,学习 NPU/AI 相关知识,将 RKNPU 硬件手册总结为 markdown 文档
  2. 实现NPU驱动异步中断支持
  3. 实现NPU驱动多核多任务并发

主要问题

  1. 环境与工具链问题:开发板 U‑Boot 缺少网卡驱动,只能通过串口加载内核,调试效率低;U-boot网卡驱动编译困难,依赖太多,将会逐步解决
  2. 驱动集成冲突:尝试将 NPU 驱动集成到 StarryOS 主线时,HAL 层架构 axhalsomehal 存在冲突,RK3588 平台级代码集成涉及整个架构的大修改。当前阶段将继续在当前已有驱动基础上开发。暂时不会集成到主线

方案或思路

面对上述问题,我制定了以下开发路线:

  1. 分阶段学习与验证

    • 第一阶段:学习 NPU 原理、AI 模型推理流程,利用 RKNN Toolkit2 仿真器在 x86 上验证推理链条。
    • 第二阶段:在真实硬件(OrangePi 5 Plus RK3588)上部署 StarryOS(NPU 版本),验证驱动可行性。
    • 第三阶段:逆向闭源用户态库 librknnrt.so,整理完整的寄存器语义和任务提交流程,形成社区参考文档。
  2. 驱动架构设计

    • 采用 rdrive 框架实现设备树(DTB)自动探测,避免硬编码设备地址。
    • 创建独立的 axdrm crate 实现 DRM 框架,提供 GEM 内存管理和 ioctl 编码解析/分发机制,保持用户态接口兼容性。
    • 将驱动模块放在 StarryOS 根目录独立开发,规避 workspace 循环依赖问题,待功能稳定后再集成回 ArceOS。
  3. 寄存器访问安全

    • 使用 svd2rust 工具从 SVD 描述文件生成类型安全的寄存器库 rknpu-regs,覆盖 PC、CNA、CORE、DPU、PPU、DDMA 等所有功能块。
    • 通过编译期类型检查杜绝寄存器偏移量写错、位域宽度混淆等错误。
  4. 异步中断处理

    • 利用 WFI(Wait For Interrupt)指令实现低功耗等待,NPU 核心完成任务后触发中断,CPU 被唤醒并读取中断状态寄存器。
    • 为后续多核并发任务提交奠定基础——每个 NPU 核心可独立触发中断,CPU 侧可并行等待多个核心的完成通知。
  5. 多核并发任务调度

    • 扩展驱动数据结构,支持多套寄存器命令缓冲区(regcmd)。
    • 重构 submit_ioctrl 函数,实现批量任务分配,一次 ioctl 可向多个核心提交任务。
    • 新增 wait_all_npucore 并行等待机制,循环检查各核心中断状态,直到所有核心完成任务。
  6. 问题规避与迂回

    • 暂时放弃将驱动集成到 StarryOS 主线,专注于在 NPU 版本上开发核心功能,减少架构冲突带来的干扰。
    • 通过刷写干净的 SPI 镜像解决 U‑Boot 环境变量残留问题,明确使用 eMMC 作为存储介质。

实现情况

1. 基础知识学习与仿真验证(第一周)

  • NPU 原理学习:理解了 NPU 作为神经网络处理单元的本质,掌握了 AI 模型训练与推理的基本流程,以及驱动在推理链条中的角色(用户态库通过 ioctl 与内核驱动通信,驱动负责任务调度、DMA 搬运、寄存器操作)。
  • RKNN Toolkit2 仿真验证:在 x86 主机上利用 RKNN Toolkit2 的仿真器跑通测例,梳理出 RKNN 推理的 API 调用流程:rknn_initrknn_inputs_setrknn_runrknn_outputs_getrknn_destroy

2. 开发板验证与文档整理(第二周)

  • 硬件验证:在 OrangePi 5 Plus(RK3588)开发板上成功部署 StarryOS(NPU 版本),并跑通 RKNN 推理测例,验证了 NPU 驱动在真实硬件上的可行性。
  • 闭源库逆向与文档:系统逆向分析了 librknnrt.so 用户态库,结合官方 TRM 手册和开源内核驱动,整理了完整的寄存器语义、任务提交流程、状态机与 DMA Fence 路径,形成 GitHub Pages 文档,为社区提供参考。

3. 驱动骨架与 DRM 框架搭建(第二周)

  • 设备探测:编写 dtbparse.rs,利用 rdrive 框架通过设备树(DTB)自动探测 NPU 设备(compatible = "rockchip,rk3588-rknn"),提取 MMIO 基址(0xfdab0000,大小 0x9000)和中断号(SPI 110‑112)。
  • DRM 框架:创建 axdrm crate,实现 GEM 内存对象管理(handle 分配/回收、物理地址映射)和 ioctl 编码解析/分发机制,为 NPU 驱动提供兼容 Linux DRM 的用户态接口。

4. 寄存器库重构与 AI 辅助注释(第三周)

  • svd2rust 寄存器库:基于 SVD 描述文件生成类型安全的寄存器库 rknpu-regs,覆盖 PC、CNA、CORE、DPU、PPU、DDMA 等所有功能块。将原有的手动偏移+裸指针访问改为类型安全、带自动补全和文档的 API,例如:
    #![allow(unused)]
    fn main() {
    let status = core.pc().interrupt_status().read().bits();
    core.pc().interrupt_clear().write(|w| unsafe { w.bits(INT_CLEAR_ALL) });
    }
  • AI 辅助注释:利用 AI 为 axnpu 驱动代码添加详细的中文注释,明确关键函数的调用流程和参数含义,降低后续开发和协作门槛。

5. 异步中断处理实现(第三周)

  • WFI 等待机制:实现基于 WFI(Wait For Interrupt)指令的低功耗异步等待。NPU 核心完成任务后触发中断,CPU 进入休眠状态;中断到来时 CPU 被唤醒,读取中断状态寄存器并清除标志位,返回任务执行结果。
  • 多核中断基础:该机制为多核并发任务提交打下基础,每个 NPU 核心可独立触发中断,CPU 侧可并行等待多个核心的完成通知。

6. 多核并行矩阵乘法实现(第五周)

  • 三核并行 QKV 计算:扩展 Transformer 结构体,支持 3 套 regcmd 缓冲区,实现 matmul_npu_3core_qkv 函数,将 Transformer 中的 Q、K、V 三个矩阵乘法并行提交到 3 个 NPU 核心。
  • 批量任务分配:重构 submit_ioctrl 函数,支持将用户空间的任务数组自动分配到多个 NPU 核心,一次 ioctl 可向多个核心提交任务。
  • 并行等待机制:新增 wait_all_npucore 函数,循环检查各核心中断状态,利用 WFI 等待所有核心完成,实现真正的多核并行等待。

7. 板端验证结果

板端运行日志显示多核并行成功:

[261.640936] Total tasks to submit: 3, active cores: 3, max batch size: 4095
[261.650710] Total tasks to submit: 1, active cores: 1, max batch size: 4095
[262.295035] Total tasks to submit: 3, active cores: 3, max batch size: 4095
...
Once upon a time...
  • 3 tasks, 3 cores 表示 QKV 三核并行成功。
  • 1 tasks, 1 core 表示后续的 wo 矩阵乘法(单核)。
  • 模型推理输出 "Once upon a time..." 验证结果正确。

8. 其他问题修复(第三周)

  • Axvisor 文件系统同步问题:修复了 rsext4 缓存未同步导致的磁盘数据不一致问题,在写操作后增加 sync_to_disk 调用,确保文件系统一致性(PR #368)。

下一步的计划/建议

基于 1 月末和 2 月份的开发进展,后续工作可围绕以下方向展开:

  1. 驱动稳定性与健壮性

    • 当前驱动还有很多unimpliment函数和特性,我将会继续完善它
    • 完善错误处理机制,增强驱动健壮性
  2. 多核调度优化

    • 实现动态负载均衡,根据各 NPU 核心的利用率自动分配任务。(当前多核并发是简单的任务切片)
    • 支持任务优先级调度,确保高优先级任务优先执行。
    • 探索任务依赖关系(DAG)支持,实现复杂模型层的流水线并行。
  3. 主线集成与代码重构

    • 待 NPU 驱动功能稳定后,重新评估集成到 StarryOS 主线的可行性,解决 HAL 层冲突。
    • axnpu-rknn 驱动模块迁移回 ArceOS 的 modules/ 目录,遵循项目模块化规范。
  4. 文档与社区建设

    • 持续更新 GitHub Pages 文档,补充更多寄存器细节、性能调优指南和故障排查案例。