1/* MN10300 CPU core caching routines
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/sys.h>
12#include <linux/linkage.h>
13#include <asm/smp.h>
14#include <asm/page.h>
15#include <asm/cache.h>
16#include <asm/irqflags.h>
17#include <asm/cacheflush.h>
18#include "cache.inc"
19
20#define mn10300_local_dcache_inv_range_intr_interval \
21	+((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
22
23#if mn10300_local_dcache_inv_range_intr_interval > 0xff
24#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
25#endif
26
27	.am33_2
28
29	.globl	mn10300_local_icache_inv_page
30	.globl	mn10300_local_icache_inv_range
31	.globl	mn10300_local_icache_inv_range2
32
33mn10300_local_icache_inv_page	= mn10300_local_icache_inv
34mn10300_local_icache_inv_range	= mn10300_local_icache_inv
35mn10300_local_icache_inv_range2	= mn10300_local_icache_inv
36
37#ifndef CONFIG_SMP
38	.globl	mn10300_icache_inv
39	.globl	mn10300_icache_inv_page
40	.globl	mn10300_icache_inv_range
41	.globl	mn10300_icache_inv_range2
42	.globl	mn10300_dcache_inv
43	.globl	mn10300_dcache_inv_page
44	.globl	mn10300_dcache_inv_range
45	.globl	mn10300_dcache_inv_range2
46
47mn10300_icache_inv		= mn10300_local_icache_inv
48mn10300_icache_inv_page		= mn10300_local_icache_inv_page
49mn10300_icache_inv_range	= mn10300_local_icache_inv_range
50mn10300_icache_inv_range2	= mn10300_local_icache_inv_range2
51mn10300_dcache_inv		= mn10300_local_dcache_inv
52mn10300_dcache_inv_page		= mn10300_local_dcache_inv_page
53mn10300_dcache_inv_range	= mn10300_local_dcache_inv_range
54mn10300_dcache_inv_range2	= mn10300_local_dcache_inv_range2
55
56#endif /* !CONFIG_SMP */
57
58###############################################################################
59#
60# void mn10300_local_icache_inv(void)
61# Invalidate the entire icache
62#
63###############################################################################
64	ALIGN
65	.globl	mn10300_local_icache_inv
66        .type	mn10300_local_icache_inv,@function
67mn10300_local_icache_inv:
68	mov	CHCTR,a0
69
70	movhu	(a0),d0
71	btst	CHCTR_ICEN,d0
72	beq	mn10300_local_icache_inv_end
73
74	invalidate_icache 1
75
76mn10300_local_icache_inv_end:
77	ret	[],0
78	.size	mn10300_local_icache_inv,.-mn10300_local_icache_inv
79
80###############################################################################
81#
82# void mn10300_local_dcache_inv(void)
83# Invalidate the entire dcache
84#
85###############################################################################
86	ALIGN
87	.globl	mn10300_local_dcache_inv
88	.type	mn10300_local_dcache_inv,@function
89mn10300_local_dcache_inv:
90	mov	CHCTR,a0
91
92	movhu	(a0),d0
93	btst	CHCTR_DCEN,d0
94	beq	mn10300_local_dcache_inv_end
95
96	invalidate_dcache 1
97
98mn10300_local_dcache_inv_end:
99	ret	[],0
100	.size	mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
101
102###############################################################################
103#
104# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
105# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
106# void mn10300_local_dcache_inv_page(unsigned long start)
107# Invalidate a range of addresses on a page in the dcache
108#
109###############################################################################
110	ALIGN
111	.globl	mn10300_local_dcache_inv_page
112	.globl	mn10300_local_dcache_inv_range
113	.globl	mn10300_local_dcache_inv_range2
114	.type	mn10300_local_dcache_inv_page,@function
115	.type	mn10300_local_dcache_inv_range,@function
116	.type	mn10300_local_dcache_inv_range2,@function
117mn10300_local_dcache_inv_page:
118	and	~(PAGE_SIZE-1),d0
119	mov	PAGE_SIZE,d1
120mn10300_local_dcache_inv_range2:
121	add	d0,d1
122mn10300_local_dcache_inv_range:
123	# If we are in writeback mode we check the start and end alignments,
124	# and if they're not cacheline-aligned, we must flush any bits outside
125	# the range that share cachelines with stuff inside the range
126#ifdef CONFIG_MN10300_CACHE_WBACK
127	btst	~L1_CACHE_TAG_MASK,d0
128	bne	1f
129	btst	~L1_CACHE_TAG_MASK,d1
130	beq	2f
1311:
132	bra	mn10300_local_dcache_flush_inv_range
1332:
134#endif /* CONFIG_MN10300_CACHE_WBACK */
135
136	movm	[d2,d3,a2],(sp)
137
138	mov	CHCTR,a2
139	movhu	(a2),d2
140	btst	CHCTR_DCEN,d2
141	beq	mn10300_local_dcache_inv_range_end
142
143#ifndef CONFIG_MN10300_CACHE_WBACK
144	and	L1_CACHE_TAG_MASK,d0		# round start addr down
145
146	add	L1_CACHE_BYTES,d1		# round end addr up
147	and	L1_CACHE_TAG_MASK,d1
148#endif /* !CONFIG_MN10300_CACHE_WBACK */
149	mov	d0,a1
150
151	clr	d2				# we're going to clear tag RAM
152						# entries
153
154	# read the tags from the tag RAM, and if they indicate a valid dirty
155	# cache line then invalidate that line
156	mov	DCACHE_TAG(0,0),a0
157	mov	a1,d0
158	and	L1_CACHE_TAG_ENTRY,d0
159	add	d0,a0				# starting dcache tag RAM
160						# access address
161
162	sub	a1,d1
163	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
164						# examine
165
166	and	~(L1_CACHE_DISPARITY-1),a1	# determine comparator base
167
168mn10300_local_dcache_inv_range_outer_loop:
169	LOCAL_CLI_SAVE(d3)
170
171	# disable the dcache
172	movhu	(a2),d0
173	and	~CHCTR_DCEN,d0
174	movhu	d0,(a2)
175
176	# and wait for it to calm down
177	setlb
178	movhu	(a2),d0
179	btst	CHCTR_DCBUSY,d0
180	lne
181
182mn10300_local_dcache_inv_range_loop:
183
184	# process the way 0 slot
185	mov	(L1_CACHE_WAYDISP*0,a0),d0	# read the tag in the way 0 slot
186	btst	L1_CACHE_TAG_VALID,d0
187	beq	mn10300_local_dcache_inv_range_skip_0	# jump if this cacheline
188						# is not valid
189
190	xor	a1,d0
191	lsr	12,d0
192	bne	mn10300_local_dcache_inv_range_skip_0	# jump if not this cacheline
193
194	mov	d2,(L1_CACHE_WAYDISP*0,a0)	# kill the tag
195
196mn10300_local_dcache_inv_range_skip_0:
197
198	# process the way 1 slot
199	mov	(L1_CACHE_WAYDISP*1,a0),d0	# read the tag in the way 1 slot
200	btst	L1_CACHE_TAG_VALID,d0
201	beq	mn10300_local_dcache_inv_range_skip_1	# jump if this cacheline
202						# is not valid
203
204	xor	a1,d0
205	lsr	12,d0
206	bne	mn10300_local_dcache_inv_range_skip_1	# jump if not this cacheline
207
208	mov	d2,(L1_CACHE_WAYDISP*1,a0)	# kill the tag
209
210mn10300_local_dcache_inv_range_skip_1:
211
212	# process the way 2 slot
213	mov	(L1_CACHE_WAYDISP*2,a0),d0	# read the tag in the way 2 slot
214	btst	L1_CACHE_TAG_VALID,d0
215	beq	mn10300_local_dcache_inv_range_skip_2	# jump if this cacheline
216						# is not valid
217
218	xor	a1,d0
219	lsr	12,d0
220	bne	mn10300_local_dcache_inv_range_skip_2	# jump if not this cacheline
221
222	mov	d2,(L1_CACHE_WAYDISP*2,a0)	# kill the tag
223
224mn10300_local_dcache_inv_range_skip_2:
225
226	# process the way 3 slot
227	mov	(L1_CACHE_WAYDISP*3,a0),d0	# read the tag in the way 3 slot
228	btst	L1_CACHE_TAG_VALID,d0
229	beq	mn10300_local_dcache_inv_range_skip_3	# jump if this cacheline
230						# is not valid
231
232	xor	a1,d0
233	lsr	12,d0
234	bne	mn10300_local_dcache_inv_range_skip_3	# jump if not this cacheline
235
236	mov	d2,(L1_CACHE_WAYDISP*3,a0)	# kill the tag
237
238mn10300_local_dcache_inv_range_skip_3:
239
240	# approx every N steps we re-enable the cache and see if there are any
241	# interrupts to be processed
242	# we also break out if we've reached the end of the loop
243	# (the bottom nibble of the count is zero in both cases)
244	add	L1_CACHE_BYTES,a0
245	add	L1_CACHE_BYTES,a1
246	and	~L1_CACHE_WAYDISP,a0
247	add	-1,d1
248	btst	mn10300_local_dcache_inv_range_intr_interval,d1
249	bne	mn10300_local_dcache_inv_range_loop
250
251	# wait for the cache to finish what it's doing
252	setlb
253	movhu	(a2),d0
254	btst	CHCTR_DCBUSY,d0
255	lne
256
257	# and reenable it
258	or	CHCTR_DCEN,d0
259	movhu	d0,(a2)
260	movhu	(a2),d0
261
262	# re-enable interrupts
263	# - we don't bother with delay NOPs as we'll have enough instructions
264	#   before we disable interrupts again to give the interrupts a chance
265	#   to happen
266	LOCAL_IRQ_RESTORE(d3)
267
268	# go around again if the counter hasn't yet reached zero
269	add	0,d1
270	bne	mn10300_local_dcache_inv_range_outer_loop
271
272mn10300_local_dcache_inv_range_end:
273	ret	[d2,d3,a2],12
274	.size	mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
275	.size	mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
276	.size	mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
277