首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DMA引擎超时和DMA内存映射

DMA引擎超时和DMA内存映射
EN

Stack Overflow用户
提问于 2018-02-07 20:43:10
回答 1查看 1K关注 0票数 1

我正在尝试使用Linux驱动程序。当前,当我发送事务并开始等待时,我的请求就会超时。我相信这与我在执行DMA映射时设置缓冲区的方式有关。

代码语言:javascript
复制
char *src_dma_buffer = kmalloc(dma_length, GFP_KERNEL);
char *dest_dma_buffer = kzalloc(dma_length, GFP_KERNEL);

tx_dma_handle = dma_map_single(tx_chan->device->dev, src_dma_buffer, dma_length, DMA_TO_DEVICE);    
rx_dma_handle = dma_map_single(rx_chan->device->dev, dest_dma_buffer, dma_length, DMA_FROM_DEVICE);

在Xilinx的DMA驱动程序中,他们特别注意内存对齐。特别是,它们使用dma_chan->dma_device的一个名为copy_align的属性。

  • @copy_align: memcpy操作的对齐移位
代码语言:javascript
复制
const int dma_length = 16*1024;
len = dmatest_random() % test_buf_size + 1;
len = (len >> align) << align;
if (!len)
    len = 1 << align;
src_off = dmatest_random() % (test_buf_size - len + 1);
dst_off = dmatest_random() % (test_buf_size - len + 1);

src_off = (src_off >> align) << align;
dst_off = (dst_off >> align) << align;

从dmatest_random()来看,原来的地址完全是随机的。不知道能说些什么/对记忆能做些什么。

代码语言:javascript
复制
static unsigned long dmatest_random(void)
{
    unsigned long buf;

    get_random_bytes(&buf, sizeof(buf));
    return buf;
}

然后,他们使用这些偏移设置DMA的源缓冲区和目标缓冲区。

代码语言:javascript
复制
u8 *buf = thread->srcs[i] + src_off;

dma_srcs[i] = dma_map_single(tx_dev->dev, buf, len, DMA_MEM_TO_DEV);

我对此感到非常困惑。我唯一的猜测是,它将在虚拟内存中对齐源缓冲区和目标缓冲区的开头。

看看我用kmalloc和kzalloc设置缓冲区的方式,我能保证缓冲区从页面边界开始吗?我说得对吗?我需要缓冲区从页面边界开始吗?

Xilinx测试驱动程序的源代码如下:https://github.com/Xilinx/linux-xlnx/blob/master/drivers/dma/xilinx/axidmatest.c

您可以在这里找到我试图解决的问题的高级描述:https://forums.xilinx.com/t5/Embedded-Linux/AXI-DMA-Drivers-for-Kernel-v-4-9-PetaLinux-2017-3/td-p/828917

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-07 21:55:52

查看一下此链接,似乎无法保证您的内存分配将从框架页面的开头开始。然而,另一个链接可能会有所帮助,在解释alloc_pages时,这可能更适合您所需要的内容。

关于DMA事务中使用的内存的对齐,我们可以读到以下内容:

什么内存是可DMA的? 您必须知道的第一条信息是,什么内核内存可以与DMA映射工具一起使用。在这方面有一套不成文的规则,本文试图最终把它们写下来。 如果您通过页面分配器(即__get_free_page*())或通用内存分配器(即kmalloc()或kmem_cache_alloc())获得内存,则可以使用从这些例程返回的地址对该内存进行DMA处理。 这意味着您可以不使用从vmalloc()返回的内存/地址进行DMA。可以将DMA映射到映射到vmalloc()区域的底层内存,但这需要遍历页表才能获取物理地址,然后使用类似于__va()的方法将每个页面转换回内核地址。编辑:当我们集成Gerd的通用代码时更新它。 这个规则还意味着您可以不使用内核映像地址(数据/文本/bss段中的项),也不能使用模块映像地址,也不能使用DMA的堆栈地址。这些都可以映射到与物理内存的其他部分完全不同的地方。即使这些类型的内存可以物理地使用DMA,您也需要确保I/O缓冲区是直线对齐的。如果没有这一点,您就会在带有DMA不连贯缓存的CPU上看到缓存共享问题(数据损坏)。( CPU可以写入一个单词,DMA可以在同一缓存行中写入另一个单词,其中一个可以被覆盖。) 此外,这意味着您不能将kmap()调用和DMA返回到/从该调用返回。这与vmalloc()类似。 那块I/O和网络缓冲区呢?块I/O和网络子系统确保它们使用的缓冲区对DMA from/to有效。

因此,我们只需要将地址与cacheline大小对齐,并且不需要将内存对齐到框架页(它也可以工作,但不需要)。对于关于kmalloc的手册,如果我们指定标志GFP_DMA,就会得到适合DMA事务的内存(与cacheline大小对齐)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48672908

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档