Orange Pi3 LTS(Allwinner H6)UART DMA驱动物理内存更新异常问题
问题原因与解决方案
核心原因:ARM缓存一致性与内存属性不匹配
你遇到的问题本质是ARM架构的CPU缓存与DMA设备的内存访问一致性冲突:
kmalloc()默认分配的是**可缓存(Cached)**内存,CPU通过虚拟(逻辑)地址写入数据时,会优先把数据存在L1/L2缓存中,不会立即同步到物理内存。- DMA设备直接访问物理内存,完全绕过CPU缓存,所以在init回调里写完逻辑地址就立刻触发DMA时,DMA读到的物理内存还是旧数据(甚至是未初始化的垃圾值)。
- 到exit回调触发DMA时,中间经过了系统调度、其他内核操作,CPU缓存已经通过主动回写、缓存淘汰等机制把数据同步到了物理内存,因此DMA能读到正确数据。
具体解决方案
1. 改用DMA专用内存分配函数(推荐)
替换kmalloc()为dma_alloc_coherent(),这个函数会直接分配**缓存一致(Cache-Coherent)**的内存:
dma_addr_t dma_phys_addr; void *virt_addr = dma_alloc_coherent(dev, size, &dma_phys_addr, GFP_KERNEL);
分配出的虚拟地址写入后,数据会自动同步到物理内存,DMA可以直接读取,无需手动处理缓存。
2. 手动刷写缓存(兼容现有kmalloc场景)
如果必须使用kmalloc(),在触发DMA前,显式把缓存中的数据刷到物理内存:
// 刷写指定范围的缓存到物理内存 flush_dcache_range((unsigned long)virt_addr, (unsigned long)virt_addr + size); // 确保刷写操作完成后再触发DMA mb(); dma_start_transfer();
flush_dcache_range()负责把CPU缓存中的数据回写到物理内存,mb()(内存屏障)确保缓存操作完成后再执行DMA启动指令。
3. 确认内存属性配置
检查你的内存区域是否被正确标记为可被DMA访问,避免因MMU页表属性错误导致的缓存问题。
内容的提问来源于stack exchange,提问作者Bart
相关产品推荐
相关产品推荐

