Linux:DMA 控制器传输异常案例

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 背景

本文基于 ARMv8 架构、Linux 6.1.75 进行分析,DMA 控制器(DMAC: DMA Controller)为 ARMPL330

3. 案例情景和分析

DMA 控制器(DMAC: DMA ControllerPL330 驱动加载信息如下:

[    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

可见,系统集成了 3DMAC(DMA Controller),各有 8 个通道,缓冲大小为 128x8bytes

当笔者在一个音频测试程序尝试使用 70 个采样长度的 period_size 时,DMACSAI 驱动均报告了错误信息:

[  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 的值即可,譬如调为 512mcbufsz 参数的含义,可以参考 PL330 手册

posted @ 2025-04-07 10:00  JiMoKuangXiangQu  阅读(65)  评论(0)    收藏  举报