"分散-聚集DMA"以及"scatterlist"

xiaoxiao2021-02-28  78

“分散-聚集DMA”以及”scatterlist”

我们知道对磁盘的每个IO操作就是在磁盘与一些内存单元之间相互传送一些相邻扇区的内容。块设备驱动程序只要向磁盘控制器发送一些适当的命令(如前面我们所讲的scsi命令)就可以触发一次数据传送;一旦完成数据的传送,控制器就会发出一个中断通知块设备驱动程序。大多数情况,磁盘控制器直接采用DMA方式进行数据传送。

DMA

DMA全称就是直接内存访问,是一种硬件机制,它允许外围设备和主内存直接直接进行数据传输而不需要cpu的参与。

分散-聚集DMA

老式磁盘控制器在DMA传送时,磁盘必须与连续的内存单元相互传送数据。 新的磁盘控制器支持所谓的分散-聚集DMA传送方式:此种方式,磁盘可以与一些非连续的内存区相互传送数据。

启动一次分散-聚集DMA传送,块设备驱动需要向磁盘控制器发送:

要传送的起始磁盘扇区号和总的扇区数内存区的描述符链表,其中链表的每项包含一个地址和一个长度(在内存页中位置以及大小)

分散/聚集映射

如果块设备驱动程序在实际传输过程中需要使用DMA,那么它可以遍历bio结构,并为 每个bio结构创建DMA映射,并将结果传递给设备。如果设备支持”分散-聚集DMA“ 则有一个更简便高效的方法: int blk_rq_map_sg(struct request_queue *q, struct request *rq, struct scatterlist *sglist) 从指定请求获得全部的段(段指bio中的每一个segment),然后把它们填写到给定表(list)中。内存中相邻的段将被合并在一个scatterlist中,返回值表示的是表中入口项的个数(表中有效元素个数),该函数使用第三个参数返回一个分散表。 在调用blk_rq_map_sg前,必须为分散表(list)分配存储空间,至少与request请求所拥有的(内存)物理段同样多的数量,即req->nr_phys_segments。

许多设备都能接受一个指针数组的分散表,以及它的长度,然后在一次DMA操作中把它们全部传输走。 映射分散表的第一步是建立并填充一个描述 被传送缓冲区的 scatterlist结构的数组。 scatterlist结构的主要成员:

unsigned long page_link;//一般指在scatter/gather操作用到缓冲区对应的page结构指针unsigned int offset;unsigned int length; //在页内缓冲区的长度和偏移量

为了映射一个分散/聚集DMA操作,驱动程序应为传输的每个缓冲区在scatterlist结构对应入口项上设置page_link,offset和length成员。(这一步由上述blk_rq_map_sg完成) 然后调用: int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction); 这里的nents是传入分散表sg入口的数量。返回值是要传送DMA缓冲区数,可能小于nents。 对在分散表中每一个缓冲区,dma_map_sg返回了指定设备的正确总线地址,总线地址和每个缓冲区长度被保存在scatterlist结构中,驱动程序应该传输由dma_map_sg返回的每个缓冲区。 一旦传输完毕,使用dma_unmap_sg解除分散/聚集映射。

转载请注明原文地址: https://www.6miu.com/read-47674.html

最新回复(0)