DMA 的理解

DMA:Direct Memory Access,直接内存访问

cache一致性的问题
CPU ------ Cache ----- 内存 --------- DMA ----- 外设

问题1:
当CPU访问某一块内存A时,CPU访问的时候,如果cache没有命中,则会将A这块内存里
面的数据刷新到cache中,当CPU再次读取A内存的数据发现cache已经命中,直接在cache
中取数据即可,不必再去更新内存的数据。这个时候如果有一个DMA的操作,去操作了A这
块内存,但是CPU不知道这块内存的数据已经更新,当CPU再次读取A块内存的数据时,发
现cache命中了,还是会直接读取cache的数据,而不更新内存的数据,这个时候就造成了
cache和内存里面数据不一致的情况。

问题2:
CPU写一片内存A,但是CPU写这块内存的时候,其实是先写在cache上,在适当的时候再
写回内存中。这个时候,我们想要写一些数据到内存,然后再通过DMA操作把这块数据搬
到网卡上去,如果我们想要写的数据没有从cache中write back回内存,这个时候就会出现
我要给用户发送的数据和用户收到的数据不一致的问题。

两种表现:
一种是别人给我发数据包,我读取到的数据包不对。
另一种是我要发给别人数据,我觉得我已经写到内存中,然后通过DMA发给了对方,但是
对方读取的数据不对。

有两种解决方法:一致性DMA缓冲区以及流式DMA映射
一致性DMA缓冲区:直接申请一块DMA内存

void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp)
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle)

流式DMA映射:强制的进行cache到内存的write back操作以及将cache标记设置为invalid。

#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)

static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
		size_t size, enum dma_data_direction dir, unsigned long attrs)
{
	debug_dma_map_single(dev, ptr, size);
	return dma_map_page_attrs(dev, virt_to_page(ptr), offset_in_page(ptr),
			size, dir, attrs);
}
#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
		size_t size, enum dma_data_direction dir, unsigned long attrs)
{
	return dma_unmap_page_attrs(dev, addr, size, dir, attrs);
}

你可能感兴趣的:(linux嵌入式开发)