本章整理 RKNPU 驱动的全部 ioctl 命令、传参结构体布局、flags 枚举,以及 mmap(offset) 编码规则。
RKNPU 驱动提供 6 个 ioctl 命令,同时定义了两套编号:
| 命令 | 编号 | DRM 路径宏 | 非 DRM 路径宏 | 方向 | 结构体 | 功能 |
| ACTION | 0x00 |
DRM_IOCTL_RKNPU_ACTION |
IOCTL_RKNPU_ACTION |
IOWR |
rknpu_action |
查询/设置:版本、频率、电压、电源、统计、复位等 |
| SUBMIT | 0x01 |
DRM_IOCTL_RKNPU_SUBMIT |
IOCTL_RKNPU_SUBMIT |
IOWR |
rknpu_submit |
提交 NPU 任务(PC job) |
| MEM_CREATE | 0x02 |
DRM_IOCTL_RKNPU_MEM_CREATE |
IOCTL_RKNPU_MEM_CREATE |
IOWR |
rknpu_mem_create |
分配 DMA buffer(GEM 对象) |
| MEM_MAP | 0x03 |
DRM_IOCTL_RKNPU_MEM_MAP |
IOCTL_RKNPU_MEM_MAP |
IOWR |
rknpu_mem_map |
获取 mmap 用的 fake offset |
| MEM_DESTROY | 0x04 |
DRM_IOCTL_RKNPU_MEM_DESTROY |
IOCTL_RKNPU_MEM_DESTROY |
IOWR |
rknpu_mem_destroy |
释放 DMA buffer |
| MEM_SYNC | 0x05 |
DRM_IOCTL_RKNPU_MEM_SYNC |
IOCTL_RKNPU_MEM_SYNC |
IOWR |
rknpu_mem_sync |
Cache 同步(flush / invalidate) |
| 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.h 中 RKNPU_IOC_MAGIC = 'r',DRM_COMMAND_BASE 来自 <libdrm/drm.h>(通常为 0x40)。
用于 ACTION ioctl,查询/设置各种属性。
| 偏移 | 大小 | 类型 | 字段 | 说明 |
0x00 | 4 | __u32 | flags | Action 编号(见 §3.4) |
0x04 | 4 | __u32 | value | GET 时为返回值,SET 时为输入值 |
| 偏移 | 大小 | 类型 | 字段 | 方向 | 说明 |
0x00 | 4 | __u32 | handle | OUT | GEM 对象句柄(驱动分配) |
0x04 | 4 | __u32 | flags | IN | 内存类型 flags(见 §3.1) |
0x08 | 8 | __u64 | size | IN | 申请大小(内部页对齐) |
0x10 | 8 | __u64 | obj_addr | OUT | 内核对象地址(opaque token) |
0x18 | 8 | __u64 | dma_addr | OUT | 设备侧 DMA 地址(IOVA 或物理地址) |
0x20 | 8 | __u64 | sram_size | IN | 可选 SRAM 申请大小 |
StarryOS Rust 驱动 扩展了额外字段:iommu_domain_id: i32、core_mask: u32,用于多核/IOMMU 域管理。
| 偏移 | 大小 | 类型 | 字段 | 方向 | 说明 |
0x00 | 4 | __u32 | handle | IN | GEM 句柄 |
0x04 | 4 | __u32 | reserved | — | 64 位对齐填充 |
0x08 | 8 | __u64 | offset | OUT | fake offset,用于 mmap(fd, ..., offset) |
| 偏移 | 大小 | 类型 | 字段 | 方向 | 说明 |
0x00 | 4 | __u32 | handle | IN | GEM 句柄 |
0x04 | 4 | __u32 | reserved | — | 填充 |
0x08 | 8 | __u64 | obj_addr | IN | 内核对象地址 |
| 偏移 | 大小 | 类型 | 字段 | 方向 | 说明 |
0x00 | 4 | __u32 | flags | IN | 同步方向(见 §3.2) |
0x04 | 4 | __u32 | reserved | — | 填充 |
0x08 | 8 | __u64 | obj_addr | IN | 要同步的内核对象地址 |
0x10 | 8 | __u64 | offset | IN | 同步起始偏移(字节) |
0x18 | 8 | __u64 | size | IN | 同步区域大小 |
单个任务描述,由 PC 命令流引擎解释执行。
| 偏移 | 大小 | 类型 | 字段 | 说明 |
0x00 | 4 | __u32 | flags | 任务标志 |
0x04 | 4 | __u32 | op_idx | 算子索引 |
0x08 | 4 | __u32 | enable_mask | 模块使能掩码 |
0x0C | 4 | __u32 | int_mask | 期望的完成中断掩码 |
0x10 | 4 | __u32 | int_clear | 中断清除值 |
0x14 | 4 | __u32 | int_status | 完成后驱动写回实际中断状态 |
0x18 | 4 | __u32 | regcfg_amount | 寄存器配置项数量 |
0x1C | 4 | __u32 | regcfg_offset | 寄存器配置在命令流中的偏移 |
0x20 | 8 | __u64 | regcmd_addr | 寄存器命令流 DMA 地址 |
__packed:编译器不插入 padding,保证与内核侧布局一致。
| 偏移 | 大小 | 类型 | 字段 | 说明 |
0x00 | 4 | __u32 | task_start | 该子核心的起始 task 索引 |
0x04 | 4 | __u32 | task_number | 该子核心要执行的 task 数量 |
任务提交主结构体,驱动最核心的入口。
| 偏移 | 大小 | 类型 | 字段 | 说明 |
0x00 | 4 | __u32 | flags | Job 模式(见 §3.3) |
0x04 | 4 | __u32 | timeout | 超时时间(ms) |
0x08 | 4 | __u32 | task_start | 全局起始 task 索引 |
0x0C | 4 | __u32 | task_number | 全局 task 数量 |
0x10 | 4 | __u32 | task_counter | 计数/序列号 |
0x14 | 4 | __s32 | priority | 调度优先级 |
0x18 | 8 | __u64 | task_obj_addr | task 数组的内核对象地址 |
0x20 | 8 | __u64 | regcfg_obj_addr | 寄存器配置对象地址 |
0x28 | 8 | __u64 | task_base_addr | task 基址(设备侧) |
0x30 | 8 | __u64 | user_data | 可选用户数据(透传/调试) |
0x38 | 4 | __u32 | core_mask | 核心选择掩码(bit0=core0, bit1=core1, bit2=core2) |
0x3C | 4 | __s32 | fence_fd | dma-fence fd(IN: fence_in, OUT: fence_out) |
0x40 | 40 | subcore_task[5] | subcore_task | 5 组子核心任务分配 |
StarryOS Rust 驱动 变体:将 regcfg_obj_addr 替换为 iommu_domain_id + reserved,并增加 hw_elapse_time 字段。
| 值 | 名称 | 说明 |
0 << 0 | CONTIGUOUS | 物理连续(默认) |
1 << 0 | NON_CONTIGUOUS | 物理不连续 |
0 << 1 | NON_CACHEABLE | 不可缓存(默认) |
1 << 1 | CACHEABLE | 可缓存 |
1 << 2 | WRITE_COMBINE | Write-Combine 映射 |
1 << 3 | KERNEL_MAPPING | 内核态映射 |
1 << 4 | IOMMU | IOMMU 映射 |
1 << 5 | ZEROING | 分配后清零 |
1 << 6 | SECURE | 安全内存 |
1 << 7 | NON_DMA32 | 不限于 DMA32 区域 |
1 << 8 | TRY_ALLOC_SRAM | 尝试分配 SRAM |
MEM_MASK = 0x1FF(bit0~bit8 的合法组合集)
| 值 | 名称 | 说明 |
1 << 0 | SYNC_TO_DEVICE | CPU → 设备:flush cache |
1 << 1 | SYNC_FROM_DEVICE | 设备 → CPU:invalidate cache |
| 值 | 名称 | 说明 |
0 << 0 | SLAVE | 从模式(默认) |
1 << 0 | PC | PC(Program Counter)模式 |
0 << 1 | BLOCK | 阻塞等待完成(默认) |
1 << 1 | NONBLOCK | 非阻塞返回 |
1 << 2 | PINGPONG | 双缓冲/流水模式 |
1 << 3 | FENCE_IN | 等待输入 fence |
1 << 4 | FENCE_OUT | 返回输出 fence fd |
| 编号 | 名称 | 方向 | 说明 |
| 0 | GET_HW_VERSION | GET | 读取硬件版本 |
| 1 | GET_DRV_VERSION | GET | 读取驱动版本(编码:major*10000+minor*100+patch) |
| 2 | GET_FREQ | GET | 读取当前频率 |
| 3 | SET_FREQ | SET | 设置频率 |
| 4 | GET_VOLT | GET | 读取电压 |
| 5 | SET_VOLT | SET | 设置电压 |
| 6 | ACT_RESET | ACT | NPU 软复位 |
| 7 | GET_BW_PRIORITY | GET | 带宽优先级 |
| 8 | SET_BW_PRIORITY | SET | 设置带宽优先级 |
| 9 | GET_BW_EXPECT | GET | 期望带宽 |
| 10 | SET_BW_EXPECT | SET | 设置期望带宽 |
| 11 | GET_BW_TW | GET | 带宽时间窗 |
| 12 | SET_BW_TW | SET | 设置带宽时间窗 |
| 13 | ACT_CLR_TOTAL_RW_AMOUNT | ACT | 清除读写量统计 |
| 14 | GET_DT_WR_AMOUNT | GET | 数据写入量 |
| 15 | GET_DT_RD_AMOUNT | GET | 数据读取量 |
| 16 | GET_WT_RD_AMOUNT | GET | 权重读取量 |
| 17 | GET_TOTAL_RW_AMOUNT | GET | 总读写量 |
| 18 | GET_IOMMU_EN | GET | IOMMU 是否启用 |
| 19 | SET_PROC_NICE | SET | 进程优先级 |
| 20 | POWER_ON | ACT | NPU 上电 |
| 21 | POWER_OFF | ACT | NPU 下电 |
| 22 | GET_TOTAL_SRAM_SIZE | GET | SRAM 总大小 |
| 23 | GET_FREE_SRAM_SIZE | GET | SRAM 空闲大小 |
| 24 | GET_IOMMU_DOMAIN_ID | GET | StarryOS 扩展 |
| 25 | SET_IOMMU_DOMAIN_ID | SET | StarryOS 扩展 |
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 内存
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_mmap 的 DeviceMmap::Physical 路径中完成映射。
size:内部页对齐(4KB)
offset:必须页对齐
dma_addr:取决于是否启用 IOMMU
- 有 IOMMU:返回 IOVA(设备虚拟地址)
- 无 IOMMU:返回物理地址(需物理连续)