2012-03-02 39 views
1

考虑这个同时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页由两者使用转移,这是一个很大的问题,有时会导致错误的数据(0xee在一个buf的末尾被发现)。为了清楚起见,这两个读取运行在不同的DMA通道上,因此它们可以同时运行。

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

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

+1

这可能是相当具体的平台 - 缓存失效的要求表明你正在嵌入式系统上运行。两个缓冲区足够接近以共享缓存线,还是在平台勘误中还存在其他限制? – 2012-03-02 09:49:44

+0

是的,这是一个ppc440ep,并且缓冲区可能足够接近。缓存行是32个字节,我只看到4-12个字节被破坏/不变。缓存中是否存在2个不同版本的相同物理内存?当我在一个线程中执行wback时,它是否可以销毁另一个线程的数据?据我所知没有任何错误。但是get_user_pages呢?当它返回2个不同版本的同一页面时会发生什么?如果来自不同线程的get_user_pages和page_cache_release变为交织。 – Ronnie 2012-03-02 10:43:39

+0

我不完全清楚get_user_pages/page_cache_release是干什么的,除非给予页面的物​​理地址。在这个系统上没有光盘缓存或任何东西,只有内存和cpu-cache。 – Ronnie 2012-03-02 10:50:58

回答

1

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

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

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

的解决方案是:

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

get_user_pages()这里不是问题的一部分 - 这是关于硬件和时间。

+0

我认为你对缓存问题是正确的,但我也认为我已经看到错误,而不使用memset,因为在调试此问题之前没有memset ...但是可能在DMA 1完成后读取缓冲区,可以使在DMA 2完成之前,缓存将0xee读回缓存? – Ronnie 2012-03-02 11:18:19

+0

'malloc'还会触及缓冲区末端周围的数据以进行堆维护。这可能就足够了。 – 2012-03-02 11:20:21

+0

是的,这听起来像一个解释。 – Ronnie 2012-03-02 11:23:21