IOCTL 协议与数据结构

本章整理 RKNPU 驱动的全部 ioctl 命令、传参结构体布局、flags 枚举,以及 mmap(offset) 编码规则。


1. IOCTL 命令表

RKNPU 驱动提供 6 个 ioctl 命令,同时定义了两套编号:

命令编号DRM 路径宏非 DRM 路径宏方向结构体功能
ACTION0x00 DRM_IOCTL_RKNPU_ACTION IOCTL_RKNPU_ACTION IOWR rknpu_action 查询/设置:版本、频率、电压、电源、统计、复位等
SUBMIT0x01 DRM_IOCTL_RKNPU_SUBMIT IOCTL_RKNPU_SUBMIT IOWR rknpu_submit 提交 NPU 任务(PC job)
MEM_CREATE0x02 DRM_IOCTL_RKNPU_MEM_CREATE IOCTL_RKNPU_MEM_CREATE IOWR rknpu_mem_create 分配 DMA buffer(GEM 对象)
MEM_MAP0x03 DRM_IOCTL_RKNPU_MEM_MAP IOCTL_RKNPU_MEM_MAP IOWR rknpu_mem_map 获取 mmap 用的 fake offset
MEM_DESTROY0x04 DRM_IOCTL_RKNPU_MEM_DESTROY IOCTL_RKNPU_MEM_DESTROY IOWR rknpu_mem_destroy 释放 DMA buffer
MEM_SYNC0x05 DRM_IOCTL_RKNPU_MEM_SYNC IOCTL_RKNPU_MEM_SYNC IOWR rknpu_mem_sync Cache 同步(flush / invalidate)

1.1 两套编号的区别

DRM 路径非 DRM 路径
编码方式 DRM_IOWR(DRM_COMMAND_BASE + nr, type) _IOWR('r', nr, type)
设备节点 /dev/dri/cardX /dev/rknpu(如果驱动注册了)
调用方式 drmIoctl(fd, DRM_IOCTL_RKNPU_*, &arg) ioctl(fd, IOCTL_RKNPU_*, &arg)
闭源库使用 librknnrt.so 主要走此路径 备选

rknpu-ioctl.hRKNPU_IOC_MAGIC = 'r'DRM_COMMAND_BASE 来自 <libdrm/drm.h>(通常为 0x40)。


2. 结构体布局

2.1 struct rknpu_action(8 字节)

用于 ACTION ioctl,查询/设置各种属性。

偏移大小类型字段说明
0x004__u32flagsAction 编号(见 §3.4)
0x044__u32valueGET 时为返回值,SET 时为输入值

2.2 struct rknpu_mem_create(40 字节)

偏移大小类型字段方向说明
0x004__u32handleOUTGEM 对象句柄(驱动分配)
0x044__u32flagsIN内存类型 flags(见 §3.1)
0x088__u64sizeIN申请大小(内部页对齐)
0x108__u64obj_addrOUT内核对象地址(opaque token)
0x188__u64dma_addrOUT设备侧 DMA 地址(IOVA 或物理地址)
0x208__u64sram_sizeIN可选 SRAM 申请大小

StarryOS Rust 驱动 扩展了额外字段:iommu_domain_id: i32core_mask: u32,用于多核/IOMMU 域管理。

2.3 struct rknpu_mem_map(16 字节)

偏移大小类型字段方向说明
0x004__u32handleINGEM 句柄
0x044__u32reserved64 位对齐填充
0x088__u64offsetOUTfake offset,用于 mmap(fd, ..., offset)

2.4 struct rknpu_mem_destroy(16 字节)

偏移大小类型字段方向说明
0x004__u32handleINGEM 句柄
0x044__u32reserved填充
0x088__u64obj_addrIN内核对象地址

2.5 struct rknpu_mem_sync(32 字节)

偏移大小类型字段方向说明
0x004__u32flagsIN同步方向(见 §3.2)
0x044__u32reserved填充
0x088__u64obj_addrIN要同步的内核对象地址
0x108__u64offsetIN同步起始偏移(字节)
0x188__u64sizeIN同步区域大小

