Linux:DMA 控制器传输异常案例
1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. 背景
本文基于 ARMv8 架构、Linux 6.1.75 进行分析,DMA 控制器(DMAC: DMA Controller)为 ARM 的 PL330 。
3. 案例情景和分析
DMA 控制器(DMAC: DMA Controller)PL330 驱动加载信息如下:
[ 4.594541] dma-pl330 2ab90000.dma-controller: Loaded driver for PL330 DMAC-241330
[ 4.594545] dma-pl330 2ab90000.dma-controller: DBUFF-128x8bytes Num_Chans-8 Num_Peri-32 Num_Events-16
[ 4.595296] dma-pl330 2abb0000.dma-controller: Loaded driver for PL330 DMAC-241330
[ 4.595300] dma-pl330 2abb0000.dma-controller: DBUFF-128x8bytes Num_Chans-8 Num_Peri-32 Num_Events-16
[ 4.596022] dma-pl330 2abd0000.dma-controller: Loaded driver for PL330 DMAC-241330
[ 4.596026] dma-pl330 2abd0000.dma-controller: DBUFF-128x8bytes Num_Chans-8 Num_Peri-32 Num_Events-16
可见,系统集成了 3 路 DMAC(DMA Controller),各有 8 个通道,缓冲大小为 128x8bytes 。
当笔者在一个音频测试程序尝试使用 70 个采样长度的 period_size 时,DMAC 和 SAI 驱动均报告了错误信息:
[ 210.187210] dma-pl330 2ab90000.dma-controller: pl330_submit_req:1722 Try increasing mcbufsz (280/256)
[ 210.187220] dma-pl330 2ab90000.dma-controller: fill_queue:2248 Bad Desc(4)
[ 210.187294] dma-pl330 2ab90000.dma-controller: pl330_submit_req:1722 Try increasing mcbufsz (280/256)
[ 210.187299] dma-pl330 2ab90000.dma-controller: fill_queue:2248 Bad Desc(4)
[ 210.187330] rockchip-sai 2a610000.sai: TX FIFO Underrun
[ 210.190066] rockchip-sai 2a610000.sai: RX FIFO Overrun
......
对应 PL330 驱动出错代码:
/* drivers/dma/pl330.c */
/*
* Submit a list of xfers after which the client wants notification.
* Client is not notified after each xfer unit, just once after all
* xfer units are done or some error occurs.
*/
static int pl330_submit_req(struct pl330_thread *thrd,
struct dma_pl330_desc *desc)
{
...
/* 当程序指令的字节数超过所分配的系统内存一半大小时出错 */
if (ret > pl330->mcbufsz / 2) {
dev_info(pl330->ddma.dev, "%s:%d Try increasing mcbufsz (%i/%i)\n",
__func__, __LINE__, ret, pl330->mcbufsz / 2);
ret = -ENOMEM;
goto xfer_exit;
}
...
}
而 mcbufsz 的设置在 PL330 驱动加载时:
/* drivers/dma/pl330.c */
pl330_probe()
pl330_add()
/*
* With 256 bytes, we can do more than 2.5MB and 5MB xfers per req
* at 1byte/burst for P<->M and M<->M respectively.
* For typical scenario, at 1word/burst, 10MB and 20MB xfers per req
* should be enough for P<->M and M<->M respectively.
*/
#define MCODE_BUFF_PER_REQ 256
static int pl330_add(struct pl330_dmac *pl330)
{
...
/* Use default MC buffer size if not provided */
if (!pl330->mcbufsz)
pl330->mcbufsz = MCODE_BUFF_PER_REQ * 2;
...
}
修正问题的方法是调大 MCODE_BUFF_PER_REQ 的值即可,譬如调为 512 。mcbufsz 参数的含义,可以参考 PL330 手册。

浙公网安备 33010602011771号