162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 762306a36Sopenharmony_ci#include <asm/cache.h> 862306a36Sopenharmony_ci#include <asm/cacheflush.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * ARCH specific callbacks for generic noncoherent DMA ops 1262306a36Sopenharmony_ci * - hardware IOC not available (or "dma-coherent" not set for device in DT) 1362306a36Sopenharmony_ci * - But still handle both coherent and non-coherent requests from caller 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * For DMA coherent hardware (IOC) generic code suffices 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_civoid arch_dma_prep_coherent(struct page *page, size_t size) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci /* 2162306a36Sopenharmony_ci * Evict any existing L1 and/or L2 lines for the backing page 2262306a36Sopenharmony_ci * in case it was used earlier as a normal "cached" page. 2362306a36Sopenharmony_ci * Yeah this bit us - STAR 9000898266 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Although core does call flush_cache_vmap(), it gets kvaddr hence 2662306a36Sopenharmony_ci * can't be used to efficiently flush L1 and/or L2 which need paddr 2762306a36Sopenharmony_ci * Currently flush_cache_vmap nukes the L1 cache completely which 2862306a36Sopenharmony_ci * will be optimized as a separate commit 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci dma_cache_wback_inv(page_to_phys(page), size); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * Cache operations depending on function and direction argument, inspired by 3562306a36Sopenharmony_ci * https://lore.kernel.org/lkml/20180518175004.GF17671@n2100.armlinux.org.uk 3662306a36Sopenharmony_ci * "dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] 3762306a36Sopenharmony_ci * dma-mapping: provide a generic dma-noncoherent implementation)" 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * | map == for_device | unmap == for_cpu 4062306a36Sopenharmony_ci * |---------------------------------------------------------------- 4162306a36Sopenharmony_ci * TO_DEV | writeback writeback | none none 4262306a36Sopenharmony_ci * FROM_DEV | invalidate invalidate | invalidate* invalidate* 4362306a36Sopenharmony_ci * BIDIR | writeback+inv writeback+inv | invalidate invalidate 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * [*] needed for CPU speculative prefetches 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * NOTE: we don't check the validity of direction argument as it is done in 4862306a36Sopenharmony_ci * upper layer functions (in include/linux/dma-mapping.h) 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid arch_sync_dma_for_device(phys_addr_t paddr, size_t size, 5262306a36Sopenharmony_ci enum dma_data_direction dir) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci switch (dir) { 5562306a36Sopenharmony_ci case DMA_TO_DEVICE: 5662306a36Sopenharmony_ci dma_cache_wback(paddr, size); 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci case DMA_FROM_DEVICE: 6062306a36Sopenharmony_ci dma_cache_inv(paddr, size); 6162306a36Sopenharmony_ci break; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci case DMA_BIDIRECTIONAL: 6462306a36Sopenharmony_ci dma_cache_wback_inv(paddr, size); 6562306a36Sopenharmony_ci break; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci default: 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_civoid arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, 7362306a36Sopenharmony_ci enum dma_data_direction dir) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci switch (dir) { 7662306a36Sopenharmony_ci case DMA_TO_DEVICE: 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* FROM_DEVICE invalidate needed if speculative CPU prefetch only */ 8062306a36Sopenharmony_ci case DMA_FROM_DEVICE: 8162306a36Sopenharmony_ci case DMA_BIDIRECTIONAL: 8262306a36Sopenharmony_ci dma_cache_inv(paddr, size); 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci default: 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * Plug in direct dma map ops. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_civoid arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, 9462306a36Sopenharmony_ci const struct iommu_ops *iommu, bool coherent) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * IOC hardware snoops all DMA traffic keeping the caches consistent 9862306a36Sopenharmony_ci * with memory - eliding need for any explicit cache maintenance of 9962306a36Sopenharmony_ci * DMA buffers. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci if (is_isa_arcv2() && ioc_enable && coherent) 10262306a36Sopenharmony_ci dev->dma_coherent = true; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci dev_info(dev, "use %scoherent DMA ops\n", 10562306a36Sopenharmony_ci dev->dma_coherent ? "" : "non"); 10662306a36Sopenharmony_ci} 107