Linux内核 -- 内存管理之scatterlist结构使用

Linux Kernel Scatterlist 使用指南

1. 简介

scatterlist 结构在 Linux 内核中主要用于 DMA(直接内存访问)操作中的内存管理。它允许将不连续的物理内存片段表示为一个逻辑上的连续块,从而使 DMA 操作可以高效地处理这些不连续的内存片段。

2. 设计思想

在 DMA 操作中,数据的源或目标可能分散在物理内存的不同位置。scatterlist 提供了一种机制,将这些分散的内存片段组合在一起,使 DMA 控制器能够处理这些数据,从而提高内存操作的效率和灵活性。

3. scatterlist 结构

scatterlist 结构体定义在 <linux/scatterlist.h> 头文件中,主要成员包括:

struct scatterlist {
    unsigned long   page_link;
    unsigned int    offset;
    dma_addr_t      dma_address;
    unsigned int    length;
};
  • page_link:指向内存页的指针及一些标志。
  • offset:内存页内的偏移量。
  • dma_address:DMA 设备使用的地址。
  • length:此段内存的长度。

4. 使用步骤

使用 scatterlist 主要包括以下几个步骤:

4.1 初始化 scatterlist

在使用 scatterlist 之前,需要先分配并初始化它。

struct scatterlist *sg;
int nents = 10; // Scatterlist 条目的数量

sg = kmalloc_array(nents, sizeof(*sg), GFP_KERNEL);
if (!sg)
    return -ENOMEM;

sg_init_table(sg, nents);

4.2 填充 scatterlist

将内存区域填充到 scatterlist 中。

for (i = 0; i < nents; i++) {
    sg_set_page(&sg[i], page, PAGE_SIZE, 0);
}

4.3 映射 scatterlist 到 DMA 地址空间

在进行 DMA 传输之前,需要将 scatterlist 映射到 DMA 地址空间。

dma_addr_t dma_handle;
dma_handle = dma_map_sg(dev, sg, nents, DMA_TO_DEVICE);

4.4 传输数据

使用映射后的 scatterlist 进行 DMA 数据传输。此步骤取决于你的具体 DMA 控制器和驱动程序。以下是一个简单的示例,假设你的 DMA 控制器支持 dmaengine 框架:

struct dma_async_tx_descriptor *tx;
dma_cookie_t cookie;
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
struct dma_chan *chan = /* your DMA channel */;

tx = dmaengine_prep_slave_sg(chan, sg, dma_nents, DMA_MEM_TO_DEV, flags);
if (!tx) {
    pr_err("Failed to prepare DMA transfer\n");
    goto unmap;
}

cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
    pr_err("Failed to submit DMA transfer\n");
    goto unmap;
}

dma_async_issue_pending(chan);

// 等待DMA传输完成(可以是中断或轮询)

4.5 解除映射

传输完成后,需要解除 scatterlist 的 DMA 映射。

dma_unmap_sg(dev, sg, nents, DMA_TO_DEVICE);

5. 注意事项

  1. 内存分配:确保分配的内存足够大,可以容纳所有的 scatterlist 条目。
  2. 映射和解除映射:确保在使用前正确映射 scatterlist,传输完成后及时解除映射,以防止内存泄漏或数据损坏。
  3. 内存对齐:确保内存地址和长度满足 DMA 控制器的对齐要求。
  4. 错误处理:处理好内存分配失败和 DMA 操作失败的情况。

6. 示例代码

以下是一个完整的示例,展示了如何使用 scatterlist 进行 DMA 操作:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>

static int __init my_module_init(void)
{
    struct scatterlist *sg;
    int nents = 10;
    int i;
    dma_addr_t dma_handle;
    struct device *dev = /* your device */;
    struct page *page;

    sg = kmalloc_array(nents, sizeof(*sg), GFP_KERNEL);
    if (!sg)
        return -ENOMEM;

    sg_init_table(sg, nents);

    for (i = 0; i < nents; i++) {
        page = alloc_page(GFP_KERNEL);
        if (!page) {
            pr_err("Failed to allocate page
");
            goto out;
        }
        sg_set_page(&sg[i], page, PAGE_SIZE, 0);
    }

    dma_handle = dma_map_sg(dev, sg, nents, DMA_TO_DEVICE);
    if (!dma_handle) {
        pr_err("Failed to map scatterlist
");
        goto out;
    }

    // Perform DMA operation here

    dma_unmap_sg(dev, sg, nents, DMA_TO_DEVICE);

out:
    for (i = 0; i < nents; i++) {
        if (sg[i].page_link)
            __free_page(sg_page(&sg[i]));
    }
    kfree(sg);

    return 0;
}

static void __exit my_module_exit(void)
{
    // Cleanup code here
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Scatterlist Example");

这个示例展示了如何分配、初始化、填充、映射和解除映射 scatterlist 进行 DMA 操作。根据具体需求,你可以在 DMA 操作中添加更多的处理逻辑。

相关推荐

  1. Linux内核 -- 内存管理scatterlist结构使用

    2024-07-10 10:26:04       52 阅读
  2. 深入理解Linux 内核 内存管理(上)

    2024-07-10 10:26:04       25 阅读
  3. Linux | 数据结构内核链表

    2024-07-10 10:26:04       70 阅读
  4. Linux 内核源码分析】物理内存组织结构

    2024-07-10 10:26:04       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 10:26:04       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 10:26:04       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 10:26:04       90 阅读
  4. Python语言-面向对象

    2024-07-10 10:26:04       98 阅读

热门阅读

  1. 【国产开源可视化引擎Meta2d.js】数据

    2024-07-10 10:26:04       27 阅读
  2. Elasticsearch 面试题指南

    2024-07-10 10:26:04       26 阅读
  3. Linux笔记之iftop查看特定IP地址吞吐量

    2024-07-10 10:26:04       23 阅读
  4. 量化交易在不同经济周期中的表现

    2024-07-10 10:26:04       29 阅读
  5. Kotlin构造函数

    2024-07-10 10:26:04       30 阅读
  6. 生日判断星座【GO】

    2024-07-10 10:26:04       26 阅读
  7. SQL Server设置端口:跨平台指南

    2024-07-10 10:26:04       26 阅读
  8. 指定版本ceph-common安装

    2024-07-10 10:26:04       29 阅读
  9. 中科海讯 C++初级研发工程师笔试题目

    2024-07-10 10:26:04       36 阅读
  10. vue3的常用 Composition API有哪些?

    2024-07-10 10:26:04       26 阅读
  11. Linux系统基础命令行指令——Ubuntu

    2024-07-10 10:26:04       34 阅读