同时DMA到用户存储器

时间:2012-03-02 07:54:39

标签: linux kernel driver dma

考虑一下

用户程序中的线程1:

buf = malloc(9000);
memset(buf, 0xee, 9000);
read(buf, 9000); //for example gives pages [part of 7, 8, 9, part of 10]

用户程序中的线程2:

buf = malloc(9000); //for example gives pages [part of 4, 6, 5, part of 7]
memset(buf, 0xee, 9000);
read(buf, 9000);

司机阅读:

get_user_pages();

//build dma sg list from pages
//...

//the platform demands a cachesync
for(all pages) {
    dma_cache_wback_inv();
}

//start dma and wait for it to be done
//...
wait_event_interruptible_timeout(); //blocks calling thread until dma done

for(all pages) {
    if(read) SetPageDirty();
    page_cache_release();
}

请注意,两次传输都使用了第7页,这是一个很大的问题,有时会导致数据错误(在一个buf的末尾找到0xee)。为了说清楚,这两个读取在不同的DMA通道上运行,因此它们可以同时运行。

我的解决方案是将用户程序中的缓冲区页面对齐,以便2驱动程序DMA永远不会共享同一页面的部分内容。

我想知道是否还有其他解决方案? 我也想知道为什么这是个大问题。

1 个答案:

答案 0 :(得分:1)

这是嵌入式处理器的限制,而DMA不是缓存一致的。在高端PowerPC芯片上,这个问题就消失了。

您的两个缓冲区在它们遇到的位置共享一个缓存行。同时一个线程在驱动程序中将缓存写入RAM,第二个线程仍然在memset中用0xee填充缓存行。

DMA 1将您的数据写入RAM,但处理器仍保留该数据的脏缓存行,包含0xee。当第二个线程写出缓存时,它将0xee放在来自DMA1的数据上。

解决方案是:

  1. 缓存对齐缓冲区(性能最高)。
  2. 在内核驱动程序中使用退回缓冲区(与现有用户空间代码最兼容)。
  3. get_user_pages()不是问题的一部分 - 这是关于硬件和时间的。