fedora core 6 1.2949 + vserver 2.2.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 static void generic_get_mtrr(unsigned int reg, unsigned long *base,
15                              unsigned long *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 /*  This function returns the number of variable MTRRs  */
38 static void __init set_num_var_ranges(void)
39 {
40         dom0_op_t op;
41
42         for (num_var_ranges = 0; ; num_var_ranges++) {
43                 op.cmd = DOM0_READ_MEMTYPE;
44                 op.u.read_memtype.reg = num_var_ranges;
45                 if (HYPERVISOR_dom0_op(&op) != 0)
46                         break;
47         }
48 }
49
50 static void __init init_table(void)
51 {
52         int i, max;
53
54         max = num_var_ranges;
55         if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
56             == NULL) {
57                 printk(KERN_ERR "mtrr: could not allocate\n");
58                 return;
59         }
60         for (i = 0; i < max; i++)
61                 usage_table[i] = 0;
62 }
63
64 int mtrr_add_page(unsigned long base, unsigned long size, 
65                   unsigned int type, char increment)
66 {
67         int error;
68         dom0_op_t op;
69
70         mutex_lock(&mtrr_mutex);
71
72         op.cmd = DOM0_ADD_MEMTYPE;
73         op.u.add_memtype.mfn     = base;
74         op.u.add_memtype.nr_mfns = size;
75         op.u.add_memtype.type    = type;
76         error = HYPERVISOR_dom0_op(&op);
77         if (error) {
78                 mutex_unlock(&mtrr_mutex);
79                 BUG_ON(error > 0);
80                 return error;
81         }
82
83         if (increment)
84                 ++usage_table[op.u.add_memtype.reg];
85
86         mutex_unlock(&mtrr_mutex);
87
88         return op.u.add_memtype.reg;
89 }
90
91 static int mtrr_check(unsigned long base, unsigned long size)
92 {
93         if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
94                 printk(KERN_WARNING
95                         "mtrr: size and base must be multiples of 4 kiB\n");
96                 printk(KERN_DEBUG
97                         "mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
98                 dump_stack();
99                 return -1;
100         }
101         return 0;
102 }
103
104 int
105 mtrr_add(unsigned long base, unsigned long size, unsigned int type,
106          char increment)
107 {
108         if (mtrr_check(base, size))
109                 return -EINVAL;
110         return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
111                              increment);
112 }
113
114 int mtrr_del_page(int reg, unsigned long base, unsigned long size)
115 {
116         unsigned i;
117         mtrr_type ltype;
118         unsigned long lbase, 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);