考虑这个
用户程序中的线程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就永远不会共享同一页面的部分。
我想知道是否还有其他解决方案?我还想知道为什么这是一个大问题。
这是对嵌入式处理器和DMA的限制,DMA与缓存不一致。在高端PowerPC芯片上,这个问题消失了。
您的两个缓冲区在相交处共享一条缓存线。在一个线程在驱动程序中将缓存写入RAM的同时,第二个线程仍在内存集中,用0xee填充缓存行。
DMA 1将数据写入RAM,但处理器仍保留该数据的脏缓存行,其中包含0xee。当第二个线程写出缓存时,它将0xee放在来自DMA1的数据上。
解决方案是:
- 缓存对齐缓冲区(最高性能)
- 在内核驱动程序中使用反弹缓冲区(与现有用户空间代码最兼容)
get_user_pages()
不是问题的一部分,这与硬件和时序有关。