1

考虑这个

用户程序中的线程 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 永远不会共享同一页面的部分内容。

我想知道是否有另一种解决方案?我也想知道为什么这是一个大问题。

4

1 回答 1

1

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

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

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

解决方案是:

  1. 缓存对齐缓冲区(最高性能)。
  2. 在内核驱动程序中使用反弹缓冲区(与现有用户空间代码最兼容)。

get_user_pages()不是问题的一部分——这与硬件和时间有关。

于 2012-03-02T11:02:46.660 回答