Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
[sfrench/cifs-2.6.git] / arch / x86 / lib / msr.c
1 #include <linux/module.h>
2 #include <linux/preempt.h>
3 #include <linux/smp.h>
4 #include <asm/msr.h>
5
6 struct msr_info {
7         u32 msr_no;
8         struct msr reg;
9         struct msr *msrs;
10         int err;
11 };
12
13 static void __rdmsr_on_cpu(void *info)
14 {
15         struct msr_info *rv = info;
16         struct msr *reg;
17         int this_cpu = raw_smp_processor_id();
18
19         if (rv->msrs)
20                 reg = per_cpu_ptr(rv->msrs, this_cpu);
21         else
22                 reg = &rv->reg;
23
24         rdmsr(rv->msr_no, reg->l, reg->h);
25 }
26
27 static void __wrmsr_on_cpu(void *info)
28 {
29         struct msr_info *rv = info;
30         struct msr *reg;
31         int this_cpu = raw_smp_processor_id();
32
33         if (rv->msrs)
34                 reg = per_cpu_ptr(rv->msrs, this_cpu);
35         else
36                 reg = &rv->reg;
37
38         wrmsr(rv->msr_no, reg->l, reg->h);
39 }
40
41 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
42 {
43         int err;
44         struct msr_info rv;
45
46         memset(&rv, 0, sizeof(rv));
47
48         rv.msr_no = msr_no;
49         err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
50         *l = rv.reg.l;
51         *h = rv.reg.h;
52
53         return err;
54 }
55 EXPORT_SYMBOL(rdmsr_on_cpu);
56
57 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
58 {
59         int err;
60         struct msr_info rv;
61
62         memset(&rv, 0, sizeof(rv));
63
64         rv.msr_no = msr_no;
65         rv.reg.l = l;
66         rv.reg.h = h;
67         err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
68
69         return err;
70 }
71 EXPORT_SYMBOL(wrmsr_on_cpu);
72
73 static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
74                             struct msr *msrs,
75                             void (*msr_func) (void *info))
76 {
77         struct msr_info rv;
78         int this_cpu;
79
80         memset(&rv, 0, sizeof(rv));
81
82         rv.msrs   = msrs;
83         rv.msr_no = msr_no;
84
85         this_cpu = get_cpu();
86
87         if (cpumask_test_cpu(this_cpu, mask))
88                 msr_func(&rv);
89
90         smp_call_function_many(mask, msr_func, &rv, 1);
91         put_cpu();
92 }
93
94 /* rdmsr on a bunch of CPUs
95  *
96  * @mask:       which CPUs
97  * @msr_no:     which MSR
98  * @msrs:       array of MSR values
99  *
100  */
101 void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
102 {
103         __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
104 }
105 EXPORT_SYMBOL(rdmsr_on_cpus);
106
107 /*
108  * wrmsr on a bunch of CPUs
109  *
110  * @mask:       which CPUs
111  * @msr_no:     which MSR
112  * @msrs:       array of MSR values
113  *
114  */
115 void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
116 {
117         __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
118 }
119 EXPORT_SYMBOL(wrmsr_on_cpus);
120
121 struct msr *msrs_alloc(void)
122 {
123         struct msr *msrs = NULL;
124
125         msrs = alloc_percpu(struct msr);
126         if (!msrs) {
127                 pr_warning("%s: error allocating msrs\n", __func__);
128                 return NULL;
129         }
130
131         return msrs;
132 }
133 EXPORT_SYMBOL(msrs_alloc);
134
135 void msrs_free(struct msr *msrs)
136 {
137         free_percpu(msrs);
138 }
139 EXPORT_SYMBOL(msrs_free);
140
141 /* These "safe" variants are slower and should be used when the target MSR
142    may not actually exist. */
143 static void __rdmsr_safe_on_cpu(void *info)
144 {
145         struct msr_info *rv = info;
146
147         rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h);
148 }
149
150 static void __wrmsr_safe_on_cpu(void *info)
151 {
152         struct msr_info *rv = info;
153
154         rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h);
155 }
156
157 int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
158 {
159         int err;
160         struct msr_info rv;
161
162         memset(&rv, 0, sizeof(rv));
163
164         rv.msr_no = msr_no;
165         err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
166         *l = rv.reg.l;
167         *h = rv.reg.h;
168
169         return err ? err : rv.err;
170 }
171 EXPORT_SYMBOL(rdmsr_safe_on_cpu);
172
173 int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
174 {
175         int err;
176         struct msr_info rv;
177
178         memset(&rv, 0, sizeof(rv));
179
180         rv.msr_no = msr_no;
181         rv.reg.l = l;
182         rv.reg.h = h;
183         err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
184
185         return err ? err : rv.err;
186 }
187 EXPORT_SYMBOL(wrmsr_safe_on_cpu);
188
189 /*
190  * These variants are significantly slower, but allows control over
191  * the entire 32-bit GPR set.
192  */
193 struct msr_regs_info {
194         u32 *regs;
195         int err;
196 };
197
198 static void __rdmsr_safe_regs_on_cpu(void *info)
199 {
200         struct msr_regs_info *rv = info;
201
202         rv->err = rdmsr_safe_regs(rv->regs);
203 }
204
205 static void __wrmsr_safe_regs_on_cpu(void *info)
206 {
207         struct msr_regs_info *rv = info;
208
209         rv->err = wrmsr_safe_regs(rv->regs);
210 }
211
212 int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
213 {
214         int err;
215         struct msr_regs_info rv;
216
217         rv.regs   = regs;
218         rv.err    = -EIO;
219         err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1);
220
221         return err ? err : rv.err;
222 }
223 EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu);
224
225 int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
226 {
227         int err;
228         struct msr_regs_info rv;
229
230         rv.regs = regs;
231         rv.err  = -EIO;
232         err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1);
233
234         return err ? err : rv.err;
235 }
236 EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu);