scatter/gather I/O

匿名 (未验证) 提交于 2019-12-03 00:38:01

发散/汇聚映射

int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction);
各参数含义如下:

dev:设备数据结构指针 sg:缓冲区列表的第一个缓冲区的指针 nets:sg中有多少个缓冲区 direction:数据流动方向 

该函数的返回值是成功映射了多少个缓冲区。如果在分散/汇聚列表中一些缓冲的物理地址或虚拟地址相邻的,且IOMMU可以将它们映射成单个内存块,则返回值可能比输入值nents小。
数据结构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 };

注意如果sg已经映射过了,则不能再对其进行映射,再次映射会损坏sg中的信息。对于sg中的每个缓冲,该函数会正确的为
其产生设备总线地址,驱动应该使用该总线地址,内核提供了两个相关的宏:

dma_addr_t sg_dma_address(struct scatterlist *sg);

用于从scatterlist返回总线( DMA )地址.

unsigned int sg_dma_len(struct scatterlist *sg);

用于返回这个缓冲的长度.

void dma_unmap_sg(struct device *dev, struct scatterlist *list, int nents,                  enum dma_data_direction direction);

该函数用于取消发散/汇聚映射。netns必须等于传给dma_map_sg的值,而不是dma_map_sg返回的值。

类似于单一映射,如果CPU必须访问已经映射了的缓冲区,则必须先让CPU获取这些缓冲区,对应的API如下:

void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum                  dma_data_direction direction);  void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, enum                  dma_data_direction direction);

scatter/gather方式是与block dma方式相对应的一种dma方式。

在dma传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但在有的计算机体系中,如IA,连续的存储器地址在物理上不一定是连续的,则dma传输要分成多次完成。

如果传输完一块物理连续的数据后发起一次中断,同时主机进行下一块物理连续的传输,则这种方式即为block dma方式。

scatter/gather方式则不同,它是用一个链表描述物理不连续的存储器,然后把链表首地址告诉dma master。

dma master传输完一块物理连续的数据后,就不用再发中断了,而是根据链表传输下一块物理连续的数据,最后发起一次中断。

很显然scatter/gather方式比block dma方式效率高。

文章来源: scatter/gather I/O
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!