arch_dma_prep_coherent() performs the cache maintenance on the address returned by page_address(). On 32-bit powerpc with CONFIG_HIGHMEM that is NULL for a highmem page which is not kmapped, so the flush would operate on the wrong virtual range and leave the dirty lines of the buffer in place.
The generic DMA code may pass highmem pages to this hook: dma_direct_alloc() handles a highmem page returned by dma_alloc_contiguous() by forcing the remap path, which calls arch_dma_prep_coherent() on that page before creating the uncached mapping. This cannot happen on powerpc today only because it does not select HAVE_DMA_CONTIGUOUS, so dma-direct never gets a highmem page there, but nothing in the hook's contract rules it out. Use __dma_sync_page() with DMA_BIDIRECTIONAL, which the arch_sync_dma_for_*() hooks already use and which kmaps highmem pages one at a time. Without CONFIG_HIGHMEM it does the same flush_dcache_range() on the linear mapping as before. Signed-off-by: Marek Szyprowski <[email protected]> --- arch/powerpc/mm/dma-noncoherent.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c index 30260b5d146d..e646256365d5 100644 --- a/arch/powerpc/mm/dma-noncoherent.c +++ b/arch/powerpc/mm/dma-noncoherent.c @@ -118,7 +118,5 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, void arch_dma_prep_coherent(struct page *page, size_t size) { - unsigned long kaddr = (unsigned long)page_address(page); - - flush_dcache_range(kaddr, kaddr + size); + __dma_sync_page(page_to_phys(page), size, DMA_BIDIRECTIONAL); } -- 2.43.0
