Skip to content

elliott10/tpu_sg2002

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SG2002 TPU Device Driver

SG2002 TPU 设备的Rust驱动。

使用 Rust 最小化设备层实现,去除操作系统内核依赖,保留硬件操作逻辑,便于在裸机或自研RustOS上集成运行。

特性

  • KernelFns 抽象层:隔离系统相关能力(日志、时间、时钟控制、缓存同步)
  • 硬件操作:TDMA/TIU 寄存器访问与控制流程
  • DMA 缓冲区执行:支持描述符模式和 PIO 模式
  • 挂起/恢复:支持电源管理
  • 结构对齐:IOCTL 结构体使用 #[repr(C)] 保证 ABI 兼容

代码结构

src/
├── lib.rs          # 库入口,类型导出,TpuError 定义
├── types.rs        # 数据类型 (DmaHeader, CpuSyncDesc, TpuConfig, TpuTdmaPioInfo)
├── device.rs       # TPU 设备核心实现 (TpuDevice)
├── kernel_fns.rs   # 内核函数抽象 trait (KernelFns)
├── platform.rs     # 平台相关结构 (TdmaReg, TpuRegBackup, 状态解析)
├── pmu.rs          # PMU 性能监控 (TpuPmu, PmuSummary)
├── registers.rs    # TDMA/TIU 硬件寄存器常量
└── ioctrl.rs       # IOCTL 参数结构定义

调用流程

本库的 API 设计参照 Linux 驱动模块的生命周期:

Linux 驱动 vs Rust 库对照

维度 Linux 驱动实现 Rust 库实现 StarryOS 适配层
设备生命周期 cvi_tpu_probe/open/remove + platform_tpu_* TpuDevice::new/open/platform_init/platform_deinit /dev/cvi-tpu0 设备对象中持有 TpuDevice
提交入口 CVITPU_SUBMIT_DMABUF -> cvi_tpu_submit() -> worker -> platform_run_dmabuf() 直接 run_dmabuf() ioctl(CVITPU_SUBMIT_DMABUF) 同步调用 run_dmabuf()
等待入口 CVITPU_WAIT_DMABUF -> wait_event_interruptible(done_list) 库不管理 OS 等待队列 wait_dmabuf 在适配层按 seq_no 查询 done_list
缓存同步 CVITPU_DMABUF_FLUSH/INVLD(_FD) KernelFns::dma_sync_for_* 抽象 StarryOS 用 fence/ion 信息做同步
描述符解析 内核直接按 C 结构体解析 dma_hdr_t + cvi_cpu_sync_desc_t[] parse_dmabuf_view() 统一解析与边界检查 适配层调用 parse_dmabuf_view(),不再手写解析
TDMA 完成等待 中断完成 + completion 等待 wait_tdma_done() 紧凑轮询 + 超时 由库内部处理,适配层仅接收结果
超时恢复 platform_tpu_reset() reset() run_dmabuf 超时后可由上层执行 reset
挂起恢复 platform_tpu_suspend/resume suspend()/resume() 可由系统电源管理路径调用

常用 ioctl 对照(用户态视角):

ioctl Linux 语义 StarryOS 当前语义
CVITPU_SUBMIT_DMABUF (_IOC(_IOC_WRITE, 0x70, 0x1, 0x8)) 提交任务入队 同步执行一次 run_dmabuf 并记录 seq_no 结果
CVITPU_WAIT_DMABUF (`_IOC(_IOC_READ _IOC_WRITE, 0x70, 0x6, 0x8)`) seq_no 阻塞等待完成
CVITPU_DMABUF_FLUSH (nr=0x4) CPU -> Device cache sync 调用 dma_sync_for_device
CVITPU_DMABUF_INVLD (nr=0x5) Device -> CPU cache sync 调用 dma_sync_for_cpu

在Rust OS中的调用序列