2.6 struct rknpu_task(36 字节,__packed

单个任务描述,由 PC 命令流引擎解释执行。

偏移大小类型字段说明
0x004__u32flags任务标志
0x044__u32op_idx算子索引
0x084__u32enable_mask模块使能掩码
0x0C4__u32int_mask期望的完成中断掩码
0x104__u32int_clear中断清除值
0x144__u32int_status完成后驱动写回实际中断状态
0x184__u32regcfg_amount寄存器配置项数量
0x1C4__u32regcfg_offset寄存器配置在命令流中的偏移
0x208__u64regcmd_addr寄存器命令流 DMA 地址

__packed:编译器不插入 padding,保证与内核侧布局一致。

2.7 struct rknpu_subcore_task(8 字节)

偏移大小类型字段说明
0x004__u32task_start该子核心的起始 task 索引
0x044__u32task_number该子核心要执行的 task 数量

2.8 struct rknpu_submit(96 字节)

任务提交主结构体,驱动最核心的入口。

偏移大小类型字段说明
0x004__u32flagsJob 模式(见 §3.3)
0x044__u32timeout超时时间(ms)
0x084__u32task_start全局起始 task 索引
0x0C4__u32task_number全局 task 数量
0x104__u32task_counter计数/序列号
0x144__s32priority调度优先级
0x188__u64task_obj_addrtask 数组的内核对象地址
0x208__u64regcfg_obj_addr寄存器配置对象地址
0x288__u64task_base_addrtask 基址(设备侧)
0x308__u64user_data可选用户数据(透传/调试)
0x384__u32core_mask核心选择掩码(bit0=core0, bit1=core1, bit2=core2)
0x3C4__s32fence_fddma-fence fd(IN: fence_in, OUT: fence_out)
0x4040subcore_task[5]subcore_task5 组子核心任务分配

StarryOS Rust 驱动 变体:将 regcfg_obj_addr 替换为 iommu_domain_id + reserved,并增加 hw_elapse_time 字段。


3. Flags 枚举

3.1 enum e_rknpu_mem_type(内存类型,位掩码)

名称说明
0 << 0CONTIGUOUS物理连续(默认)
1 << 0NON_CONTIGUOUS物理不连续
0 << 1NON_CACHEABLE不可缓存(默认)
1 << 1CACHEABLE可缓存
1 << 2WRITE_COMBINEWrite-Combine 映射
1 << 3KERNEL_MAPPING内核态映射
1 << 4IOMMUIOMMU 映射
1 << 5ZEROING分配后清零
1 << 6SECURE安全内存
1 << 7NON_DMA32不限于 DMA32 区域
1 << 8TRY_ALLOC_SRAM尝试分配 SRAM

MEM_MASK = 0x1FF(bit0~bit8 的合法组合集)

3.2 enum e_rknpu_mem_sync_mode(Cache 同步方向)

名称说明
1 << 0SYNC_TO_DEVICECPU → 设备:flush cache
1 << 1SYNC_FROM_DEVICE设备 → CPU:invalidate cache

3.3 enum e_rknpu_job_mode(Job 模式,位掩码)

名称说明
0 << 0SLAVE从模式(默认)
1 << 0PCPC(Program Counter)模式
0 << 1BLOCK阻塞等待完成(默认)
1 << 1NONBLOCK非阻塞返回
1 << 2PINGPONG双缓冲/流水模式
1 << 3FENCE_IN等待输入 fence
1 << 4FENCE_OUT返回输出 fence fd

3.4 enum e_rknpu_action(Action 编号)

编号名称方向说明
0GET_HW_VERSIONGET读取硬件版本
1GET_DRV_VERSIONGET读取驱动版本(编码:major*10000+minor*100+patch)
2GET_FREQGET读取当前频率
3SET_FREQSET设置频率
4GET_VOLTGET读取电压
5SET_VOLTSET设置电压
6ACT_RESETACTNPU 软复位
7GET_BW_PRIORITYGET带宽优先级
8SET_BW_PRIORITYSET设置带宽优先级
9GET_BW_EXPECTGET期望带宽
10SET_BW_EXPECTSET设置期望带宽
11GET_BW_TWGET带宽时间窗
12SET_BW_TWSET设置带宽时间窗
13ACT_CLR_TOTAL_RW_AMOUNTACT清除读写量统计
14GET_DT_WR_AMOUNTGET数据写入量
15GET_DT_RD_AMOUNTGET数据读取量
16GET_WT_RD_AMOUNTGET权重读取量
17GET_TOTAL_RW_AMOUNTGET总读写量
18GET_IOMMU_ENGETIOMMU 是否启用
19SET_PROC_NICESET进程优先级
20POWER_ONACTNPU 上电
21POWER_OFFACTNPU 下电
22GET_TOTAL_SRAM_SIZEGETSRAM 总大小
23GET_FREE_SRAM_SIZEGETSRAM 空闲大小
24GET_IOMMU_DOMAIN_IDGETStarryOS 扩展
25SET_IOMMU_DOMAIN_IDSETStarryOS 扩展

4. mmap 规则(handle → offset 编码)

4.1 流程

sequenceDiagram
    participant U as 用户态
    participant K as 内核驱动

    U->>K: ioctl(MEM_CREATE, {size, flags})
    K-->>U: {handle, obj_addr, dma_addr}

    U->>K: ioctl(MEM_MAP, {handle})
    K-->>U: {offset}

    U->>U: ptr = mmap(fd, size, PROT_RW, MAP_SHARED, fd, offset)
    Note over U: 现在 ptr 指向 DMA buffer 的用户态映射

    U->>K: ioctl(MEM_SYNC, {obj_addr, offset=0, size, flags=TO_DEVICE})
    Note over K: flush CPU cache → 设备可见

    Note over U,K: ... 使用 buffer(填充数据 / 读取结果)...

    U->>K: ioctl(MEM_DESTROY, {handle, obj_addr})
    Note over K: 释放 GEM 对象 + DMA 内存

4.2 offset 编码约定

Linux rknpu 驱动 中,MEM_MAP 返回的 offset 是 DRM GEM 的 fake offset

  • drm_gem_create_mmap_offset() 生成
  • 编码方式:offset = handle_to_node_offset(DRM 内部维护的映射表)
  • 用户态拿到 offset 后,传给 mmap() 的最后一个参数
  • 内核在 drm_gem_mmap() 中根据 offset 查找对应的 GEM 对象,建立页表映射

StarryOS 实现:由于没有完整 DRM 框架,需要自行维护 handle → 物理页的映射表,并在 sys_mmapDeviceMmap::Physical 路径中完成映射。

4.3 对齐要求

  • size:内部页对齐(4KB)
  • offset:必须页对齐
  • dma_addr:取决于是否启用 IOMMU
    • 有 IOMMU:返回 IOVA(设备虚拟地址)
    • 无 IOMMU:返回物理地址(需物理连续)