Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mn10300/mm/cache-inv-by-reg.S
10817 views
1
/* MN10300 CPU cache invalidation routines, using automatic purge registers
2
*
3
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
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
#ifndef CONFIG_SMP
30
.globl mn10300_icache_inv
31
.globl mn10300_icache_inv_page
32
.globl mn10300_icache_inv_range
33
.globl mn10300_icache_inv_range2
34
.globl mn10300_dcache_inv
35
.globl mn10300_dcache_inv_page
36
.globl mn10300_dcache_inv_range
37
.globl mn10300_dcache_inv_range2
38
39
mn10300_icache_inv = mn10300_local_icache_inv
40
mn10300_icache_inv_page = mn10300_local_icache_inv_page
41
mn10300_icache_inv_range = mn10300_local_icache_inv_range
42
mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
43
mn10300_dcache_inv = mn10300_local_dcache_inv
44
mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
45
mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
46
mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
47
48
#endif /* !CONFIG_SMP */
49
50
###############################################################################
51
#
52
# void mn10300_local_icache_inv(void)
53
# Invalidate the entire icache
54
#
55
###############################################################################
56
ALIGN
57
.globl mn10300_local_icache_inv
58
.type mn10300_local_icache_inv,@function
59
mn10300_local_icache_inv:
60
mov CHCTR,a0
61
62
movhu (a0),d0
63
btst CHCTR_ICEN,d0
64
beq mn10300_local_icache_inv_end
65
66
invalidate_icache 1
67
68
mn10300_local_icache_inv_end:
69
ret [],0
70
.size mn10300_local_icache_inv,.-mn10300_local_icache_inv
71
72
###############################################################################
73
#
74
# void mn10300_local_dcache_inv(void)
75
# Invalidate the entire dcache
76
#
77
###############################################################################
78
ALIGN
79
.globl mn10300_local_dcache_inv
80
.type mn10300_local_dcache_inv,@function
81
mn10300_local_dcache_inv:
82
mov CHCTR,a0
83
84
movhu (a0),d0
85
btst CHCTR_DCEN,d0
86
beq mn10300_local_dcache_inv_end
87
88
invalidate_dcache 1
89
90
mn10300_local_dcache_inv_end:
91
ret [],0
92
.size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
93
94
###############################################################################
95
#
96
# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
97
# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
98
# void mn10300_local_dcache_inv_page(unsigned long start)
99
# Invalidate a range of addresses on a page in the dcache
100
#
101
###############################################################################
102
ALIGN
103
.globl mn10300_local_dcache_inv_page
104
.globl mn10300_local_dcache_inv_range
105
.globl mn10300_local_dcache_inv_range2
106
.type mn10300_local_dcache_inv_page,@function
107
.type mn10300_local_dcache_inv_range,@function
108
.type mn10300_local_dcache_inv_range2,@function
109
mn10300_local_dcache_inv_page:
110
and ~(PAGE_SIZE-1),d0
111
mov PAGE_SIZE,d1
112
mn10300_local_dcache_inv_range2:
113
add d0,d1
114
mn10300_local_dcache_inv_range:
115
# If we are in writeback mode we check the start and end alignments,
116
# and if they're not cacheline-aligned, we must flush any bits outside
117
# the range that share cachelines with stuff inside the range
118
#ifdef CONFIG_MN10300_CACHE_WBACK
119
btst ~L1_CACHE_TAG_MASK,d0
120
bne 1f
121
btst ~L1_CACHE_TAG_MASK,d1
122
beq 2f
123
1:
124
bra mn10300_local_dcache_flush_inv_range
125
2:
126
#endif /* CONFIG_MN10300_CACHE_WBACK */
127
128
movm [d2,d3,a2],(sp)
129
130
mov CHCTR,a0
131
movhu (a0),d2
132
btst CHCTR_DCEN,d2
133
beq mn10300_local_dcache_inv_range_end
134
135
# round the addresses out to be full cachelines, unless we're in
136
# writeback mode, in which case we would be in flush and invalidate by
137
# now
138
#ifndef CONFIG_MN10300_CACHE_WBACK
139
and L1_CACHE_TAG_MASK,d0 # round start addr down
140
141
mov L1_CACHE_BYTES-1,d2
142
add d2,d1
143
and L1_CACHE_TAG_MASK,d1 # round end addr up
144
#endif /* !CONFIG_MN10300_CACHE_WBACK */
145
146
sub d0,d1,d2 # calculate the total size
147
mov d0,a2 # A2 = start address
148
mov d1,a1 # A1 = end address
149
150
LOCAL_CLI_SAVE(d3)
151
152
mov DCPGCR,a0 # make sure the purger isn't busy
153
setlb
154
mov (a0),d0
155
btst DCPGCR_DCPGBSY,d0
156
lne
157
158
# skip initial address alignment calculation if address is zero
159
mov d2,d1
160
cmp 0,a2
161
beq 1f
162
163
dcivloop:
164
/* calculate alignsize
165
*
166
* alignsize = L1_CACHE_BYTES;
167
* while (! start & alignsize) {
168
* alignsize <<=1;
169
* }
170
* d1 = alignsize;
171
*/
172
mov L1_CACHE_BYTES,d1
173
lsr 1,d1
174
setlb
175
add d1,d1
176
mov d1,d0
177
and a2,d0
178
leq
179
180
1:
181
/* calculate invsize
182
*
183
* if (totalsize > alignsize) {
184
* invsize = alignsize;
185
* } else {
186
* invsize = totalsize;
187
* tmp = 0x80000000;
188
* while (! invsize & tmp) {
189
* tmp >>= 1;
190
* }
191
* invsize = tmp;
192
* }
193
* d1 = invsize
194
*/
195
cmp d2,d1
196
bns 2f
197
mov d2,d1
198
199
mov 0x80000000,d0 # start from 31bit=1
200
setlb
201
lsr 1,d0
202
mov d0,e0
203
and d1,e0
204
leq
205
mov d0,d1
206
207
2:
208
/* set mask
209
*
210
* mask = ~(invsize-1);
211
* DCPGMR = mask;
212
*/
213
mov d1,d0
214
add -1,d0
215
not d0
216
mov d0,(DCPGMR)
217
218
# invalidate area
219
mov a2,d0
220
or DCPGCR_DCI,d0
221
mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI
222
223
setlb # wait for the purge to complete
224
mov (a0),d0
225
btst DCPGCR_DCPGBSY,d0
226
lne
227
228
sub d1,d2 # decrease size remaining
229
add d1,a2 # increase next start address
230
231
/* check invalidating of end address
232
*
233
* a2 = a2 + invsize
234
* if (a2 < end) {
235
* goto dcivloop;
236
* } */
237
cmp a1,a2
238
bns dcivloop
239
240
LOCAL_IRQ_RESTORE(d3)
241
242
mn10300_local_dcache_inv_range_end:
243
ret [d2,d3,a2],12
244
.size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
245
.size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
246
.size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
247
248
###############################################################################
249
#
250
# void mn10300_local_icache_inv_page(unsigned long start)
251
# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)
252
# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)
253
# Invalidate a range of addresses on a page in the icache
254
#
255
###############################################################################
256
ALIGN
257
.globl mn10300_local_icache_inv_page
258
.globl mn10300_local_icache_inv_range
259
.globl mn10300_local_icache_inv_range2
260
.type mn10300_local_icache_inv_page,@function
261
.type mn10300_local_icache_inv_range,@function
262
.type mn10300_local_icache_inv_range2,@function
263
mn10300_local_icache_inv_page:
264
and ~(PAGE_SIZE-1),d0
265
mov PAGE_SIZE,d1
266
mn10300_local_icache_inv_range2:
267
add d0,d1
268
mn10300_local_icache_inv_range:
269
movm [d2,d3,a2],(sp)
270
271
mov CHCTR,a0
272
movhu (a0),d2
273
btst CHCTR_ICEN,d2
274
beq mn10300_local_icache_inv_range_reg_end
275
276
/* calculate alignsize
277
*
278
* alignsize = L1_CACHE_BYTES;
279
* for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {
280
* alignsize <<= 1;
281
* }
282
* d2 = alignsize;
283
*/
284
mov L1_CACHE_BYTES,d2
285
sub d0,d1,d3
286
add -1,d3
287
lsr L1_CACHE_SHIFT,d3
288
beq 2f
289
1:
290
add d2,d2
291
lsr 1,d3
292
bne 1b
293
2:
294
295
/* a1 = end */
296
mov d1,a1
297
298
LOCAL_CLI_SAVE(d3)
299
300
mov ICIVCR,a0
301
/* wait for busy bit of area invalidation */
302
setlb
303
mov (a0),d1
304
btst ICIVCR_ICIVBSY,d1
305
lne
306
307
/* set mask
308
*
309
* mask = ~(alignsize-1);
310
* ICIVMR = mask;
311
*/
312
mov d2,d1
313
add -1,d1
314
not d1
315
mov d1,(ICIVMR)
316
/* a2 = mask & start */
317
and d1,d0,a2
318
319
icivloop:
320
/* area invalidate
321
*
322
* ICIVCR = (mask & start) | ICIVCR_ICI
323
*/
324
mov a2,d0
325
or ICIVCR_ICI,d0
326
mov d0,(a0)
327
328
/* wait for busy bit of area invalidation */
329
setlb
330
mov (a0),d1
331
btst ICIVCR_ICIVBSY,d1
332
lne
333
334
/* check invalidating of end address
335
*
336
* a2 = a2 + alignsize
337
* if (a2 < end) {
338
* goto icivloop;
339
* } */
340
add d2,a2
341
cmp a1,a2
342
bns icivloop
343
344
LOCAL_IRQ_RESTORE(d3)
345
346
mn10300_local_icache_inv_range_reg_end:
347
ret [d2,d3,a2],12
348
.size mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page
349
.size mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range
350
.size mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2
351
352