Added patch headers.
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / cpu / mtrr / main-xen.c
1 #define DEBUG
2
3 #include <linux/uaccess.h>
4 #include <linux/module.h>
5 #include <linux/mutex.h>
6 #include <linux/init.h>
7
8 #include <asm/mtrr.h>
9 #include "mtrr.h"
10
11 static DEFINE_MUTEX(mtrr_mutex);
12
13 void generic_get_mtrr(unsigned int reg, unsigned long *base,
14                       unsigned long *size, mtrr_type * type)
15 {
16         struct xen_platform_op op;
17
18         op.cmd = XENPF_read_memtype;
19         op.u.read_memtype.reg = reg;
20         if (unlikely(HYPERVISOR_platform_op(&op)))
21                 memset(&op.u.read_memtype, 0, sizeof(op.u.read_memtype));
22
23         *size = op.u.read_memtype.nr_mfns;
24         *base = op.u.read_memtype.mfn;
25         *type = op.u.read_memtype.type;
26 }
27
28 const struct mtrr_ops generic_mtrr_ops = {
29         .use_intel_if      = 1,
30         .get               = generic_get_mtrr,
31 };
32
33 const struct mtrr_ops *mtrr_if = &generic_mtrr_ops;
34 unsigned int num_var_ranges;
35 unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
36
37 static u64 tom2;
38
39 static void __init set_num_var_ranges(void)
40 {
41         struct xen_platform_op op;
42
43         for (num_var_ranges = 0; ; num_var_ranges++) {
44                 op.cmd = XENPF_read_memtype;
45                 op.u.read_memtype.reg = num_var_ranges;
46                 if (HYPERVISOR_platform_op(&op) != 0)
47                         break;
48         }
49 }
50
51 static void __init init_table(void)
52 {
53         int i, max;
54
55         max = num_var_ranges;
56         for (i = 0; i < max; i++)
57                 mtrr_usage_table[i] = 0;
58 }
59
60 int mtrr_add_page(unsigned long base, unsigned long size,
61                   unsigned int type, bool increment)
62 {
63         int error;
64         struct xen_platform_op op;
65
66         mutex_lock(&mtrr_mutex);
67
68         op.cmd = XENPF_add_memtype;
69         op.u.add_memtype.mfn     = base;
70         op.u.add_memtype.nr_mfns = size;
71         op.u.add_memtype.type    = type;
72         error = HYPERVISOR_platform_op(&op);
73         if (error) {
74                 mutex_unlock(&mtrr_mutex);
75                 BUG_ON(error > 0);
76                 return error;
77         }
78
79         if (increment)
80                 ++mtrr_usage_table[op.u.add_memtype.reg];
81
82         mutex_unlock(&mtrr_mutex);
83
84         return op.u.add_memtype.reg;
85 }
86
87 static int mtrr_check(unsigned long base, unsigned long size)
88 {
89         if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
90                 pr_warning("mtrr: size and base must be multiples of 4 kiB\n");
91                 pr_debug("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
92                 dump_stack();
93                 return -1;
94         }
95         return 0;
96 }
97
98 int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
99              bool increment)
100 {
101         if (mtrr_check(base, size))
102                 return -EINVAL;
103         return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
104                              increment);
105 }
106 EXPORT_SYMBOL(mtrr_add);
107
108 int mtrr_del_page(int reg, unsigned long base, unsigned long size)
109 {
110         unsigned i;
111         mtrr_type ltype;
112         unsigned long lbase, lsize;
113         int error = -EINVAL;
114         struct xen_platform_op op;
115
116         mutex_lock(&mtrr_mutex);
117
118         if (reg < 0) {
119                 /*  Search for existing MTRR  */
120                 for (i = 0; i < num_var_ranges; ++i) {
121                         mtrr_if->get(i, &lbase, &lsize, &ltype);
122                         if (lbase == base && lsize == size) {
123                                 reg = i;
124                                 break;
125                         }
126                 }
127                 if (reg < 0) {
128                         pr_debug("mtrr: no MTRR for %lx000,%lx000 found\n",
129                                  base, size);
130                         goto out;
131                 }
132         }
133         if (mtrr_usage_table[reg] < 1) {
134                 pr_warning("mtrr: reg: %d has count=0\n", reg);
135                 goto out;
136         }
137         if (--mtrr_usage_table[reg] < 1) {
138                 op.cmd = XENPF_del_memtype;
139                 op.u.del_memtype.handle = 0;
140                 op.u.del_memtype.reg    = reg;
141                 error = HYPERVISOR_platform_op(&op);
142                 if (error) {
143                         BUG_ON(error > 0);
144                         goto out;
145                 }
146         }
147         error = reg;
148  out:
149         mutex_unlock(&mtrr_mutex);
150         return error;
151 }
152
153 int mtrr_del(int reg, unsigned long base, unsigned long size)
154 {
155         if (mtrr_check(base, size))
156                 return -EINVAL;
157         return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
158 }
159 EXPORT_SYMBOL(mtrr_del);
160
161 /*
162  * Returns the effective MTRR type for the region
163  * Error returns:
164  * - 0xFE - when the range is "not entirely covered" by _any_ var range MTRR
165  * - 0xFF - when MTRR is not enabled
166  */
167 u8 mtrr_type_lookup(u64 start, u64 end)
168 {
169         int i, error;
170         u64 start_mfn, end_mfn, base_mfn, top_mfn;
171         u8 prev_match, curr_match;
172         struct xen_platform_op op;
173
174         if (!is_initial_xendomain())
175                 return MTRR_TYPE_WRBACK;
176
177         if (!num_var_ranges)
178                 return 0xFF;
179
180         start_mfn = start >> PAGE_SHIFT;
181         /* Make end inclusive end, instead of exclusive */
182         end_mfn = --end >> PAGE_SHIFT;
183
184         /* Look in fixed ranges. Just return the type as per start */
185         if (start_mfn < 0x100) {
186 #if 0//todo
187                 op.cmd = XENPF_read_memtype;
188                 op.u.read_memtype.reg = ???;
189                 error = HYPERVISOR_platform_op(&op);
190                 if (!error)
191                         return op.u.read_memtype.type;
192 #endif
193                 return MTRR_TYPE_UNCACHABLE;
194         }
195
196         /*
197          * Look in variable ranges
198          * Look of multiple ranges matching this address and pick type
199          * as per MTRR precedence
200          */
201         prev_match = 0xFF;
202         for (i = 0; i < num_var_ranges; ++i) {
203                 op.cmd = XENPF_read_memtype;
204                 op.u.read_memtype.reg = i;
205                 error = HYPERVISOR_platform_op(&op);
206
207                 if (error || !op.u.read_memtype.nr_mfns)
208                         continue;
209
210                 base_mfn = op.u.read_memtype.mfn;
211                 top_mfn = base_mfn + op.u.read_memtype.nr_mfns - 1;
212
213                 if (base_mfn > end_mfn || start_mfn > top_mfn) {
214                         continue;
215                 }
216
217                 if (base_mfn > start_mfn || end_mfn > top_mfn) {
218                         return 0xFE;
219                 }
220
221                 curr_match = op.u.read_memtype.type;
222                 if (prev_match == 0xFF) {
223                         prev_match = curr_match;
224                         continue;
225                 }
226
227                 if (prev_match == MTRR_TYPE_UNCACHABLE ||
228                     curr_match == MTRR_TYPE_UNCACHABLE) {
229                         return MTRR_TYPE_UNCACHABLE;
230                 }
231
232                 if ((prev_match == MTRR_TYPE_WRBACK &&
233                      curr_match == MTRR_TYPE_WRTHROUGH) ||
234                     (prev_match == MTRR_TYPE_WRTHROUGH &&
235                      curr_match == MTRR_TYPE_WRBACK)) {
236                         prev_match = MTRR_TYPE_WRTHROUGH;
237                         curr_match = MTRR_TYPE_WRTHROUGH;
238                 }
239
240                 if (prev_match != curr_match) {
241                         return MTRR_TYPE_UNCACHABLE;
242                 }
243         }
244
245         if (tom2) {
246                 if (start >= (1ULL<<32) && (end < tom2))
247                         return MTRR_TYPE_WRBACK;
248         }
249
250         if (prev_match != 0xFF)
251                 return prev_match;
252
253 #if 0//todo
254         op.cmd = XENPF_read_def_memtype;
255         error = HYPERVISOR_platform_op(&op);
256         if (!error)
257                 return op.u.read_def_memtype.type;
258 #endif
259         return MTRR_TYPE_UNCACHABLE;
260 }
261
262 /*
263  * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
264  * for memory >4GB. Check for that here.
265  * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
266  * apply to are wrong, but so far we don't know of any such case in the wild.
267  */
268 #define Tom2Enabled (1U << 21)
269 #define Tom2ForceMemTypeWB (1U << 22)
270
271 int __init amd_special_default_mtrr(void)
272 {
273         u32 l, h;
274
275         if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
276                 return 0;
277         if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
278                 return 0;
279         /* In case some hypervisor doesn't pass SYSCFG through */
280         if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
281                 return 0;
282         /*
283          * Memory between 4GB and top of mem is forced WB by this magic bit.
284          * Reserved before K8RevF, but should be zero there.
285          */
286         if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
287                  (Tom2Enabled | Tom2ForceMemTypeWB))
288                 return 1;
289         return 0;
290 }
291
292 void __init mtrr_bp_init(void)
293 {
294         if (amd_special_default_mtrr()) {
295                 /* TOP_MEM2 */
296                 rdmsrl(MSR_K8_TOP_MEM2, tom2);
297                 tom2 &= 0xffffff8000000ULL;
298         }
299 }
300
301 void mtrr_ap_init(void)
302 {
303 }
304
305 static int __init mtrr_init(void)
306 {
307         struct cpuinfo_x86 *c = &boot_cpu_data;
308
309         if (!is_initial_xendomain())
310                 return -ENODEV;
311
312         if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
313             (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
314             (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
315             (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
316                 return -ENODEV;
317
318         set_num_var_ranges();
319         init_table();
320
321         return 0;
322 }
323
324 subsys_initcall(mtrr_init);