linux申请dma内存,linux内存管理之DMA

本文详细介绍了Linux内核如何管理DMA内存,包括dma_map_single、dma_alloc_coherent等函数,以及DMA缓冲区映射的三种类型。通过分析e1000网卡驱动,展示了DMA在数据发送过程中的作用,强调了DMA内存管理和硬件交互的重要性。
摘要由CSDN通过智能技术生成

说起DMA我们并不陌生,但是实际编程中去用的人不多吧,最多就是网卡驱动里的环形buffer,再有就是设备的dma,下面我们就分析分析.

DMA用来在设备内存和内存之间直接数据交互。而无需cpu干预

13f6c0e1ecf51a6ac17448511ab7e11e.png

内核为了方便驱动的开发,已经提供了几个dma 函数接口。

dma跟硬件架构相关,所以linux关于硬件部分已经给屏蔽了,有兴趣的可以深入跟踪学习.

按照linux内核对dma层的架构设计,各平台dma缓冲区映射之间的差异由内核定义的一个dma操作集

include/linux/dma-mapping.h:点击(此处)折叠或打开struct dma_map_ops {

void* (*alloc)(struct device *dev, size_t size,

dma_addr_t *dma_handle, gfp_t gfp,

struct dma_attrs *attrs);

void (*free)(struct device *dev, size_t size,

void *vaddr, dma_addr_t dma_handle,

struct dma_attrs *attrs);

int (*mmap)(struct device *, struct vm_area_struct *,

void *, dma_addr_t, size_t, struct dma_attrs *attrs);

int (*get_sgtable)(struct device *dev, struct sg_table *sgt, void *,

dma_addr_t, size_t, struct dma_attrs *attrs);

dma_addr_t (*map_page)(struct device *dev, struct page *page,

unsigned long offset, size_t size,

enum dma_data_direction dir,

struct dma_attrs *attrs);

void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,

size_t size, enum dma_data_direction dir,

struct dma_attrs *attrs);

int (*map_sg)(struct device *dev, struct scatterlist *sg,

int nents, enum dma_data_direction dir,

struct dma_attrs *attrs);

void (*unmap_sg)(struct device *dev,

struct scatterlist *sg, int nents,

enum dma_data_direction dir,

struct dma_attrs *attrs);

void (*sync_single_for_cpu)(struct device *dev,

dma_addr_t dma_handle, size_t size,

enum dma_data_direction dir);

void (*sync_single_for_device)(struct device *dev,

dma_addr_t dma_handle, size_t size,

enum dma_data_direction dir);

void (*sync_sg_for_cpu)(struct device *dev,

struct scatterlist *sg, int nents,

enum dma_data_direction dir);

void (*sync_sg_for_device)(struct device *dev,

struct scatterlist *sg, int nents,

enum dma_data_direction dir);

int (*mapping_error)(struct device *dev, dma_addr_t dma_addr);

int (*dma_supported)(struct device *dev, u64 mask);

int (*set_dma_mask)(struct device *dev, u64 mask);

#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK

u64 (*get_required_mask)(struct device *dev);

#endif

int is_phys;

}

来统一屏蔽实现的差异.

不同差异主要来来自cache的问题

Cache与dma同步问题,这里不深入讨论.

另外一个常用的函数是Dma_set_mask,  为了通知内核设备能够寻址的范围,很多时候设备能够寻址的范围有限。

Dma映射可以分为三类:

1.一致性dma映射dma_alloc_coherent(问题:驱动使用的buffer不是自身申请的,而是其他模块)

当驱动模块主动分配一个Dma缓冲区并且dma生存期和模块一样时

参数说明:

(1)这个函数的返回值是缓冲的一个内核虚拟地址,它可被驱动使用

(2)第三个参数dma_handle:

其间相关的物理地址在dma_handle中返回

2.流式dma映射dma_map_single

通常用于把内核一段buffer映射,返回物理地址.

如果驱动模块需要使用从别的模块传进来的虚拟地址空间作为dma缓冲区,保证地址的线性cache一致性

一致性api接口:sync_single_for_cpu

3.分散/聚集映射(scatter/gather map)  Dma_map_sgs

6c7f95efac34fe7660921c964d368d88.png

有时候我们还需要

1. 回弹缓冲区bounce  buffer:当cpu侧物理地址不适合设备的dma操作的时候

bfa724737ee84e888616e0f790b9ec43.png

2.

DmA内存池:一般dma映射都是单个page的整数倍,如果驱动程序需要更小的一致性映射的dma缓冲区,可以使用。类似于slab机制,

Dma_pool_create

下面我们就那网卡驱动的例子说说dma的具体应用,参考linux kernel e1000网卡

drivers/net/ethernet/intel/e1000/*

Ring buffer

Dma不能为高端内存,一般为32,默认低端内存,由于设备能够访问的地址范围有限。

设备使用物理地址,而代码使用虚拟地址。

就看看如何发送数据包:e1000_main.c:

e1000_xmit_frame: 关于帧的发送流程这里不多说.

点击(此处)折叠或打开

static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,

struct net_device *netdev)

{

struct e1000_adapter *adapter = netdev_priv(netdev);

struct e1000_hw *hw = &adapter->hw;

struct e1000_tx_ring *tx_ring;

unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;

unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;

unsigned int tx_flags = 0;

unsigned int len = skb_headlen(skb);

unsigned int nr_frags;

unsigned int mss;

int count = 0;

int tso;

unsigned int f;

/* This goes back to the question of how to logically map a tx queue

* to a flow. Right now, performance is impacted slightly negatively

* if using multiple tx queues. If the stack breaks away from a

* single qdisc implementation, we can look at this again. */

tx_ring = adapter->tx_ring;

if (unlikely(skb->len <=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值