ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / i386 / kernel / cpu / mtrr / centaur.c
1 #include <linux/init.h>
2 #include <linux/mm.h>
3 #include <asm/mtrr.h>
4 #include <asm/msr.h>
5 #include "mtrr.h"
6
7 static struct {
8         unsigned long high;
9         unsigned long low;
10 } centaur_mcr[8];
11
12 static u8 centaur_mcr_reserved;
13 static u8 centaur_mcr_type;     /* 0 for winchip, 1 for winchip2 */
14
15 /*
16  *      Report boot time MCR setups 
17  */
18
19 static int
20 centaur_get_free_region(unsigned long base, unsigned long size)
21 /*  [SUMMARY] Get a free MTRR.
22     <base> The starting (base) address of the region.
23     <size> The size (in bytes) of the region.
24     [RETURNS] The index of the region on success, else -1 on error.
25 */
26 {
27         int i, max;
28         mtrr_type ltype;
29         unsigned long lbase;
30         unsigned int lsize;
31
32         max = num_var_ranges;
33         for (i = 0; i < max; ++i) {
34                 if (centaur_mcr_reserved & (1 << i))
35                         continue;
36                 mtrr_if->get(i, &lbase, &lsize, &ltype);
37                 if (lsize == 0)
38                         return i;
39         }
40         return -ENOSPC;
41 }
42
43 void
44 mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
45 {
46         centaur_mcr[mcr].low = lo;
47         centaur_mcr[mcr].high = hi;
48 }
49
50 static void
51 centaur_get_mcr(unsigned int reg, unsigned long *base,
52                 unsigned int *size, mtrr_type * type)
53 {
54         *base = centaur_mcr[reg].high >> PAGE_SHIFT;
55         *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
56         *type = MTRR_TYPE_WRCOMB;       /*  If it is there, it is write-combining  */
57         if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2))
58                 *type = MTRR_TYPE_UNCACHABLE;
59         if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25)
60                 *type = MTRR_TYPE_WRBACK;
61         if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31)
62                 *type = MTRR_TYPE_WRBACK;
63
64 }
65
66 static void centaur_set_mcr(unsigned int reg, unsigned long base,
67                             unsigned long size, mtrr_type type)
68 {
69         unsigned long low, high;
70
71         if (size == 0) {
72                 /*  Disable  */
73                 high = low = 0;
74         } else {
75                 high = base << PAGE_SHIFT;
76                 if (centaur_mcr_type == 0)
77                         low = -size << PAGE_SHIFT | 0x1f;       /* only support write-combining... */
78                 else {
79                         if (type == MTRR_TYPE_UNCACHABLE)
80                                 low = -size << PAGE_SHIFT | 0x02;       /* NC */
81                         else
82                                 low = -size << PAGE_SHIFT | 0x09;       /* WWO,WC */
83                 }
84         }
85         centaur_mcr[reg].high = high;
86         centaur_mcr[reg].low = low;
87         wrmsr(MSR_IDT_MCR0 + reg, low, high);
88 }
89 /*
90  *      Initialise the later (saner) Winchip MCR variant. In this version
91  *      the BIOS can pass us the registers it has used (but not their values)
92  *      and the control register is read/write
93  */
94
95 static void __init
96 centaur_mcr1_init(void)
97 {
98         unsigned i;
99         u32 lo, hi;
100
101         /* Unfortunately, MCR's are read-only, so there is no way to
102          * find out what the bios might have done.
103          */
104
105         rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
106         if (((lo >> 17) & 7) == 1) {    /* Type 1 Winchip2 MCR */
107                 lo &= ~0x1C0;   /* clear key */
108                 lo |= 0x040;    /* set key to 1 */
109                 wrmsr(MSR_IDT_MCR_CTRL, lo, hi);        /* unlock MCR */
110         }
111
112         centaur_mcr_type = 1;
113
114         /*
115          *  Clear any unconfigured MCR's.
116          */
117
118         for (i = 0; i < 8; ++i) {
119                 if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) {
120                         if (!(lo & (1 << (9 + i))))
121                                 wrmsr(MSR_IDT_MCR0 + i, 0, 0);
122                         else
123                                 /*
124                                  *      If the BIOS set up an MCR we cannot see it
125                                  *      but we don't wish to obliterate it
126                                  */
127                                 centaur_mcr_reserved |= (1 << i);
128                 }
129         }
130         /*  
131          *  Throw the main write-combining switch... 
132          *  However if OOSTORE is enabled then people have already done far
133          *  cleverer things and we should behave. 
134          */
135
136         lo |= 15;               /* Write combine enables */
137         wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
138 }
139
140 /*
141  *      Initialise the original winchip with read only MCR registers
142  *      no used bitmask for the BIOS to pass on and write only control
143  */
144
145 static void __init
146 centaur_mcr0_init(void)
147 {
148         unsigned i;
149
150         /* Unfortunately, MCR's are read-only, so there is no way to
151          * find out what the bios might have done.
152          */
153
154         /* Clear any unconfigured MCR's.
155          * This way we are sure that the centaur_mcr array contains the actual
156          * values. The disadvantage is that any BIOS tweaks are thus undone.
157          *
158          */
159         for (i = 0; i < 8; ++i) {
160                 if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0)
161                         wrmsr(MSR_IDT_MCR0 + i, 0, 0);
162         }
163
164         wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */
165 }
166
167 /*
168  *      Initialise Winchip series MCR registers
169  */
170
171 static void __init
172 centaur_mcr_init(void)
173 {
174         struct set_mtrr_context ctxt;
175
176         set_mtrr_prepare_save(&ctxt);
177         set_mtrr_cache_disable(&ctxt);
178
179         if (boot_cpu_data.x86_model == 4)
180                 centaur_mcr0_init();
181         else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9)
182                 centaur_mcr1_init();
183
184         set_mtrr_done(&ctxt);
185 }
186
187 static int centaur_validate_add_page(unsigned long base, 
188                                      unsigned long size, unsigned int type)
189 {
190         /*
191          *  FIXME: Winchip2 supports uncached
192          */
193         if (type != MTRR_TYPE_WRCOMB && 
194             (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) {
195                 printk(KERN_WARNING
196                        "mtrr: only write-combining%s supported\n",
197                        centaur_mcr_type ? " and uncacheable are"
198                        : " is");
199                 return -EINVAL;
200         }
201         return 0;
202 }
203
204 static struct mtrr_ops centaur_mtrr_ops = {
205         .vendor            = X86_VENDOR_CENTAUR,
206         .init              = centaur_mcr_init,
207         .set               = centaur_set_mcr,
208         .get               = centaur_get_mcr,
209         .get_free_region   = centaur_get_free_region,
210         .validate_add_page = centaur_validate_add_page,
211         .have_wrcomb       = positive_have_wrcomb,
212 };
213
214 int __init centaur_init_mtrr(void)
215 {
216         set_mtrr_ops(&centaur_mtrr_ops);
217         return 0;
218 }
219
220 //arch_initcall(centaur_init_mtrr);