scatterlist

news2024/11/24 20:34:52

在内核驱动程序的很多代码中,都能够看到类似sgdma的内容,sgdma全称为Scatter/Gather DMA(散列/收集 DMA),内核中抽象了scatterlist和sg table用来描述和管理这种需要做散列和收集的DMA缓冲区。在内核中设计scatterlist,主要出于两方面的原因,从硬件层面来说,目前很多DMA控制器都支持硬件的SG DMA模式,由开发人员在内存中构建一个链式的DMA缓冲区描述符(Buffer Descriptor, BD),DMA控制器根据这个链式BD进行一对多、多对一或者多对多的拷贝操作。例如Xilinx的AXI DMA IPCore,参考PG021文档中的介绍,该IP核的Block Diagram中就集成了Scatter/Gather逻辑电路

 使能了SG模式后的DMA BD描述符,其内部有一个Next字段,用于指向下一个描述符的地址,控制器通过这个Next字段即可遍历整个BD链,而遍历过程完全是由硬件完成,软件只需要构造这个BD链

 Gather是将多个离散的buffers拷贝到一个连续的buffer中

 Scatter是将一个连续的buffer拷贝到多个离散的buffers中

 从软件层面来说,对于存在虚拟内存管理的系统而言,由应用程序创建的大内存块在虚拟地址空间中是连续的,但是在物理内存的层面,大概率是离散的,而如果想要在一个单独的I/O操作中搬运这些由应用层创建的物理非连续buffer,比较笨重的办法是申请与其大小相当的连续物理页面,并将数据先拷贝到这些物理页面上,然后再进行DMA操作。但是这样做的缺陷也很明显,一方面是增加了数据拷贝的过程,性能较差,另一方面是增加了对连续物理页面资源的要求,在长时间使用过后碎片化严重的物理内存中,申请一大块连续物理内存会非常困难。使用scatterlist,结合DMA的SG功能,能够非常有效的节省对大块连续物理内存的要求,也避免了不必要的额外拷贝过程

数据结构

刚接触scatterlist的朋友可能容易被这个结构体的名字误导,scatterlist本身并不是一种链表结构,而只是用于描述一个单独的内存块

struct scatterlist {
#ifdef CONFIG_DEBUG_SG
        unsigned long   sg_magic;
#endif
        unsigned long   page_link;
        unsigned int    offset;
        unsigned int    length;
        dma_addr_t      dma_address;
#ifdef CONFIG_NEED_SG_DMA_LENGTH
        unsigned int    dma_length;
#endif
};

page_link用于记录该内存块所在的页面号,page_link的bit[0]和bit[1]有特殊用途,因此页面必须是4字节对齐的。bit[0]为1表示该节点是一个铰链,为0表示一个普通内存节点,铰链是用于将多个链串成一个更大的链。bit[1]为1表示该节点是尾节点,为0表示一个普通节点。offset表示内存块在页面内的偏移,length表示内存块长度,dma_address表示物理地址

要使用scatterlist,开发者可以自己定义一个scatterlist的数组

struct scatterlist sgt[8];

也可以使用内核提供好的封装后的sg table结构

struct sg_table {
	struct scatterlist *sgl;	/* the list */
	unsigned int nents;		/* number of mapped entries */
	unsigned int orig_nents;	/* original size of list */
};

其中sgl是一个指向scatterlist数组的指针,nents是scatterlist数组的长度,orig_nents是scatterlist的原始长度

创建

创建一个scatterlist链有两种方式,一种是静态声明,并调用API进行初始化

struct scatterlist sgt[8];
sg_init_table(sgt, 8);

sg_init_table()函数定义如下

/**
 * sg_init_table - Initialize SG table
 * @sgl:	   The SG table
 * @nents:	   Number of entries in table
 *
 * Notes:
 *   If this is part of a chained sg table, sg_mark_end() should be
 *   used only on the last table part.
 *
 **/
void sg_init_table(struct scatterlist *sgl, unsigned int nents)
{
	memset(sgl, 0, sizeof(*sgl) * nents);
#ifdef CONFIG_DEBUG_SG
	{
		unsigned int i;
		for (i = 0; i < nents; i++)
			sgl[i].sg_magic = SG_MAGIC;
	}
#endif
	sg_mark_end(&sgl[nents - 1]);
}
EXPORT_SYMBOL(sg_init_table);

传入的参数sgl是scatterlist的数组地址,nents是数组长度,函数内部将数组内存初始化,然后调用了sg_mark_end将数组的最后一个元素的page_link标记为尾节点

另一种方法是动态创建

struct sg_table sgt;
sg_alloc_table(&sgt, 8, GFP_KERNEL);

 sg_alloc_table()函数定义如下

/**
 * sg_alloc_table - Allocate and initialize an sg table
 * @table:	The sg table header to use
 * @nents:	Number of entries in sg list
 * @gfp_mask:	GFP allocation mask
 *
 *  Description:
 *    Allocate and initialize an sg table. If @nents@ is larger than
 *    SG_MAX_SINGLE_ALLOC a chained sg table will be setup.
 *
 **/
int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
{
	int ret;

	ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
			       NULL, gfp_mask, sg_kmalloc);
	if (unlikely(ret))
		__sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);

	return ret;
}
EXPORT_SYMBOL(sg_alloc_table);

其内部通过__sg_alloc_table()来动添申请内存创建。这里的SG_MAX_SINGLE_ALLOC是一个由于各种原因的限制,即动态申请的连续内存的sg table必须在一个页面中,默认一个页面4096的话,scatterlist结构体大小20字节,那么一个页面最大能够创建大小为204的scatterlist链,而如果要创建更大数目的话,需要通过铰链的方式将多个分散在不同页面的scatterlist链串联起来,这在__sg_alloc_table()内部已经实现,用户不需要关心

使用

通常的应用场景是将应用程序分配的buffer映射到sg table上

void map_user_buf_to_sgl(struct sg_table *sgt, void __user *buf, int len)
{
    int page_nr = (((unsigned long)buf + len + PAGE_SIZE - 1) -
				 ((unsigned long)buf & PAGE_MASK))
				>> PAGE_SHIFT; 
    
    /* alloc sg table */
    sg_alloc_table(sgt, pages_nr, GFP_KERNEL);

    /* alloc page ptr */
    struct page **pages = kcalloc(pages_nr, sizeof(struct page *), GFP_KERNEL);
    
    /* buf to pages */
    get_user_pages_fast((unsigned long)buf, pages_nr, 1/* write */,
				pages);
    
    struct scatterlist *sg = sgt->sgl;
    for (i = 0; i < pages_nr; i++, sg = sg_next(sg)) {
        unsigned int offset = offset_in_page(buf);
        sg_set_page(sg, pages[i], len, offset);
    }
}

首先根据buf和len得到页面数量,然后根据页面数量创建对应长度的sg table,然后获取buf对应的页面,最后遍历sg table,通过sg_set_page()将页面设置到scatterlist上

其他的一些API

  • sg_alloc_table_from_pages:从一组页面创建sg table

  • sg_nents:获取sg的entity数量

  • sg_copy_from_buffer:从一个连续的buffer拷贝到sg list

  • sg_chain:将两个单独的sg list串联

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/499616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BDCC - Lambda VS Kappa

文章目录 概述区别Lambda架构:Kappa架构:总结 适用场景:案例:小结 概述 Lambda架构和Kappa架构都是用于处理大数据的架构模式。 Lambda架构使用了批处理和流处理两种不同的处理方式来处理数据。数据首先通过流处理层进行实时处理&#xff0c;然后再通过批处理层进行离线处理&…

开源C#代码生成器,SmartSoftHelp 开发辅助工具

开源代码生成器&#xff0c;支持自定义生成代码&#xff0c;开源生成代码&#xff0c;自己编写生成格式&#xff0c;最方便的代码生成器 下载地址&#xff1a; 百度网盘 请输入提取码

《时间从来不语,却回答了所有问题》笔记三

目录 感悟 经典摘录 假若我再上一次大学 不完满才是人生 走运与倒霉 毁誉 我的座右铭 二月兰 观天池 火车上观日出 感悟 人这个万物之灵却偏偏有了感情&#xff0c;有了感情就有了悲欢。自古及今&#xff0c;海内海外&#xff0c;一个百分之百完满的人生是没有的&…

《Java虚拟机学习》JVM虚拟机是如何执行方法

1. 重载与重写方法 重载 重载 &#xff1a;同一个类中&#xff0c;方法名相同&#xff0c;形参列表不用&#xff0c;与返回值无关 对于重载方法的执行&#xff0c;JVM遵循下面的三条规则&#xff1a; 在不考虑对基本类型自动装拆箱&#xff08;auto-boxing&#xff0c;auto-…

图嵌入表示学习—Graph Embeddings

Embedding Entire Graphs 一、图嵌入向量基本概念 与Node Embeddings不同&#xff0c;Graph Embeddings是对整个图或子图进行编码而忽略其中的节点。应用场景包括异常检测或分子有毒检测。 二、对Node Embeddings求和或求和后平均 如图&#xff0c;首先对图/子图中的节点进行…

shell与shell script 学习总结

文章目录 shell与shell script 学习总结vivim可视化区块多文件编辑多窗口功能vim环境设置与记录中文编码问题语系编码转换 Shell的变量功能变量的使用与设置echo(变量的使用)变量设置的规则 环境变量的功能env(观察环境变量)set(观察所有变量)unset(取消变量) locale(语系变量)…

【Hello Network】TCP协议相关理解

作者&#xff1a;小萌新 专栏&#xff1a;网络 作者简介&#xff1a;大二学生 希望能和大家一起进步 本篇博客简介&#xff1a;补充下对于TCP协议的各种理解 TCP协议相关实验 TCP相关试验理解CLOSE_WAIT状态理解TIME_WAIT状态解决TIME_WAIT状态引起的bind失败的方法理解listen的…

