18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
48c2ecf20Sopenharmony_ci * Copyright (C) 2000, 2001, 06	 Ralf Baechle <ralf@linux-mips.org>
58c2ecf20Sopenharmony_ci * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/dma-direct.h>
88c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h>
98c2ecf20Sopenharmony_ci#include <linux/highmem.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/cache.h>
128c2ecf20Sopenharmony_ci#include <asm/cpu-type.h>
138c2ecf20Sopenharmony_ci#include <asm/dma-coherence.h>
148c2ecf20Sopenharmony_ci#include <asm/io.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/*
178c2ecf20Sopenharmony_ci * The affected CPUs below in 'cpu_needs_post_dma_flush()' can speculatively
188c2ecf20Sopenharmony_ci * fill random cachelines with stale data at any time, requiring an extra
198c2ecf20Sopenharmony_ci * flush post-DMA.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Warning on the terminology - Linux calls an uncached area coherent;  MIPS
228c2ecf20Sopenharmony_ci * terminology calls memory areas with hardware maintained coherency coherent.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Note that the R14000 and R16000 should also be checked for in this condition.
258c2ecf20Sopenharmony_ci * However this function is only called on non-I/O-coherent systems and only the
268c2ecf20Sopenharmony_ci * R10000 and R12000 are used in such systems, the SGI IP28 Indigo² rsp.
278c2ecf20Sopenharmony_ci * SGI IP32 aka O2.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic inline bool cpu_needs_post_dma_flush(void)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	switch (boot_cpu_type()) {
328c2ecf20Sopenharmony_ci	case CPU_R10000:
338c2ecf20Sopenharmony_ci	case CPU_R12000:
348c2ecf20Sopenharmony_ci	case CPU_BMIPS5000:
358c2ecf20Sopenharmony_ci	case CPU_LOONGSON2EF:
368c2ecf20Sopenharmony_ci		return true;
378c2ecf20Sopenharmony_ci	default:
388c2ecf20Sopenharmony_ci		/*
398c2ecf20Sopenharmony_ci		 * Presence of MAARs suggests that the CPU supports
408c2ecf20Sopenharmony_ci		 * speculatively prefetching data, and therefore requires
418c2ecf20Sopenharmony_ci		 * the post-DMA flush/invalidate.
428c2ecf20Sopenharmony_ci		 */
438c2ecf20Sopenharmony_ci		return cpu_has_maar;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_civoid arch_dma_prep_coherent(struct page *page, size_t size)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	dma_cache_wback_inv((unsigned long)page_address(page), size);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_civoid *arch_dma_set_uncached(void *addr, size_t size)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return (void *)(__pa(addr) + UNCAC_BASE);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline void dma_sync_virt_for_device(void *addr, size_t size,
588c2ecf20Sopenharmony_ci		enum dma_data_direction dir)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	switch (dir) {
618c2ecf20Sopenharmony_ci	case DMA_TO_DEVICE:
628c2ecf20Sopenharmony_ci		dma_cache_wback((unsigned long)addr, size);
638c2ecf20Sopenharmony_ci		break;
648c2ecf20Sopenharmony_ci	case DMA_FROM_DEVICE:
658c2ecf20Sopenharmony_ci		dma_cache_inv((unsigned long)addr, size);
668c2ecf20Sopenharmony_ci		break;
678c2ecf20Sopenharmony_ci	case DMA_BIDIRECTIONAL:
688c2ecf20Sopenharmony_ci		dma_cache_wback_inv((unsigned long)addr, size);
698c2ecf20Sopenharmony_ci		break;
708c2ecf20Sopenharmony_ci	default:
718c2ecf20Sopenharmony_ci		BUG();
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic inline void dma_sync_virt_for_cpu(void *addr, size_t size,
768c2ecf20Sopenharmony_ci		enum dma_data_direction dir)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	switch (dir) {
798c2ecf20Sopenharmony_ci	case DMA_TO_DEVICE:
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	case DMA_FROM_DEVICE:
828c2ecf20Sopenharmony_ci	case DMA_BIDIRECTIONAL:
838c2ecf20Sopenharmony_ci		dma_cache_inv((unsigned long)addr, size);
848c2ecf20Sopenharmony_ci		break;
858c2ecf20Sopenharmony_ci	default:
868c2ecf20Sopenharmony_ci		BUG();
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/*
918c2ecf20Sopenharmony_ci * A single sg entry may refer to multiple physically contiguous pages.  But
928c2ecf20Sopenharmony_ci * we still need to process highmem pages individually.  If highmem is not
938c2ecf20Sopenharmony_ci * configured then the bulk of this loop gets optimized out.
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_cistatic inline void dma_sync_phys(phys_addr_t paddr, size_t size,
968c2ecf20Sopenharmony_ci		enum dma_data_direction dir, bool for_device)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
998c2ecf20Sopenharmony_ci	unsigned long offset = paddr & ~PAGE_MASK;
1008c2ecf20Sopenharmony_ci	size_t left = size;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	do {
1038c2ecf20Sopenharmony_ci		size_t len = left;
1048c2ecf20Sopenharmony_ci		void *addr;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		if (PageHighMem(page)) {
1078c2ecf20Sopenharmony_ci			if (offset + len > PAGE_SIZE)
1088c2ecf20Sopenharmony_ci				len = PAGE_SIZE - offset;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		addr = kmap_atomic(page);
1128c2ecf20Sopenharmony_ci		if (for_device)
1138c2ecf20Sopenharmony_ci			dma_sync_virt_for_device(addr + offset, len, dir);
1148c2ecf20Sopenharmony_ci		else
1158c2ecf20Sopenharmony_ci			dma_sync_virt_for_cpu(addr + offset, len, dir);
1168c2ecf20Sopenharmony_ci		kunmap_atomic(addr);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		offset = 0;
1198c2ecf20Sopenharmony_ci		page++;
1208c2ecf20Sopenharmony_ci		left -= len;
1218c2ecf20Sopenharmony_ci	} while (left);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_civoid arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
1258c2ecf20Sopenharmony_ci		enum dma_data_direction dir)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	dma_sync_phys(paddr, size, dir, true);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
1318c2ecf20Sopenharmony_civoid arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
1328c2ecf20Sopenharmony_ci		enum dma_data_direction dir)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	if (cpu_needs_post_dma_flush())
1358c2ecf20Sopenharmony_ci		dma_sync_phys(paddr, size, dir, false);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci#endif
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_PERDEV_COHERENT
1408c2ecf20Sopenharmony_civoid arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
1418c2ecf20Sopenharmony_ci		const struct iommu_ops *iommu, bool coherent)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	dev->dma_coherent = coherent;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci#endif
146