1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Cache management functions for Hexagon
4  *
5  * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
6  */
7 
8 #include <linux/mm.h>
9 #include <asm/cacheflush.h>
10 #include <asm/hexagon_vm.h>
11 
12 #define spanlines(start, end) \
13 	(((end - (start & ~(LINESIZE - 1))) >> LINEBITS) + 1)
14 
flush_dcache_range(unsigned long start,unsigned long end)15 void flush_dcache_range(unsigned long start, unsigned long end)
16 {
17 	unsigned long lines = spanlines(start, end-1);
18 	unsigned long i, flags;
19 
20 	start &= ~(LINESIZE - 1);
21 
22 	local_irq_save(flags);
23 
24 	for (i = 0; i < lines; i++) {
25 		__asm__ __volatile__ (
26 		"	dccleaninva(%0);	"
27 		:
28 		: "r" (start)
29 		);
30 		start += LINESIZE;
31 	}
32 	local_irq_restore(flags);
33 }
34 
flush_icache_range(unsigned long start,unsigned long end)35 void flush_icache_range(unsigned long start, unsigned long end)
36 {
37 	unsigned long lines = spanlines(start, end-1);
38 	unsigned long i, flags;
39 
40 	start &= ~(LINESIZE - 1);
41 
42 	local_irq_save(flags);
43 
44 	for (i = 0; i < lines; i++) {
45 		__asm__ __volatile__ (
46 			"	dccleana(%0); "
47 			"	icinva(%0);	"
48 			:
49 			: "r" (start)
50 		);
51 		start += LINESIZE;
52 	}
53 	__asm__ __volatile__ (
54 		"isync"
55 	);
56 	local_irq_restore(flags);
57 }
58 EXPORT_SYMBOL(flush_icache_range);
59 
hexagon_clean_dcache_range(unsigned long start,unsigned long end)60 void hexagon_clean_dcache_range(unsigned long start, unsigned long end)
61 {
62 	unsigned long lines = spanlines(start, end-1);
63 	unsigned long i, flags;
64 
65 	start &= ~(LINESIZE - 1);
66 
67 	local_irq_save(flags);
68 
69 	for (i = 0; i < lines; i++) {
70 		__asm__ __volatile__ (
71 		"	dccleana(%0);	"
72 		:
73 		: "r" (start)
74 		);
75 		start += LINESIZE;
76 	}
77 	local_irq_restore(flags);
78 }
79 
hexagon_inv_dcache_range(unsigned long start,unsigned long end)80 void hexagon_inv_dcache_range(unsigned long start, unsigned long end)
81 {
82 	unsigned long lines = spanlines(start, end-1);
83 	unsigned long i, flags;
84 
85 	start &= ~(LINESIZE - 1);
86 
87 	local_irq_save(flags);
88 
89 	for (i = 0; i < lines; i++) {
90 		__asm__ __volatile__ (
91 		"	dcinva(%0);	"
92 		:
93 		: "r" (start)
94 		);
95 		start += LINESIZE;
96 	}
97 	local_irq_restore(flags);
98 }
99 
100 
101 
102 
103 /*
104  * This is just really brutal and shouldn't be used anyways,
105  * especially on V2.  Left here just in case.
106  */
flush_cache_all_hexagon(void)107 void flush_cache_all_hexagon(void)
108 {
109 	unsigned long flags;
110 	local_irq_save(flags);
111 	__vmcache_ickill();
112 	__vmcache_dckill();
113 	__vmcache_l2kill();
114 	local_irq_restore(flags);
115 	mb();
116 }
117 
copy_to_user_page(struct vm_area_struct * vma,struct page * page,unsigned long vaddr,void * dst,void * src,int len)118 void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
119 		       unsigned long vaddr, void *dst, void *src, int len)
120 {
121 	memcpy(dst, src, len);
122 	if (vma->vm_flags & VM_EXEC) {
123 		flush_icache_range((unsigned long) dst,
124 		(unsigned long) dst + len);
125 	}
126 }
127