分布式 03 富文本处理插件和图片文件上传

01.使用富文本编辑器来上传图片文件。 02.最开始在html文件中去使用相关富文本的插件。 引入相关文件 <link href"/js/kindeditor-4.1.10/themes/default/default.css" type"text/css" rel"stylesheet"> <script type"text/java…

Redis面试题(上)

1.什么是 Redis&#xff1f; Redis 是一种基于内存的数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景&#xff0c;比如 Strin…

Python机器学习入门 -- 支持向量机学习笔记

文章目录 前言一、支持向量机简介二、支持向量机的数学原理1. 距离解算2. 目标函数3. 约束下的优化求解4. 软间隔优化5. 核函数变换 三、Python实现支持向量机1. 惩罚力度对比2. 高斯核函数3. 非线性SVM 总结 前言 大部分传统的机器学习算法都可以实现分类任务&#xff0c;但这…

干货丨你真的了解反应持续时间吗?

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 在今天的推文里&#xff0c;要给大家分享的是一种灵活、免费的心理科学工具——反应持续时间&#xff0c;快来一起看看哦~ 01 导读 简单按键的反应持续时间是一种容易获得但未被充分利用…

C++相比于C语言增加的8个小特性(详解)

C相比于C语言增加的8个小特性&#xff08;详解&#xff09; 文章目录 C相比于C语言增加的8个小特性&#xff08;详解&#xff09;一、命名空间二、C输入和输出三、缺省参数四、函数重载五、引用六、内联函数七、auto关键字八、指针空值nullptr总结 一、命名空间 c的命名空间是…

从一到无穷大 #8 Arrow,Parquet and ORC

文章目录 引言ArrowParquetNested EncodingRepetition LevelsDefinition Levels 列化压缩 ORC 引言 以我的机器为例来做一个简单的计算&#xff1a; 执行cat /proc/cpuinfo |grep MHz|uniq可以看到目前机器中CPU频率&#xff0c;得到值 2494.140MHZ&#xff5e;2494140000HZ&…

【算法】——全排列算法讲解

前言&#xff1a; 今天&#xff0c;我给大家讲解的是关于全排列算。我会从三个方面去进行展开&#xff1a; 首先&#xff0c;我会给大家分析关于全排列算法的思想和定义&#xff1b;紧接着通过手动实现出一个全排列代码来带大家见见是怎么实现的&#xff1b;最后我会给出两道题…

ESP32单片机入门篇

目录 一、ESP32单片机的基本概念 1.双核架构 2. Wi-Fi和蓝牙功能 3. 集成多种外设 4. 支持多种操作系统 二、开发环境 1. Arduino IDE 2. ESP-IDF 三、开发语言 四、注意事项 五、代码例程 &#xff08;1&#xff09;点亮LED灯 1. 电路图 2. 代码 3. 代码注释 …

【精品】Java-Stream流详解

Java-Stream流详解 如何学会JDK8中的Stream流&#xff0c;用它来提高开发效率&#xff1f;创建不可变的集合&#xff08;Immutable 不可变的&#xff09;场景方法 初试 Stream 流Stream 流的思想Stream 流的作用Stream 流的使用步骤Stream 流的中间方法Stream 流的终结方法 如何…

STM32:利用PWM波控制飞盈电调过程和注意事项

STM32&#xff1a;利用PWM波控制电调过程和注意事项 在进行模型控制的过程中&#xff0c;如四旋翼无人机等&#xff0c;需要用到电机&#xff0c;这些电机需要通过电调来控制电机的转速。在电调模块中带有的说明书一般都是利用遥控器进行控制&#xff0c;有些情况需要自己通过…

【自然语言处理】【大模型】CodeGeeX:用于代码生成的多语言预训练模型

CodeGeeX&#xff1a;用于代码生成的多语言预训练模型 《CodeGeeX: A Pre-Trained Model for Code Generation with Multilingual Evaluations on HumanEval-X》 论文地址&#xff1a;https://arxiv.org/pdf/2303.17568.pdf 相关博客 【自然语言处理】【大模型】CodeGeeX&#…

二叉排序树

二叉排序树 文章目录 二叉排序树创建遍历删除完整代码 假如给你一个数列 (7, 3, 10, 12, 5, 1, 9)&#xff0c;要求能够高效的完成对数据的查询和添加。 使用数组 数组未排序&#xff1a; 优点&#xff1a;直接在数组尾添加&#xff0c;速度快。 缺点&#xff1a;查找速度慢. 数…

[图形学] 射线和线段之间的最小距离

1 说在前面 本文的主要内容来自于Unity引擎中Spline功能的一个函数&#xff0c;一开始我难以理解这几个向量运算的作用和几何意义&#xff0c;经过一番思考后总结如下&#xff1a; 该段代码实际上更像是两个直线之间寻找最短距离&#xff0c;然后判断该距离对应的点在其中一条…