1#include <linux/init.h>
2#include <linux/mm.h>
3#include <asm/mtrr.h>
4#include <asm/msr.h>
5#include <asm/io.h>
6#include "mtrr.h"
7
8int arr3_protected;
9
10static void
11cyrix_get_arr(unsigned int reg, unsigned long *base,
12 unsigned int *size, mtrr_type * type)
13{
14 unsigned long flags;
15 unsigned char arr, ccr3, rcr, shift;
16
17 arr = CX86_ARR_BASE + (reg << 1) + reg;
18
19
20 local_irq_save(flags);
21
22 ccr3 = getCx86(CX86_CCR3);
23 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
24 ((unsigned char *) base)[3] = getCx86(arr);
25 ((unsigned char *) base)[2] = getCx86(arr + 1);
26 ((unsigned char *) base)[1] = getCx86(arr + 2);
27 rcr = getCx86(CX86_RCR_BASE + reg);
28 setCx86(CX86_CCR3, ccr3);
29
30
31 local_irq_restore(flags);
32 shift = ((unsigned char *) base)[1] & 0x0f;
33 *base >>= PAGE_SHIFT;
34
35
36
37
38 if (shift)
39 *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
40 else
41 *size = 0;
42
43
44 if (reg < 7) {
45 switch (rcr) {
46 case 1:
47 *type = MTRR_TYPE_UNCACHABLE;
48 break;
49 case 8:
50 *type = MTRR_TYPE_WRBACK;
51 break;
52 case 9:
53 *type = MTRR_TYPE_WRCOMB;
54 break;
55 case 24:
56 default:
57 *type = MTRR_TYPE_WRTHROUGH;
58 break;
59 }
60 } else {
61 switch (rcr) {
62 case 0:
63 *type = MTRR_TYPE_UNCACHABLE;
64 break;
65 case 8:
66 *type = MTRR_TYPE_WRCOMB;
67 break;
68 case 9:
69 *type = MTRR_TYPE_WRBACK;
70 break;
71 case 25:
72 default:
73 *type = MTRR_TYPE_WRTHROUGH;
74 break;
75 }
76 }
77}
78
79static int
80cyrix_get_free_region(unsigned long base, unsigned long size)
81
82
83
84
85
86{
87 int i;
88 mtrr_type ltype;
89 unsigned long lbase;
90 unsigned int lsize;
91
92
93 if (size > 0x2000) {
94 cyrix_get_arr(7, &lbase, &lsize, <ype);
95 if (lsize == 0)
96 return 7;
97
98 } else {
99 for (i = 0; i < 7; i++) {
100 cyrix_get_arr(i, &lbase, &lsize, <ype);
101 if ((i == 3) && arr3_protected)
102 continue;
103 if (lsize == 0)
104 return i;
105 }
106
107 cyrix_get_arr(i, &lbase, &lsize, <ype);
108 if ((lsize == 0) && (size >= 0x40))
109 return i;
110 }
111 return -ENOSPC;
112}
113
114static u32 cr4 = 0;
115static u32 ccr3;
116
117static void prepare_set(void)
118{
119 u32 cr0;
120
121
122 if ( cpu_has_pge ) {
123 cr4 = read_cr4();
124 write_cr4(cr4 & (unsigned char) ~(1 << 7));
125 }
126
127
128
129 cr0 = read_cr0() | 0x40000000;
130 wbinvd();
131 write_cr0(cr0);
132 wbinvd();
133
134
135 ccr3 = getCx86(CX86_CCR3);
136
137
138 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
139
140}
141
142static void post_set(void)
143{
144
145 wbinvd();
146
147
148 setCx86(CX86_CCR3, ccr3);
149
150
151 write_cr0(read_cr0() & 0xbfffffff);
152
153
154 if ( cpu_has_pge )
155 write_cr4(cr4);
156}
157
158static void cyrix_set_arr(unsigned int reg, unsigned long base,
159 unsigned long size, mtrr_type type)
160{
161 unsigned char arr, arr_type, arr_size;
162
163 arr = CX86_ARR_BASE + (reg << 1) + reg;
164
165
166 if (reg >= 7)
167 size >>= 6;
168
169 size &= 0x7fff;
170 for (arr_size = 0; size; arr_size++, size >>= 1) ;
171
172 if (reg < 7) {
173 switch (type) {
174 case MTRR_TYPE_UNCACHABLE:
175 arr_type = 1;
176 break;
177 case MTRR_TYPE_WRCOMB:
178 arr_type = 9;
179 break;
180 case MTRR_TYPE_WRTHROUGH:
181 arr_type = 24;
182 break;
183 default:
184 arr_type = 8;
185 break;
186 }
187 } else {
188 switch (type) {
189 case MTRR_TYPE_UNCACHABLE:
190 arr_type = 0;
191 break;
192 case MTRR_TYPE_WRCOMB:
193 arr_type = 8;
194 break;
195 case MTRR_TYPE_WRTHROUGH:
196 arr_type = 25;
197 break;
198 default:
199 arr_type = 9;
200 break;
201 }
202 }
203
204 prepare_set();
205
206 base <<= PAGE_SHIFT;
207 setCx86(arr, ((unsigned char *) &base)[3]);
208 setCx86(arr + 1, ((unsigned char *) &base)[2]);
209 setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size);
210 setCx86(CX86_RCR_BASE + reg, arr_type);
211
212 post_set();
213}
214
215typedef struct {
216 unsigned long base;
217 unsigned int size;
218 mtrr_type type;
219} arr_state_t;
220
221arr_state_t arr_state[8] __initdata = {
222 {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
223 {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
224};
225
226unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
227
228static void cyrix_set_all(void)
229{
230 int i;
231
232 prepare_set();
233
234
235 for (i = 0; i < 4; i++)
236 setCx86(CX86_CCR0 + i, ccr_state[i]);
237 for (; i < 7; i++)
238 setCx86(CX86_CCR4 + i, ccr_state[i]);
239 for (i = 0; i < 8; i++)
240 cyrix_set_arr(i, arr_state[i].base,
241 arr_state[i].size, arr_state[i].type);
242
243 post_set();
244}
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260static void __init
261cyrix_arr_init(void)
262{
263 struct set_mtrr_context ctxt;
264 unsigned char ccr[7];
265 int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
266#ifdef CONFIG_SMP
267 int i;
268#endif
269
270
271 set_mtrr_prepare_save(&ctxt);
272 set_mtrr_cache_disable(&ctxt);
273
274
275 ccr[0] = getCx86(CX86_CCR0);
276 ccr[1] = getCx86(CX86_CCR1);
277 ccr[2] = getCx86(CX86_CCR2);
278 ccr[3] = ctxt.ccr3;
279 ccr[4] = getCx86(CX86_CCR4);
280 ccr[5] = getCx86(CX86_CCR5);
281 ccr[6] = getCx86(CX86_CCR6);
282
283 if (ccr[3] & 1) {
284 ccrc[3] = 1;
285 arr3_protected = 1;
286 } else {
287
288
289
290 if (ccr[1] & 0x80) {
291 ccr[1] &= 0x7f;
292 ccrc[1] |= 0x80;
293 }
294 if (ccr[1] & 0x04) {
295 ccr[1] &= 0xfb;
296 ccrc[1] |= 0x04;
297 }
298 if (ccr[1] & 0x02) {
299 ccr[1] &= 0xfd;
300 ccrc[1] |= 0x02;
301 }
302 arr3_protected = 0;
303 if (ccr[6] & 0x02) {
304 ccr[6] &= 0xfd;
305 ccrc[6] = 1;
306 setCx86(CX86_CCR6, ccr[6]);
307 }
308
309
310 }
311
312 if (ccrc[1])
313 setCx86(CX86_CCR1, ccr[1]);
314
315
316 if (!(ccr[5] & 0x20)) {
317 ccr[5] |= 0x20;
318 ccrc[5] = 1;
319 setCx86(CX86_CCR5, ccr[5]);
320 }
321#ifdef CONFIG_SMP
322 for (i = 0; i < 7; i++)
323 ccr_state[i] = ccr[i];
324 for (i = 0; i < 8; i++)
325 cyrix_get_arr(i,
326 &arr_state[i].base, &arr_state[i].size,
327 &arr_state[i].type);
328#endif
329
330 set_mtrr_done(&ctxt);
331
332 if (ccrc[5])
333 printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n");
334 if (ccrc[3])
335 printk(KERN_INFO "mtrr: ARR3 cannot be changed\n");
336
337
338
339
340
341 if (ccrc[6])
342 printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
343}
344
345static struct mtrr_ops cyrix_mtrr_ops = {
346 .vendor = X86_VENDOR_CYRIX,
347 .init = cyrix_arr_init,
348 .set_all = cyrix_set_all,
349 .set = cyrix_set_arr,
350 .get = cyrix_get_arr,
351 .get_free_region = cyrix_get_free_region,
352 .validate_add_page = generic_validate_add_page,
353 .have_wrcomb = positive_have_wrcomb,
354};
355
356int __init cyrix_init_mtrr(void)
357{
358 set_mtrr_ops(&cyrix_mtrr_ops);
359 return 0;
360}
361
362
363