1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * RISC-V specific functions to support DMA for non-coherent devices 4 * 5 * Copyright (c) 2021 Western Digital Corporation or its affiliates. 6 */ 7 8 #include <linux/dma-direct.h> 9 #include <linux/dma-map-ops.h> 10 #include <linux/mm.h> 11 #include <asm/cacheflush.h> 12 13 static bool noncoherent_supported __ro_after_init; 14 int dma_cache_alignment __ro_after_init = ARCH_DMA_MINALIGN; 15 EXPORT_SYMBOL_GPL(dma_cache_alignment); 16 17 void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, 18 enum dma_data_direction dir) 19 { 20 void *vaddr = phys_to_virt(paddr); 21 22 switch (dir) { 23 case DMA_TO_DEVICE: 24 ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size); 25 break; 26 case DMA_FROM_DEVICE: 27 ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size); 28 break; 29 case DMA_BIDIRECTIONAL: 30 ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size); 31 break; 32 default: 33 break; 34 } 35 } 36 37 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, 38 enum dma_data_direction dir) 39 { 40 void *vaddr = phys_to_virt(paddr); 41 42 switch (dir) { 43 case DMA_TO_DEVICE: 44 break; 45 case DMA_FROM_DEVICE: 46 case DMA_BIDIRECTIONAL: 47 ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size); 48 break; 49 default: 50 break; 51 } 52 } 53 54 void arch_dma_prep_coherent(struct page *page, size_t size) 55 { 56 void *flush_addr = page_address(page); 57 58 ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size); 59 } 60 61 void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, 62 const struct iommu_ops *iommu, bool coherent) 63 { 64 WARN_TAINT(!coherent && riscv_cbom_block_size > ARCH_DMA_MINALIGN, 65 TAINT_CPU_OUT_OF_SPEC, 66 "%s %s: ARCH_DMA_MINALIGN smaller than riscv,cbom-block-size (%d < %d)", 67 dev_driver_string(dev), dev_name(dev), 68 ARCH_DMA_MINALIGN, riscv_cbom_block_size); 69 70 WARN_TAINT(!coherent && !noncoherent_supported, TAINT_CPU_OUT_OF_SPEC, 71 "%s %s: device non-coherent but no non-coherent operations supported", 72 dev_driver_string(dev), dev_name(dev)); 73 74 dev->dma_coherent = coherent; 75 } 76 77 void riscv_noncoherent_supported(void) 78 { 79 WARN(!riscv_cbom_block_size, 80 "Non-coherent DMA support enabled without a block size\n"); 81 noncoherent_supported = true; 82 } 83 84 void __init riscv_set_dma_cache_alignment(void) 85 { 86 if (!noncoherent_supported) 87 dma_cache_alignment = 1; 88 } 89