xref: /openbmc/linux/arch/microblaze/kernel/cpu/cache.c (revision b627b4ed)
1 /*
2  * Cache control for MicroBlaze cache memories
3  *
4  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5  * Copyright (C) 2007-2009 PetaLogix
6  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
7  *
8  * This file is subject to the terms and conditions of the GNU General
9  * Public License. See the file COPYING in the main directory of this
10  * archive for more details.
11  */
12 
13 #include <asm/cacheflush.h>
14 #include <linux/cache.h>
15 #include <asm/cpuinfo.h>
16 
17 /* Exported functions */
18 
19 void _enable_icache(void)
20 {
21 	if (cpuinfo.use_icache) {
22 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
23 		__asm__ __volatile__ ("					\
24 				msrset	r0, %0;				\
25 				nop; "					\
26 				:					\
27 				: "i" (MSR_ICE)				\
28 				: "memory");
29 #else
30 		__asm__ __volatile__ ("					\
31 				mfs	r12, rmsr;			\
32 				nop;					\
33 				ori	r12, r12, %0;			\
34 				mts	rmsr, r12;			\
35 				nop; "					\
36 				:					\
37 				: "i" (MSR_ICE)				\
38 				: "memory", "r12");
39 #endif
40 	}
41 }
42 
43 void _disable_icache(void)
44 {
45 	if (cpuinfo.use_icache) {
46 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
47 		__asm__ __volatile__ ("					\
48 				msrclr r0, %0;				\
49 				nop; "					\
50 				:					\
51 				: "i" (MSR_ICE)				\
52 				: "memory");
53 #else
54 		__asm__ __volatile__ ("					\
55 				mfs	r12, rmsr;			\
56 				nop;					\
57 				andi	r12, r12, ~%0;			\
58 				mts	rmsr, r12;			\
59 				nop; "					\
60 				:					\
61 				: "i" (MSR_ICE)				\
62 				: "memory", "r12");
63 #endif
64 	}
65 }
66 
67 void _invalidate_icache(unsigned int addr)
68 {
69 	if (cpuinfo.use_icache) {
70 		__asm__ __volatile__ ("					\
71 				wic	%0, r0"				\
72 				:					\
73 				: "r" (addr));
74 	}
75 }
76 
77 void _enable_dcache(void)
78 {
79 	if (cpuinfo.use_dcache) {
80 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
81 		__asm__ __volatile__ ("					\
82 				msrset	r0, %0;				\
83 				nop; "					\
84 				:					\
85 				: "i" (MSR_DCE)				\
86 				: "memory");
87 #else
88 		__asm__ __volatile__ ("					\
89 				mfs	r12, rmsr;			\
90 				nop;					\
91 				ori	r12, r12, %0;			\
92 				mts	rmsr, r12;			\
93 				nop; "					\
94 				:					\
95 				: "i" (MSR_DCE)			\
96 				: "memory", "r12");
97 #endif
98 	}
99 }
100 
101 void _disable_dcache(void)
102 {
103 	if (cpuinfo.use_dcache) {
104 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
105 		__asm__ __volatile__ ("					\
106 				msrclr	r0, %0;				\
107 				nop; "					\
108 				:					\
109 				: "i" (MSR_DCE)			\
110 				: "memory");
111 #else
112 		__asm__ __volatile__ ("					\
113 				mfs	r12, rmsr;			\
114 				nop;					\
115 				andi	r12, r12, ~%0;			\
116 				mts	rmsr, r12;			\
117 				nop; "					\
118 				:					\
119 				: "i" (MSR_DCE)			\
120 				: "memory", "r12");
121 #endif
122 	}
123 }
124 
125 void _invalidate_dcache(unsigned int addr)
126 {
127 	if (cpuinfo.use_dcache)
128 		__asm__ __volatile__ ("					\
129 				wdc	%0, r0"				\
130 				:					\
131 				: "r" (addr));
132 }
133 
134 void __invalidate_icache_all(void)
135 {
136 	unsigned int i;
137 	unsigned flags;
138 
139 	if (cpuinfo.use_icache) {
140 		local_irq_save(flags);
141 		__disable_icache();
142 
143 		/* Just loop through cache size and invalidate, no need to add
144 			CACHE_BASE address */
145 		for (i = 0; i < cpuinfo.icache_size;
146 			i += cpuinfo.icache_line)
147 				__invalidate_icache(i);
148 
149 		__enable_icache();
150 		local_irq_restore(flags);
151 	}
152 }
153 
154 void __invalidate_icache_range(unsigned long start, unsigned long end)
155 {
156 	unsigned int i;
157 	unsigned flags;
158 	unsigned int align;
159 
160 	if (cpuinfo.use_icache) {
161 		/*
162 		 * No need to cover entire cache range,
163 		 * just cover cache footprint
164 		 */
165 		end = min(start + cpuinfo.icache_size, end);
166 		align = ~(cpuinfo.icache_line - 1);
167 		start &= align; /* Make sure we are aligned */
168 		/* Push end up to the next cache line */
169 		end = ((end & align) + cpuinfo.icache_line);
170 
171 		local_irq_save(flags);
172 		__disable_icache();
173 
174 		for (i = start; i < end; i += cpuinfo.icache_line)
175 			__invalidate_icache(i);
176 
177 		__enable_icache();
178 		local_irq_restore(flags);
179 	}
180 }
181 
182 void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
183 {
184 	__invalidate_icache_all();
185 }
186 
187 void __invalidate_icache_user_range(struct vm_area_struct *vma,
188 				struct page *page, unsigned long adr,
189 				int len)
190 {
191 	__invalidate_icache_all();
192 }
193 
194 void __invalidate_cache_sigtramp(unsigned long addr)
195 {
196 	__invalidate_icache_range(addr, addr + 8);
197 }
198 
199 void __invalidate_dcache_all(void)
200 {
201 	unsigned int i;
202 	unsigned flags;
203 
204 	if (cpuinfo.use_dcache) {
205 		local_irq_save(flags);
206 		__disable_dcache();
207 
208 		/*
209 		 * Just loop through cache size and invalidate,
210 		 * no need to add CACHE_BASE address
211 		 */
212 		for (i = 0; i < cpuinfo.dcache_size;
213 			i += cpuinfo.dcache_line)
214 				__invalidate_dcache(i);
215 
216 		__enable_dcache();
217 		local_irq_restore(flags);
218 	}
219 }
220 
221 void __invalidate_dcache_range(unsigned long start, unsigned long end)
222 {
223 	unsigned int i;
224 	unsigned flags;
225 	unsigned int align;
226 
227 	if (cpuinfo.use_dcache) {
228 		/*
229 		 * No need to cover entire cache range,
230 		 * just cover cache footprint
231 		 */
232 		end = min(start + cpuinfo.dcache_size, end);
233 		align = ~(cpuinfo.dcache_line - 1);
234 		start &= align; /* Make sure we are aligned */
235 		/* Push end up to the next cache line */
236 		end = ((end & align) + cpuinfo.dcache_line);
237 		local_irq_save(flags);
238 		__disable_dcache();
239 
240 		for (i = start; i < end; i += cpuinfo.dcache_line)
241 			__invalidate_dcache(i);
242 
243 		__enable_dcache();
244 		local_irq_restore(flags);
245 	}
246 }
247 
248 void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
249 {
250 	__invalidate_dcache_all();
251 }
252 
253 void __invalidate_dcache_user_range(struct vm_area_struct *vma,
254 				struct page *page, unsigned long adr,
255 				int len)
256 {
257 	__invalidate_dcache_all();
258 }
259