1. 第一现场:DMA_CHANNEL_NPRIV 是怎么冒出来的
1.1 一次 DMA 通道申请失败的真实日志
先给个最典型的现场。嵌入式 Linux 板卡开机,外设驱动(音频、SPI、UART、存储控制器都常见)在 probe 阶段请求 DMA 通道,紧跟着 dmesg 里滚出一行类似这样的东西:
[ 3.245678] dma-pl330 fdb30000.dma-controller: DMA_CHANNEL_NPRIV [ 3.245712] spi1 1f0000.spi: failed to request DMA channel rx, err=-16如果是不带完整 dmesg 的全志/RK 系列 BSP,可能更简单,就一行 error,没有 errno,也没有 caller stack。很多人第一次看到DMA_CHANNEL_NPRIV会下意识先去搜 errno 表,结果-EINVAL、-EBUSY、-EPERM都对不上,因为这不是标准内核 errno,而是某个 DMA 控制器驱动或者厂商 BSP 自定义的错误码。
我在 RK 平台的 BSP 和 Zynq 平台的 FPGA 加速卡项目里都见过类似的报错,每次出现都差不多是同一个画面:外设 probe 走到一半,DMA 通道拿不到,整个设备直接 init 失败或者降级成 PIO 模式。这篇文章就是把这类问题的机制、排查方法和修复手段一次讲透,适合做嵌入式 Linux 驱动、BSP、FPGA+DMA 集成、音视频采集卡相关工作的同学参考。如果你只是写应用层代码,大概率不会碰它;一旦碰了,说明内核驱动这一层已经出问题了。
1.2 名字拆解:DMA_CHANNEL_NPRIV 的两个可能含义
先拆一下这个字符串。DMA 是 Direct Memory Access,CHANNEL 指 DMA 控制器里的通道,剩下的NPRIV是矛盾的焦点。我在不同板子上看到两种含义,都存在:
- 第一种是not private,指 DMA 通道的“独占属性”不满足。Linux dmaengine 里本来就有
DMA_PRIVATE能力位,表示这个通道是给某个固定外设专用的,不能随便给别的设备共享。 - 第二种是not privileged,指通道的“权限级别”不够。在带安全隔离的 SoC 上,DMA 通道可能被配置成 secure / non-secure,如果发起 DMA 的驱动进程或者 IOMMU 域没有