Files
linux/arch/arm64/mm/dma-mapping.c
John Cox 60e9069014 arm64/dma-mapping: Fix arch_sync_dma_for_device to respect dir parameter
All other architectures do different cache operations depending on the
dir parameter. Fix arm64 to do the same.

This fixes udmabuf operations when syncing for read e.g. when the CPU
reads back a V4L2 decoded frame buffer.

Signed-off-by: John Cox <jc@kynesim.co.uk>
2025-12-01 12:28:12 +00:00

69 lines
1.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
*/
#include <linux/gfp.h>
#include <linux/cache.h>
#include <linux/dma-map-ops.h>
#include <xen/xen.h>
#include <asm/cacheflush.h>
#include <asm/xen/xen-ops.h>
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
enum dma_data_direction dir)
{
unsigned long start = (unsigned long)phys_to_virt(paddr);
unsigned long end = start + size;
switch (dir) {
case DMA_BIDIRECTIONAL:
dcache_clean_inval_poc(start, end);
break;
case DMA_TO_DEVICE:
dcache_clean_poc(start, end);
break;
case DMA_FROM_DEVICE:
dcache_inval_poc(start, end);
break;
case DMA_NONE:
default:
break;
}
}
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
enum dma_data_direction dir)
{
unsigned long start = (unsigned long)phys_to_virt(paddr);
if (dir == DMA_TO_DEVICE)
return;
dcache_inval_poc(start, start + size);
}
void arch_dma_prep_coherent(struct page *page, size_t size)
{
unsigned long start = (unsigned long)page_address(page);
dcache_clean_poc(start, start + size);
}
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
int cls = cache_line_size_of_cpu();
WARN_TAINT(!coherent && cls > ARCH_DMA_MINALIGN,
TAINT_CPU_OUT_OF_SPEC,
"%s %s: ARCH_DMA_MINALIGN smaller than CTR_EL0.CWG (%d < %d)",
dev_driver_string(dev), dev_name(dev),
ARCH_DMA_MINALIGN, cls);
dev->dma_coherent = coherent;
xen_setup_dma_ops(dev);
}