Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/m68k/mm/memory.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* linux/arch/m68k/mm/memory.c
4
*
5
* Copyright (C) 1995 Hamish Macdonald
6
*/
7
8
#include <linux/module.h>
9
#include <linux/mm.h>
10
#include <linux/kernel.h>
11
#include <linux/string.h>
12
#include <linux/types.h>
13
#include <linux/init.h>
14
#include <linux/pagemap.h>
15
#include <linux/gfp.h>
16
17
#include <asm/setup.h>
18
#include <asm/page.h>
19
#include <asm/traps.h>
20
#include <asm/machdep.h>
21
22
23
/* invalidate page in both caches */
24
static inline void clear040(unsigned long paddr)
25
{
26
asm volatile (
27
"nop\n\t"
28
".chip 68040\n\t"
29
"cinvp %%bc,(%0)\n\t"
30
".chip 68k"
31
: : "a" (paddr));
32
}
33
34
/* invalidate page in i-cache */
35
static inline void cleari040(unsigned long paddr)
36
{
37
asm volatile (
38
"nop\n\t"
39
".chip 68040\n\t"
40
"cinvp %%ic,(%0)\n\t"
41
".chip 68k"
42
: : "a" (paddr));
43
}
44
45
/* push page in both caches */
46
/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
47
static inline void push040(unsigned long paddr)
48
{
49
asm volatile (
50
"nop\n\t"
51
".chip 68040\n\t"
52
"cpushp %%bc,(%0)\n\t"
53
".chip 68k"
54
: : "a" (paddr));
55
}
56
57
/* push and invalidate page in both caches, must disable ints
58
* to avoid invalidating valid data */
59
static inline void pushcl040(unsigned long paddr)
60
{
61
unsigned long flags;
62
63
local_irq_save(flags);
64
push040(paddr);
65
if (CPU_IS_060)
66
clear040(paddr);
67
local_irq_restore(flags);
68
}
69
70
/*
71
* 040: Hit every page containing an address in the range paddr..paddr+len-1.
72
* (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s).
73
* Hit every page until there is a page or less to go. Hit the next page,
74
* and the one after that if the range hits it.
75
*/
76
/* ++roman: A little bit more care is required here: The CINVP instruction
77
* invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning
78
* and the end of the region must be treated differently if they are not
79
* exactly at the beginning or end of a page boundary. Else, maybe too much
80
* data becomes invalidated and thus lost forever. CPUSHP does what we need:
81
* it invalidates the page after pushing dirty data to memory. (Thanks to Jes
82
* for discovering the problem!)
83
*/
84
/* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set
85
* the DPI bit in the CACR; would it cause problems with temporarily changing
86
* this?). So we have to push first and then additionally to invalidate.
87
*/
88
89
90
/*
91
* cache_clear() semantics: Clear any cache entries for the area in question,
92
* without writing back dirty entries first. This is useful if the data will
93
* be overwritten anyway, e.g. by DMA to memory. The range is defined by a
94
* _physical_ address.
95
*/
96
97
void cache_clear (unsigned long paddr, int len)
98
{
99
if (CPU_IS_COLDFIRE) {
100
clear_cf_bcache(0, DCACHE_MAX_ADDR);
101
} else if (CPU_IS_040_OR_060) {
102
int tmp;
103
104
/*
105
* We need special treatment for the first page, in case it
106
* is not page-aligned. Page align the addresses to work
107
* around bug I17 in the 68060.
108
*/
109
if ((tmp = -paddr & (PAGE_SIZE - 1))) {
110
pushcl040(paddr & PAGE_MASK);
111
if ((len -= tmp) <= 0)
112
return;
113
paddr += tmp;
114
}
115
tmp = PAGE_SIZE;
116
paddr &= PAGE_MASK;
117
while ((len -= tmp) >= 0) {
118
clear040(paddr);
119
paddr += tmp;
120
}
121
if ((len += tmp))
122
/* a page boundary gets crossed at the end */
123
pushcl040(paddr);
124
}
125
else /* 68030 or 68020 */
126
asm volatile ("movec %/cacr,%/d0\n\t"
127
"oriw %0,%/d0\n\t"
128
"movec %/d0,%/cacr"
129
: : "i" (FLUSH_I_AND_D)
130
: "d0");
131
#ifdef CONFIG_M68K_L2_CACHE
132
if(mach_l2_flush)
133
mach_l2_flush(0);
134
#endif
135
}
136
EXPORT_SYMBOL(cache_clear);
137
138
139
/*
140
* cache_push() semantics: Write back any dirty cache data in the given area,
141
* and invalidate the range in the instruction cache. It needs not (but may)
142
* invalidate those entries also in the data cache. The range is defined by a
143
* _physical_ address.
144
*/
145
146
void cache_push (unsigned long paddr, int len)
147
{
148
if (CPU_IS_COLDFIRE) {
149
flush_cf_bcache(0, DCACHE_MAX_ADDR);
150
} else if (CPU_IS_040_OR_060) {
151
int tmp = PAGE_SIZE;
152
153
/*
154
* on 68040 or 68060, push cache lines for pages in the range;
155
* on the '040 this also invalidates the pushed lines, but not on
156
* the '060!
157
*/
158
len += paddr & (PAGE_SIZE - 1);
159
160
/*
161
* Work around bug I17 in the 68060 affecting some instruction
162
* lines not being invalidated properly.
163
*/
164
paddr &= PAGE_MASK;
165
166
do {
167
push040(paddr);
168
paddr += tmp;
169
} while ((len -= tmp) > 0);
170
}
171
/*
172
* 68030/68020 have no writeback cache. On the other hand,
173
* cache_push is actually a superset of cache_clear (the lines
174
* get written back and invalidated), so we should make sure
175
* to perform the corresponding actions. After all, this is getting
176
* called in places where we've just loaded code, or whatever, so
177
* flushing the icache is appropriate; flushing the dcache shouldn't
178
* be required.
179
*/
180
else /* 68030 or 68020 */
181
asm volatile ("movec %/cacr,%/d0\n\t"
182
"oriw %0,%/d0\n\t"
183
"movec %/d0,%/cacr"
184
: : "i" (FLUSH_I)
185
: "d0");
186
#ifdef CONFIG_M68K_L2_CACHE
187
if(mach_l2_flush)
188
mach_l2_flush(1);
189
#endif
190
}
191
EXPORT_SYMBOL(cache_push);
192
193
194