blob: 1440b9c0547e9bd668a7bedf683686c57f5d1db0 [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
92 preempt_disable();
93 /*
94 * FIXME: handle the CPU we're executing on separately for now until
95 * smp_call_function_many has been fixed to not skip it.
96 */
97 this_cpu = raw_smp_processor_id();
98 smp_call_function_single(this_cpu, __rdmsr_on_cpu, &rv, 1);
99
100 smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1);
101 preempt_enable();
102}
103EXPORT_SYMBOL(rdmsr_on_cpus);
104
105/*
106 * wrmsr on a bunch of CPUs
107 *
108 * @mask: which CPUs
109 * @msr_no: which MSR
110 * @msrs: array of MSR values
111 *
112 */
113void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
114{
115 struct msr_info rv;
116 int this_cpu;
117
118 memset(&rv, 0, sizeof(rv));
119
120 rv.off = cpumask_first(mask);
121 rv.msrs = msrs;
122 rv.msr_no = msr_no;
123
124 preempt_disable();
125 /*
126 * FIXME: handle the CPU we're executing on separately for now until
127 * smp_call_function_many has been fixed to not skip it.
128 */
129 this_cpu = raw_smp_processor_id();
130 smp_call_function_single(this_cpu, __wrmsr_on_cpu, &rv, 1);
131
132 smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1);
133 preempt_enable();
134}
135EXPORT_SYMBOL(wrmsr_on_cpus);
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700136
137/* These "safe" variants are slower and should be used when the target MSR
138 may not actually exist. */
139static void __rdmsr_safe_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800140{
141 struct msr_info *rv = info;
142
Borislav Petkov6bc10962009-05-22 12:12:01 +0200143 rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800144}
145
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200146static void __wrmsr_safe_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800147{
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200148 struct msr_info *rv = info;
149
Borislav Petkov6bc10962009-05-22 12:12:01 +0200150 rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h);
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200151}
152
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700153int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200154{
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700155 int err;
156 struct msr_info rv;
157
Borislav Petkovb034c192009-05-22 13:52:19 +0200158 memset(&rv, 0, sizeof(rv));
159
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700160 rv.msr_no = msr_no;
161 err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1);
Borislav Petkov6bc10962009-05-22 12:12:01 +0200162 *l = rv.reg.l;
163 *h = rv.reg.h;
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700164
165 return err ? err : rv.err;
166}
Borislav Petkovb034c192009-05-22 13:52:19 +0200167EXPORT_SYMBOL(rdmsr_safe_on_cpu);
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700168
169int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
170{
171 int err;
Avi Kivity5f1f9352007-10-17 18:04:38 +0200172 struct msr_info rv;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800173
Borislav Petkovb034c192009-05-22 13:52:19 +0200174 memset(&rv, 0, sizeof(rv));
175
Avi Kivity5f1f9352007-10-17 18:04:38 +0200176 rv.msr_no = msr_no;
Borislav Petkov6bc10962009-05-22 12:12:01 +0200177 rv.reg.l = l;
178 rv.reg.h = h;
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700179 err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
Avi Kivity5f1f9352007-10-17 18:04:38 +0200180
H. Peter Anvinbdd31462008-08-25 17:44:03 -0700181 return err ? err : rv.err;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -0800182}
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200183EXPORT_SYMBOL(wrmsr_safe_on_cpu);