Linux内核 -- DMA控制器之dmaengine框架的注册与使用流程

Linux Kernel dmaengine 框架

简介

Linux内核的dmaengine框架是一个用于管理DMA(Direct Memory Access)操作的通用框架。它抽象了不同DMA控制器的实现,使得上层代码可以方便地进行DMA传输。

初始化流程

1. 驱动注册

每个DMA控制器驱动都需要注册为一个dma_device,并将其操作接口(如device_alloc_chan_resourcesdevice_free_chan_resources等)填充到dma_device结构中。使用dma_async_device_register函数将dma_device注册到dmaengine框架中。

struct dma_device *dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL);
dma_dev->dev = &pdev->dev; // Platform device's dev
dma_dev->device_alloc_chan_resources = my_alloc_chan_resources;
dma_dev->device_free_chan_resources = my_free_chan_resources;
dma_dev->device_prep_slave_sg = my_prep_slave_sg;
dma_async_device_register(dma_dev);

2. 通道初始化

DMA控制器通常包含多个DMA通道,每个通道需要注册到dmaengine框架。使用dma_async_tx_descriptor结构描述每个传输通道的属性。使用dma_cookie_t机制跟踪传输的状态。

3. DMA过滤器函数

注册DMA控制器时,可以提供一个过滤器函数,用于选择合适的DMA通道。这在请求特定类型的DMA通道时特别有用。

使用方法

1. 请求DMA通道

使用dma_request_chan函数请求一个DMA通道。可以指定一个过滤器函数来选择通道。

struct dma_chan *chan;
chan = dma_request_chan(dev, "my_dma_channel");
if (IS_ERR(chan)) {
    // Handle error
}

2. 准备DMA传输

使用dmaengine_prep_slave_sg函数准备DMA传输。这个函数会返回一个dma_async_tx_descriptor结构。

struct dma_async_tx_descriptor *tx;
tx = dmaengine_prep_slave_sg(chan, sg, sg_len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);

3. 提交传输并启动

使用dmaengine_submit提交传输,并使用dma_async_issue_pending启动传输。

dma_cookie_t cookie;
cookie = tx->tx_submit(tx);
dma_async_issue_pending(chan);

4. 传输完成回调

可以在dma_async_tx_descriptor中设置回调函数,以便在传输完成时通知上层代码。

tx->callback = my_dma_callback;
tx->callback_param = my_param;

注意事项

1. 错误处理

在请求DMA通道、准备传输和提交传输时都需要处理可能的错误。例如,dma_request_chan返回ERR_PTR类型的错误码,必须检查。

2. 缓存一致性

如果DMA传输涉及缓存(例如,DMA从内存中读取数据),需要确保数据在传输前后的一致性。通常可以使用dma_map_singledma_unmap_single等函数。

3. 资源释放

使用完成后,需要释放DMA通道资源,使用dma_release_channel释放请求的通道。

dma_release_channel(chan);

4. 中断处理

DMA传输通常依赖中断来通知传输完成,因此需要确保中断处理正确配置。

5. 同步操作

DMA操作是异步的,因此在某些情况下需要同步等待传输完成,可以使用dma_sync_wait函数。

dma_sync_wait(chan, cookie);

示例代码

struct dma_chan *chan;
struct dma_async_tx_descriptor *tx;
dma_cookie_t cookie;
struct scatterlist sg;

// 请求DMA通道
chan = dma_request_chan(dev, "my_dma_channel");
if (IS_ERR(chan)) {
    // 处理错误
}

// 准备DMA传输
tx = dmaengine_prep_slave_sg(chan, &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!tx) {
    // 处理错误
}

// 设置传输完成回调
tx->callback = my_dma_callback;
tx->callback_param = my_param;

// 提交传输
cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
    // 处理错误
}

// 启动传输
dma_async_issue_pending(chan);

// 等待传输完成
dma_sync_wait(chan, cookie);

// 释放DMA通道
dma_release_channel(chan);
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值