基于 YOLOv8 on StarryOS 实际运行于SG2002硬件平台的建议集成流程:

  1. 系统初始化阶段

    • 创建 TpuDevice::new(...)
    • 调用 probe_setting()
    • 在设备初始化阶段调用一次 platform_init()
  2. 用户态准备阶段(/dev/ion + /dev/cvi-tpu0

    • ION_IOC_ALLOC 分配 dmabuf
    • mmap 映射 ion buffer 到用户态
    • CVITPU_DMABUF_INVLD / CVITPU_DMABUF_FLUSH 做缓存同步
  3. 提交执行阶段(核心热路径)

    • CVITPU_SUBMIT_DMABUF
    • 驱动侧通过 parse_dmabuf_view() 解析 header/descs
    • 调用 run_dmabuf(paddr, header, descs)
  4. 等待完成阶段

    • CVITPU_WAIT_DMABUF
    • 使用与 submit 一致的 seq_no 获取结果
  5. 可选收尾

    • 继续下一帧提交(推荐)
    • 设备长时间空闲时再 platform_deinit()

适配的示例代码

// 1. 实现 KernelFns trait
struct MyKernelFns {
    // 可包含时钟控制器、复位控制器的引用
}

impl KernelFns for MyKernelFns {
    fn sleep_ms(&self, ms: u32) {
        // 实现毫秒级延时
    }
    
    fn now_us(&self) -> TimeStamp {
        // 返回微秒级单调时间戳
        0
    }
    
    fn log(&self, level: LogLevel, msg: &str) {
        // 日志输出
    }
    
    fn enable_clocks(&self) {
        // 使能 clk_tpu_axi, clk_tpu_fab
    }
    
    fn disable_clocks(&self) {
        // 关闭 TPU 时钟
    }
    
    fn reset(&self) {
        // 触发 res_tdma, res_tpu, res_tpusys 复位
    }
    
    fn dma_sync_for_device(&self, paddr: PhysAddr, size: usize) {
        // 刷新 CPU cache 到内存 (DMA_TO_DEVICE)
    }
    
    fn dma_sync_for_cpu(&self, paddr: PhysAddr, size: usize) {
        // 使 CPU cache 无效化 (DMA_FROM_DEVICE)
    }
}

// 2. 设备探测阶段 (probe)
fn tpu_probe() -> Result<TpuDevice<MyKernelFns>, TpuError> {
    // 从设备树获取寄存器地址
    let tdma_base = NonNull::new(0x0C00_0000 as *mut u8).unwrap();
    let tiu_base = NonNull::new(0x0C01_0000 as *mut u8).unwrap();
    
    let config = TpuConfig {
        pmu_buf_size: 0,      // PMU 缓冲区大小,0 表示禁用
        pmu_buf_paddr: 0,     // PMU 缓冲区物理地址
    };
    
    let kfns = MyKernelFns { /* ... */ };
    
    let mut tpu = TpuDevice::new(tdma_base, tiu_base, config, kfns);
    tpu.probe_setting();
    
    Ok(tpu)
}

// 3. 中断处理函数
fn tpu_irq_handler(tpu: &mut TpuDevice<MyKernelFns>) {
    let status = tpu.irq_handle();
    // 根据 status 处理中断
}

// 4. 执行一次 dmabuf 提交(StarryOS 驱动热路径)
fn submit_one_dmabuf(
    tpu: &mut TpuDevice<MyKernelFns>,
    dmabuf_vaddr: *const u8,
    dmabuf_len: usize,
    dmabuf_paddr: PhysAddr,
) -> Result<(), TpuError> {
    // dmabuf 结构解析已下沉到 tpu_sg2002
    let parsed = unsafe { parse_dmabuf_view(dmabuf_vaddr, dmabuf_len) }?;

    // 直接执行,header/descs 为零拷贝借用
    let result = tpu.run_dmabuf(dmabuf_paddr, parsed.header, parsed.descs);

    if let Err(TpuError::Timeout) = result {
        tpu.reset()?;
    }

    result
}

// 5. 电源管理(可选)
fn tpu_suspend(tpu: &mut TpuDevice<MyKernelFns>) -> Result<(), TpuError> {
    tpu.suspend()
}

fn tpu_resume(tpu: &mut TpuDevice<MyKernelFns>) -> Result<(), TpuError> {
    tpu.resume()
}

// 6. 用户态 ioctl 的典型顺序(伪代码)
fn user_ioctl_sequence_example() {
    // open("/dev/cvi-tpu0")
    // open("/dev/ion")
    // ION_IOC_ALLOC + mmap
    // ioctl(CVITPU_DMABUF_INVLD)
    // fill command buffer
    // ioctl(CVITPU_DMABUF_FLUSH)
    // ioctl(CVITPU_SUBMIT_DMABUF)
    // ioctl(CVITPU_WAIT_DMABUF)
}

KernelFns Trait

实现此 trait 以适配不同运行环境:

精简评估结论:

  • now_us 是硬性必需(超时与轮询逻辑核心依赖)。
  • enable_clocks/disable_clocks/reset 保留为可选钩子,符合不同 SoC 的电源域差异。
  • dma_sync_for_device/dma_sync_for_cpu 保留为可选钩子,用于兼容有 cache 维护要求的平台。
  • sleep_ms 在当前 SG2002 快路径不是必需;已调整为默认空实现,用于降低接入方实现负担。
pub trait KernelFns {
    /// 毫秒级睡眠
    fn sleep_ms(&self, _ms: u32) {}
    
    /// 获取微秒级单调时间戳
    fn now_us(&self) -> TimeStamp;
    
    /// 日志输出
    fn log(&self, level: LogLevel, msg: &str);
    
    /// 使能 TPU 时钟(可选)
    fn enable_clocks(&self) {}
    
    /// 关闭 TPU 时钟(可选)
    fn disable_clocks(&self) {}
    
    /// 复位 TPU 硬件(可选)
    fn reset(&self) {}

    // DMA 内存申请相关的函数

    /// DMA 缓存同步(可选)
    fn dma_sync_for_device(&self, _paddr: PhysAddr, _size: usize) {}
    fn dma_sync_for_cpu(&self, _paddr: PhysAddr, _size: usize) {}
}

编译

cargo build --target=riscv64gc-unknown-none-elf

Cache 指令的说明

SG2002 硬件板使用了 XuanTie C906/C910 CPU, 并支持一套丰富的 cache 维护指令。正确使用这些指令对于 DMA 数据一致性和性能至关重要。

常见术语

  • Clean / Writeback:把脏 cache line 回写到下一级存储,不一定无效该行
  • Invalidate:无效 cache line,不回写脏数据
  • Clean + Invalidate:先回写再无效
  • 全量操作:对整级 cache 生效(例如 dcache.call/dcache.ciall/dcache.iall)
  • 范围操作:对某段地址按 cache line 执行(例如 dcache.cpa/cipa/ipa)

推荐的Cache维护策略

场景 推荐操作 指令语义 本库 API
CPU 写完 DMA 缓冲,设备马上读(DMA_TO_DEVICE) 按物理地址 clean dcache.cpa cache::dcache_clean_range_by_pa(paddr, size)
设备写完 DMA 缓冲,CPU 马上读(DMA_FROM_DEVICE) 按物理地址 invalidate(或保守用 clean+invalidate) dcache.ipa / dcache.cipa cache::dcache_invalidate_range_by_pa(paddr, size)cache::dcache_clean_invalidate_range_by_pa(paddr, size)
双向 DMA 或方向不确定 按物理地址 clean+invalidate dcache.cipa cache::dcache_clean_invalidate_range_by_pa(paddr, size)
用户态 VA 与内核 VA 映射同一 PA(VA alias) 避免只做 VA 操作,优先 PA 或全量 dcache.cpa/cipa 或 dcache.call/ciall cache::dcache_clean_range_by_pa/cache::dcache_clean_invalidate_range_by_pacache::dcache_clean_all/cache::dcache_clean_invalidate_all
调试或异常恢复,需强制一次全局整理 全量 clean / clean+inv / inv dcache.call / dcache.ciall / dcache.iall cache::dcache_clean_all / cache::dcache_clean_invalidate_all / cache::dcache_invalidate_all

fence / sync 指令简述

  • fence:内存访问顺序屏障。它保证前后的读写顺序,不负责回写或无效 cache line。
  • fence iorw, iorw:更强顺序约束,常用于设备寄存器访问与 DMA 同步边界。
  • fence.i:指令流同步,保证后续取指看到新写入的代码;它不等价于 dcache clean/invalidate。
  • sync.is(Xuantie C910/C906 扩展):用于 cache 维护后的同步收敛,常与 dcache.cpa/cipa/ipa 配合使用。
  • sfence.vma:TLB 刷新相关,不是 cache 维护指令;通常在页表修改后使用。

实践建议:

  • 先做 cache 维护(cpa/cipa/ipa 或全量 call/ciall/iall),再做 sync.is / fence
  • 不要把 fence 当作 cache flush 的替代;fence 只管顺序,不管脏行回写。

参考

  • 原始 C 驱动的Linux 内核版本:5.10.4
  • HAL 实现:hal/mars(Mars 平台)
  • 设备树兼容字符串:cvitek,tpu

SG2002 硬件信息

资源 描述
TDMA 寄存器 设备树 tdma 资源
TIU 寄存器 设备树 tiu 资源
中断 平台中断 1 (TDMA)
时钟 clk_tpu_axi, clk_tpu_fab
复位 res_tdma, res_tpu, res_tpusys

说明

  • 需要实现 KernelFns trait 以提供平台相关功能
  • run_dmabuf 实现了 hal/mars 的核心提交流程
  • 该库不包含 Linux 设备模型与中断注册逻辑,由 RustOS 操作系统驱动框架提供
  • 不支持 TEE (安全执行环境)

About

TPU driver in Rust for SG2002 SoC.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages