Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / i386 / kernel / cpu / mtrr / main-xen.c
1 #include <linux/init.h>
2 #include <linux/proc_fs.h>
3 #include <linux/ctype.h>
4 #include <linux/module.h>
5 #include <linux/seq_file.h>
6 #include <linux/mutex.h>
7 #include <asm/uaccess.h>
8
9 #include <asm/mtrr.h>
10 #include "mtrr.h"
11
12 static DEFINE_MUTEX(mtrr_mutex);
13
14 void generic_get_mtrr(unsigned int reg, unsigned long *base,
15                       unsigned int *size, mtrr_type * type)
16 {
17         dom0_op_t op;
18
19         op.cmd = DOM0_READ_MEMTYPE;
20         op.u.read_memtype.reg = reg;
21         (void)HYPERVISOR_dom0_op(&op);
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 struct mtrr_ops generic_mtrr_ops = {
29         .use_intel_if      = 1,
30         .get               = generic_get_mtrr,
31 };
32
33 struct mtrr_ops *mtrr_if = &generic_mtrr_ops;
34 unsigned int num_var_ranges;
35 unsigned int *usage_table;
36
37 static void __init set_num_var_ranges(void)
38 {
39         dom0_op_t op;
40
41         for (num_var_ranges = 0; ; num_var_ranges++) {
42                 op.cmd = DOM0_READ_MEMTYPE;
43                 op.u.read_memtype.reg = num_var_ranges;
44                 if (HYPERVISOR_dom0_op(&op) != 0)
45                         break;
46         }
47 }
48
49 static void __init init_table(void)
50 {
51         int i, max;
52
53         max = num_var_ranges;
54         if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
55             == NULL) {
56                 printk(KERN_ERR "mtrr: could not allocate\n");
57                 return;
58         }
59         for (i = 0; i < max; i++)
60                 usage_table[i] = 0;
61 }
62
63 int mtrr_add_page(unsigned long base, unsigned long size, 
64                   unsigned int type, char increment)
65 {
66         int error;
67         dom0_op_t op;
68
69         mutex_lock(&mtrr_mutex);
70
71         op.cmd = DOM0_ADD_MEMTYPE;
72         op.u.add_memtype.mfn     = base;
73         op.u.add_memtype.nr_mfns = size;
74         op.u.add_memtype.type    = type;
75         error = HYPERVISOR_dom0_op(&op);
76         if (error) {
77                 mutex_unlock(&mtrr_mutex);
78                 BUG_ON(error > 0);
79                 return error;
80         }
81
82         if (increment)
83                 ++usage_table[op.u.add_memtype.reg];
84
85         mutex_unlock(&mtrr_mutex);
86
87         return op.u.add_memtype.reg;
88 }
89
90 static int mtrr_check(unsigned long base, unsigned long size)
91 {
92         if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
93                 printk(KERN_WARNING
94                         "mtrr: size and base must be multiples of 4 kiB\n");
95                 printk(KERN_DEBUG
96                         "mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
97                 dump_stack();
98                 return -1;
99         }
100         return 0;
101 }
102
103 int
104 mtrr_add(unsigned long base, unsigned long size, unsigned int type,
105          char increment)
106 {
107         if (mtrr_check(base, size))
108                 return -EINVAL;
109         return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
110                              increment);
111 }
112
113 int mtrr_del_page(int reg, unsigned long base, unsigned long size)
114 {
115         unsigned i;
116         mtrr_type ltype;
117         unsigned long lbase;
118         unsigned int lsize;
119         int error = -EINVAL;
120         dom0_op_t op;
121
122         mutex_lock(&mtrr_mutex);
123
124         if (reg < 0) {
125                 /*  Search for existing MTRR  */
126                 for (i = 0; i < num_var_ranges; ++i) {
127                         mtrr_if->get(i, &lbase, &lsize, &ltype);
128                         if (lbase == base && lsize == size) {
129                                 reg = i;
130                                 break;
131                         }
132                 }
133                 if (reg < 0) {
134                         printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
135                                size);
136                         goto out;
137                 }
138         }
139         if (usage_table[reg] < 1) {
140                 printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
141                 goto out;
142         }
143         if (--usage_table[reg] < 1) {
144                 op.cmd = DOM0_DEL_MEMTYPE;
145                 op.u.del_memtype.handle = 0;
146                 op.u.del_memtype.reg    = reg;
147                 error = HYPERVISOR_dom0_op(&op);
148                 if (error) {
149                         BUG_ON(error > 0);
150                         goto out;
151                 }
152         }
153         error = reg;
154  out:
155         mutex_unlock(&mtrr_mutex);
156         return error;
157 }
158
159 int
160 mtrr_del(int reg, unsigned long base, unsigned long size)
161 {
162         if (mtrr_check(base, size))
163                 return -EINVAL;
164         return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
165 }
166
167 EXPORT_SYMBOL(mtrr_add);
168 EXPORT_SYMBOL(mtrr_del);
169
170 void __init mtrr_bp_init(void)
171 {
172 }
173
174 void mtrr_ap_init(void)
175 {
176 }
177
178 static int __init mtrr_init(void)
179 {
180         struct cpuinfo_x86 *c = &boot_cpu_data;
181
182         if (!is_initial_xendomain())
183                 return -ENODEV;
184
185         if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
186             (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
187             (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
188             (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
189                 return -ENODEV;
190
191         set_num_var_ranges();
192         init_table();
193
194         return 0;
195 }
196
197 subsys_initcall(mtrr_init);