blob: 33a1e3ca22d81e71240c1509f42c7d4b69d2c9e2 [file] [log] [blame]
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -08001#include <linux/module.h>
2#include <linux/preempt.h>
3#include <linux/smp.h>
4#include <asm/msr.h>
5
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -08006struct msr_info {
7 u32 msr_no;
Borislav Petkov6bc10962009-05-22 12:12:01 +02008 struct msr reg;
Borislav Petkovb034c192009-05-22 13:52:19 +02009 struct msr *msrs;
10 int off;
Rudolf Marek4e9baad2007-05-08 17:22:01 +020011 int err;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080012};
13
14static void __rdmsr_on_cpu(void *info)
15{
16 struct msr_info *rv = info;
Borislav Petkovb034c192009-05-22 13:52:19 +020017 struct msr *reg;
18 int this_cpu = raw_smp_processor_id();
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080019
Borislav Petkovb034c192009-05-22 13:52:19 +020020 if (rv->msrs)
21 reg = &rv->msrs[this_cpu - rv->off];
22 else
23 reg = &rv->reg;
24
25 rdmsr(rv->msr_no, reg->l, reg->h);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080026}
27
H. Peter Anvinbdd31462008-08-25 17:44:03 -070028static void __wrmsr_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080029{
Rudolf Marek4e9baad2007-05-08 17:22:01 +020030 struct msr_info *rv = info;
Borislav Petkovb034c192009-05-22 13:52:19 +020031 struct msr *reg;
32 int this_cpu = raw_smp_processor_id();
Rudolf Marek4e9baad2007-05-08 17:22:01 +020033
Borislav Petkovb034c192009-05-22 13:52:19 +020034 if (rv->msrs)
35 reg = &rv->msrs[this_cpu - rv->off];
36 else
37 reg = &rv->reg;
38
39 wrmsr(rv->msr_no, reg->l, reg->h);
Rudolf Marek4e9baad2007-05-08 17:22:01 +020040}
41
H. Peter Anvinbdd31462008-08-25 17:44:03 -070042int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
Rudolf Marek4e9baad2007-05-08 17:22:01 +020043{
H. Peter Anvinbdd31462008-08-25 17:44:03 -070044 int err;
Avi Kivity5f1f9352007-10-17 18:04:38 +020045 struct msr_info rv;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080046
Borislav Petkovb034c192009-05-22 13:52:19 +020047 memset(&rv, 0, sizeof(rv));
48
Avi Kivity5f1f9352007-10-17 18:04:38 +020049 rv.msr_no = msr_no;
H. Peter Anvinbdd31462008-08-25 17:44:03 -070050 err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
Borislav Petkov6bc10962009-05-22 12:12:01 +020051 *l = rv.reg.l;
52 *h = rv.reg.h;
Avi Kivity5f1f9352007-10-17 18:04:38 +020053
Rudolf Marek4e9baad2007-05-08 17:22:01 +020054 return err;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080055}
Borislav Petkovb034c192009-05-22 13:52:19 +020056EXPORT_SYMBOL(rdmsr_on_cpu);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080057
H. Peter Anvinbdd31462008-08-25 17:44:03 -070058int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
59{
60 int err;
61 struct msr_info rv;
62
Borislav Petkovb034c192009-05-22 13:52:19 +020063 memset(&rv, 0, sizeof(rv));
64
H. Peter Anvinbdd31462008-08-25 17:44:03 -070065 rv.msr_no = msr_no;
Borislav Petkov6bc10962009-05-22 12:12:01 +020066 rv.reg.l = l;
67 rv.reg.h = h;
H. Peter Anvinbdd31462008-08-25 17:44:03 -070068 err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
69
70 return err;
71}
Borislav Petkovb034c192009-05-22 13:52:19 +020072EXPORT_SYMBOL(wrmsr_on_cpu);
73
74/* rdmsr on a bunch of CPUs
75 *
76 * @mask: which CPUs
77 * @msr_no: which MSR
78 * @msrs: array of MSR values
79 *
80 */
81void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
82{
83 struct msr_info rv;
84 int this_cpu;
85
86 memset(&rv, 0, sizeof(rv));
87
88 rv.off = cpumask_first(mask);
89 rv.msrs = msrs;
90 rv.msr_no = msr_no;
91
Borislav Petkovbab9a3d2009-07-30 11:10:01 +020092 this_cpu = get_cpu();
93
94 if (cpumask_test_cpu(this_cpu, mask))
95 __rdmsr_on_cpu(&rv);
Borislav Petkovb034c192009-05-22 13:52:19 +020096
97 smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1);
Borislav Petkovbab9a3d2009-07-30 11:10:01 +020098 put_cpu();
Borislav Petkovb034c192009-05-22 13:52:19 +020099}
100EXPORT_SYMBOL(rdmsr_on_cpus);
101
102/*
103 * wrmsr on a bunch of CPUs
104 *
105 * @mask: which CPUs
106 * @msr_no: which MSR
107 * @msrs: array of MSR values
108 *
109 */
110void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
111{
112 struct msr_info rv;
113 int this_cpu;
114
115 memset(&rv, 0, sizeof(rv));
116
117 rv.off = cpumask_first(mask);
118 rv.msrs = msrs;
119 rv.msr_no = msr_no;
120
Borislav Petkovbab9a3d2009-07-30 11:10:01 +0200121 this_cpu = get_cpu();
122
123 if (cpumask_test_cpu(this_cpu, mask))
124 __wrmsr_on_cpu(&rv);
Borislav Petkovb034c192009-05-22 13:52:19 +0200125
126 smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1);
Borislav Petkovbab9a3d2009-07-30 11:10:01 +0200127 put_cpu();
Borislav Petkovb034c192009-05-22 13:52:19 +0200128}
129EXPORT_SYMBOL(wrmsr_on_cpus);
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700130
131/* These "safe" variants are slower and should be used when the target MSR
132 may not actually exist. */
133static void __rdmsr_safe_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800134{
135 struct msr_info *rv = info;
136
Borislav Petkov6bc10962009-05-22 12:12:01 +0200137 rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800138}
139
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200140static void __wrmsr_safe_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800141{
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200142 struct msr_info *rv = info;
143
Borislav Petkov6bc10962009-05-22 12:12:01 +0200144 rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h);
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200145}
146
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700147int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200148{
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700149 int err;
150 struct msr_info rv;
151
Borislav Petkovb034c192009-05-22 13:52:19 +0200152 memset(&rv, 0, sizeof(rv));
153
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700154 rv.msr_no = msr_no;
155 err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
Borislav Petkov6bc10962009-05-22 12:12:01 +0200156 *l = rv.reg.l;
157 *h = rv.reg.h;
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700158
159 return err ? err : rv.err;
160}
Borislav Petkovb034c192009-05-22 13:52:19 +0200161EXPORT_SYMBOL(rdmsr_safe_on_cpu);
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700162
163int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
164{
165 int err;
Avi Kivity5f1f9352007-10-17 18:04:38 +0200166 struct msr_info rv;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800167
Borislav Petkovb034c192009-05-22 13:52:19 +0200168 memset(&rv, 0, sizeof(rv));
169
Avi Kivity5f1f9352007-10-17 18:04:38 +0200170 rv.msr_no = msr_no;
Borislav Petkov6bc10962009-05-22 12:12:01 +0200171 rv.reg.l = l;
172 rv.reg.h = h;
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700173 err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
Avi Kivity5f1f9352007-10-17 18:04:38 +0200174
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700175 return err ? err : rv.err;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800176}
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200177EXPORT_SYMBOL(wrmsr_safe_on_cpu);
H. Peter Anvin8b956bf2009-08-31 14:13:48 -0700178
179/*
180 * These variants are significantly slower, but allows control over
181 * the entire 32-bit GPR set.
182 */
183struct msr_regs_info {
184 u32 *regs;
185 int err;
186};
187
188static void __rdmsr_safe_regs_on_cpu(void *info)
189{
190 struct msr_regs_info *rv = info;
191
192 rv->err = rdmsr_safe_regs(rv->regs);
193}
194
195static void __wrmsr_safe_regs_on_cpu(void *info)
196{
197 struct msr_regs_info *rv = info;
198
199 rv->err = wrmsr_safe_regs(rv->regs);
200}
201
202int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
203{
204 int err;
205 struct msr_regs_info rv;
206
207 rv.regs = regs;
208 rv.err = -EIO;
209 err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1);
210
211 return err ? err : rv.err;
212}
213EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu);
214
215int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
216{
217 int err;
218 struct msr_regs_info rv;
219
220 rv.regs = regs;
221 rv.err = -EIO;
222 err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1);
223
224 return err ? err : rv.err;
225}
226EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu);