162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cache management functions for Hexagon
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/mm.h>
962306a36Sopenharmony_ci#include <asm/cacheflush.h>
1062306a36Sopenharmony_ci#include <asm/hexagon_vm.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define spanlines(start, end) \
1362306a36Sopenharmony_ci	(((end - (start & ~(LINESIZE - 1))) >> LINEBITS) + 1)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_civoid flush_dcache_range(unsigned long start, unsigned long end)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	unsigned long lines = spanlines(start, end-1);
1862306a36Sopenharmony_ci	unsigned long i, flags;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	start &= ~(LINESIZE - 1);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	local_irq_save(flags);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	for (i = 0; i < lines; i++) {
2562306a36Sopenharmony_ci		__asm__ __volatile__ (
2662306a36Sopenharmony_ci		"	dccleaninva(%0);	"
2762306a36Sopenharmony_ci		:
2862306a36Sopenharmony_ci		: "r" (start)
2962306a36Sopenharmony_ci		);
3062306a36Sopenharmony_ci		start += LINESIZE;
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci	local_irq_restore(flags);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_civoid flush_icache_range(unsigned long start, unsigned long end)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	unsigned long lines = spanlines(start, end-1);
3862306a36Sopenharmony_ci	unsigned long i, flags;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	start &= ~(LINESIZE - 1);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	local_irq_save(flags);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	for (i = 0; i < lines; i++) {
4562306a36Sopenharmony_ci		__asm__ __volatile__ (
4662306a36Sopenharmony_ci			"	dccleana(%0); "
4762306a36Sopenharmony_ci			"	icinva(%0);	"
4862306a36Sopenharmony_ci			:
4962306a36Sopenharmony_ci			: "r" (start)
5062306a36Sopenharmony_ci		);
5162306a36Sopenharmony_ci		start += LINESIZE;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	__asm__ __volatile__ (
5462306a36Sopenharmony_ci		"isync"
5562306a36Sopenharmony_ci	);
5662306a36Sopenharmony_ci	local_irq_restore(flags);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ciEXPORT_SYMBOL(flush_icache_range);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_civoid hexagon_clean_dcache_range(unsigned long start, unsigned long end)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	unsigned long lines = spanlines(start, end-1);
6362306a36Sopenharmony_ci	unsigned long i, flags;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	start &= ~(LINESIZE - 1);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	local_irq_save(flags);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	for (i = 0; i < lines; i++) {
7062306a36Sopenharmony_ci		__asm__ __volatile__ (
7162306a36Sopenharmony_ci		"	dccleana(%0);	"
7262306a36Sopenharmony_ci		:
7362306a36Sopenharmony_ci		: "r" (start)
7462306a36Sopenharmony_ci		);
7562306a36Sopenharmony_ci		start += LINESIZE;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	local_irq_restore(flags);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_civoid hexagon_inv_dcache_range(unsigned long start, unsigned long end)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	unsigned long lines = spanlines(start, end-1);
8362306a36Sopenharmony_ci	unsigned long i, flags;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	start &= ~(LINESIZE - 1);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	local_irq_save(flags);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	for (i = 0; i < lines; i++) {
9062306a36Sopenharmony_ci		__asm__ __volatile__ (
9162306a36Sopenharmony_ci		"	dcinva(%0);	"
9262306a36Sopenharmony_ci		:
9362306a36Sopenharmony_ci		: "r" (start)
9462306a36Sopenharmony_ci		);
9562306a36Sopenharmony_ci		start += LINESIZE;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	local_irq_restore(flags);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci * This is just really brutal and shouldn't be used anyways,
10562306a36Sopenharmony_ci * especially on V2.  Left here just in case.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_civoid flush_cache_all_hexagon(void)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	unsigned long flags;
11062306a36Sopenharmony_ci	local_irq_save(flags);
11162306a36Sopenharmony_ci	__vmcache_ickill();
11262306a36Sopenharmony_ci	__vmcache_dckill();
11362306a36Sopenharmony_ci	__vmcache_l2kill();
11462306a36Sopenharmony_ci	local_irq_restore(flags);
11562306a36Sopenharmony_ci	mb();
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_civoid copy_to_user_page(struct vm_area_struct *vma, struct page *page,
11962306a36Sopenharmony_ci		       unsigned long vaddr, void *dst, void *src, int len)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	memcpy(dst, src, len);
12262306a36Sopenharmony_ci	if (vma->vm_flags & VM_EXEC) {
12362306a36Sopenharmony_ci		flush_icache_range((unsigned long) dst,
12462306a36Sopenharmony_ci		(unsigned long) dst + len);
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci}
127