diff options
author | Borislav Petkov <petkovbb@googlemail.com> | 2009-12-16 18:16:25 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-12-16 18:36:32 -0500 |
commit | 6ede31e03084ee084bcee073ef3d1136f68d0906 (patch) | |
tree | b10344809c72de850c11701cdbc0194d042fb79a /arch/x86/lib | |
parent | 9d260ebc09a0ad6b5c73e17676df42c7bc75ff64 (diff) |
x86, msr: msrs_alloc/free for CONFIG_SMP=n
Randy Dunlap reported the following build error:
"When CONFIG_SMP=n, CONFIG_X86_MSR=m:
ERROR: "msrs_free" [drivers/edac/amd64_edac_mod.ko] undefined!
ERROR: "msrs_alloc" [drivers/edac/amd64_edac_mod.ko] undefined!"
This is due to the fact that <arch/x86/lib/msr.c> is conditioned on
CONFIG_SMP and in the UP case we have only the stubs in the header.
Fork off SMP functionality into a new file (msr-smp.c) and build
msrs_{alloc,free} unconditionally.
Reported-by: Randy Dunlap <randy.dunlap@oracle.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Borislav Petkov <petkovbb@gmail.com>
LKML-Reference: <20091216231625.GD27228@liondog.tnic>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/lib')
-rw-r--r-- | arch/x86/lib/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/lib/msr-smp.c | 204 | ||||
-rw-r--r-- | arch/x86/lib/msr.c | 213 |
3 files changed, 206 insertions, 215 deletions
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index a2d6472895fb..706be8bf967b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile | |||
@@ -14,7 +14,7 @@ $(obj)/inat.o: $(obj)/inat-tables.c | |||
14 | 14 | ||
15 | clean-files := inat-tables.c | 15 | clean-files := inat-tables.c |
16 | 16 | ||
17 | obj-$(CONFIG_SMP) := msr.o | 17 | obj-$(CONFIG_SMP) += msr-smp.o |
18 | 18 | ||
19 | lib-y := delay.o | 19 | lib-y := delay.o |
20 | lib-y += thunk_$(BITS).o | 20 | lib-y += thunk_$(BITS).o |
@@ -22,7 +22,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o | |||
22 | lib-y += memcpy_$(BITS).o | 22 | lib-y += memcpy_$(BITS).o |
23 | lib-y += insn.o inat.o | 23 | lib-y += insn.o inat.o |
24 | 24 | ||
25 | obj-y += msr-reg.o msr-reg-export.o | 25 | obj-y += msr.o msr-reg.o msr-reg-export.o |
26 | 26 | ||
27 | ifeq ($(CONFIG_X86_32),y) | 27 | ifeq ($(CONFIG_X86_32),y) |
28 | obj-y += atomic64_32.o | 28 | obj-y += atomic64_32.o |
diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c new file mode 100644 index 000000000000..a6b1b86d2253 --- /dev/null +++ b/arch/x86/lib/msr-smp.c | |||
@@ -0,0 +1,204 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/preempt.h> | ||
3 | #include <linux/smp.h> | ||
4 | #include <asm/msr.h> | ||
5 | |||
6 | static void __rdmsr_on_cpu(void *info) | ||
7 | { | ||
8 | struct msr_info *rv = info; | ||
9 | struct msr *reg; | ||
10 | int this_cpu = raw_smp_processor_id(); | ||
11 | |||
12 | if (rv->msrs) | ||
13 | reg = per_cpu_ptr(rv->msrs, this_cpu); | ||
14 | else | ||
15 | reg = &rv->reg; | ||
16 | |||
17 | rdmsr(rv->msr_no, reg->l, reg->h); | ||
18 | } | ||
19 | |||
20 | static void __wrmsr_on_cpu(void *info) | ||
21 | { | ||
22 | struct msr_info *rv = info; | ||
23 | struct msr *reg; | ||
24 | int this_cpu = raw_smp_processor_id(); | ||
25 | |||
26 | if (rv->msrs) | ||
27 | reg = per_cpu_ptr(rv->msrs, this_cpu); | ||
28 | else | ||
29 | reg = &rv->reg; | ||
30 | |||
31 | wrmsr(rv->msr_no, reg->l, reg->h); | ||
32 | } | ||
33 | |||
34 | int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) | ||
35 | { | ||
36 | int err; | ||
37 | struct msr_info rv; | ||
38 | |||
39 | memset(&rv, 0, sizeof(rv)); | ||
40 | |||
41 | rv.msr_no = msr_no; | ||
42 | err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); | ||
43 | *l = rv.reg.l; | ||
44 | *h = rv.reg.h; | ||
45 | |||
46 | return err; | ||
47 | } | ||
48 | EXPORT_SYMBOL(rdmsr_on_cpu); | ||
49 | |||
50 | int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | ||
51 | { | ||
52 | int err; | ||
53 | struct msr_info rv; | ||
54 | |||
55 | memset(&rv, 0, sizeof(rv)); | ||
56 | |||
57 | rv.msr_no = msr_no; | ||
58 | rv.reg.l = l; | ||
59 | rv.reg.h = h; | ||
60 | err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); | ||
61 | |||
62 | return err; | ||
63 | } | ||
64 | EXPORT_SYMBOL(wrmsr_on_cpu); | ||
65 | |||
66 | static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no, | ||
67 | struct msr *msrs, | ||
68 | void (*msr_func) (void *info)) | ||
69 | { | ||
70 | struct msr_info rv; | ||
71 | int this_cpu; | ||
72 | |||
73 | memset(&rv, 0, sizeof(rv)); | ||
74 | |||
75 | rv.msrs = msrs; | ||
76 | rv.msr_no = msr_no; | ||
77 | |||
78 | this_cpu = get_cpu(); | ||
79 | |||
80 | if (cpumask_test_cpu(this_cpu, mask)) | ||
81 | msr_func(&rv); | ||
82 | |||
83 | smp_call_function_many(mask, msr_func, &rv, 1); | ||
84 | put_cpu(); | ||
85 | } | ||
86 | |||
87 | /* rdmsr on a bunch of CPUs | ||
88 | * | ||
89 | * @mask: which CPUs | ||
90 | * @msr_no: which MSR | ||
91 | * @msrs: array of MSR values | ||
92 | * | ||
93 | */ | ||
94 | void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs) | ||
95 | { | ||
96 | __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu); | ||
97 | } | ||
98 | EXPORT_SYMBOL(rdmsr_on_cpus); | ||
99 | |||
100 | /* | ||
101 | * wrmsr on a bunch of CPUs | ||
102 | * | ||
103 | * @mask: which CPUs | ||
104 | * @msr_no: which MSR | ||
105 | * @msrs: array of MSR values | ||
106 | * | ||
107 | */ | ||
108 | void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs) | ||
109 | { | ||
110 | __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu); | ||
111 | } | ||
112 | EXPORT_SYMBOL(wrmsr_on_cpus); | ||
113 | |||
114 | /* These "safe" variants are slower and should be used when the target MSR | ||
115 | may not actually exist. */ | ||
116 | static void __rdmsr_safe_on_cpu(void *info) | ||
117 | { | ||
118 | struct msr_info *rv = info; | ||
119 | |||
120 | rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); | ||
121 | } | ||
122 | |||
123 | static void __wrmsr_safe_on_cpu(void *info) | ||
124 | { | ||
125 | struct msr_info *rv = info; | ||
126 | |||
127 | rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h); | ||
128 | } | ||
129 | |||
130 | int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) | ||
131 | { | ||
132 | int err; | ||
133 | struct msr_info rv; | ||
134 | |||
135 | memset(&rv, 0, sizeof(rv)); | ||
136 | |||
137 | rv.msr_no = msr_no; | ||
138 | err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); | ||
139 | *l = rv.reg.l; | ||
140 | *h = rv.reg.h; | ||
141 | |||
142 | return err ? err : rv.err; | ||
143 | } | ||
144 | EXPORT_SYMBOL(rdmsr_safe_on_cpu); | ||
145 | |||
146 | int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | ||
147 | { | ||
148 | int err; | ||
149 | struct msr_info rv; | ||
150 | |||
151 | memset(&rv, 0, sizeof(rv)); | ||
152 | |||
153 | rv.msr_no = msr_no; | ||
154 | rv.reg.l = l; | ||
155 | rv.reg.h = h; | ||
156 | err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); | ||
157 | |||
158 | return err ? err : rv.err; | ||
159 | } | ||
160 | EXPORT_SYMBOL(wrmsr_safe_on_cpu); | ||
161 | |||
162 | /* | ||
163 | * These variants are significantly slower, but allows control over | ||
164 | * the entire 32-bit GPR set. | ||
165 | */ | ||
166 | static void __rdmsr_safe_regs_on_cpu(void *info) | ||
167 | { | ||
168 | struct msr_regs_info *rv = info; | ||
169 | |||
170 | rv->err = rdmsr_safe_regs(rv->regs); | ||
171 | } | ||
172 | |||
173 | static void __wrmsr_safe_regs_on_cpu(void *info) | ||
174 | { | ||
175 | struct msr_regs_info *rv = info; | ||
176 | |||
177 | rv->err = wrmsr_safe_regs(rv->regs); | ||
178 | } | ||
179 | |||
180 | int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) | ||
181 | { | ||
182 | int err; | ||
183 | struct msr_regs_info rv; | ||
184 | |||
185 | rv.regs = regs; | ||
186 | rv.err = -EIO; | ||
187 | err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1); | ||
188 | |||
189 | return err ? err : rv.err; | ||
190 | } | ||
191 | EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu); | ||
192 | |||
193 | int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) | ||
194 | { | ||
195 | int err; | ||
196 | struct msr_regs_info rv; | ||
197 | |||
198 | rv.regs = regs; | ||
199 | rv.err = -EIO; | ||
200 | err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1); | ||
201 | |||
202 | return err ? err : rv.err; | ||
203 | } | ||
204 | EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu); | ||
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index 872834177937..8f8eebdca7d4 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c | |||
@@ -1,123 +1,7 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/preempt.h> | 2 | #include <linux/preempt.h> |
3 | #include <linux/smp.h> | ||
4 | #include <asm/msr.h> | 3 | #include <asm/msr.h> |
5 | 4 | ||
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) | 5 | struct msr *msrs_alloc(void) |
122 | { | 6 | { |
123 | struct msr *msrs = NULL; | 7 | struct msr *msrs = NULL; |
@@ -137,100 +21,3 @@ void msrs_free(struct msr *msrs) | |||
137 | free_percpu(msrs); | 21 | free_percpu(msrs); |
138 | } | 22 | } |
139 | EXPORT_SYMBOL(msrs_free); | 23 | 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); | ||