1#include <linux/module.h>
2#include <linux/preempt.h>
3#include <linux/smp.h>
4#include <asm/msr.h>
5
6struct msr_info {
7	u32 msr_no;
8	u32 l, h;
9	int err;
10};
11
12static void __rdmsr_on_cpu(void *info)
13{
14	struct msr_info *rv = info;
15
16	rdmsr(rv->msr_no, rv->l, rv->h);
17}
18
19static void __rdmsr_safe_on_cpu(void *info)
20{
21	struct msr_info *rv = info;
22
23	rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h);
24}
25
26static int _rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h, int safe)
27{
28	int err = 0;
29	preempt_disable();
30	if (smp_processor_id() == cpu)
31		if (safe)
32			err = rdmsr_safe(msr_no, l, h);
33		else
34			rdmsr(msr_no, *l, *h);
35	else {
36		struct msr_info rv;
37
38		rv.msr_no = msr_no;
39		if (safe) {
40			smp_call_function_single(cpu, __rdmsr_safe_on_cpu,
41						 &rv, 0, 1);
42			err = rv.err;
43		} else {
44			smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1);
45		}
46		*l = rv.l;
47		*h = rv.h;
48	}
49	preempt_enable();
50	return err;
51}
52
53static void __wrmsr_on_cpu(void *info)
54{
55	struct msr_info *rv = info;
56
57	wrmsr(rv->msr_no, rv->l, rv->h);
58}
59
60static void __wrmsr_safe_on_cpu(void *info)
61{
62	struct msr_info *rv = info;
63
64	rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h);
65}
66
67static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe)
68{
69	int err = 0;
70	preempt_disable();
71	if (smp_processor_id() == cpu)
72		if (safe)
73			err = wrmsr_safe(msr_no, l, h);
74		else
75			wrmsr(msr_no, l, h);
76	else {
77		struct msr_info rv;
78
79		rv.msr_no = msr_no;
80		rv.l = l;
81		rv.h = h;
82		if (safe) {
83			smp_call_function_single(cpu, __wrmsr_safe_on_cpu,
84						 &rv, 0, 1);
85			err = rv.err;
86		} else {
87			smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1);
88		}
89	}
90	preempt_enable();
91	return err;
92}
93
94void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
95{
96	_wrmsr_on_cpu(cpu, msr_no, l, h, 0);
97}
98
99void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
100{
101	_rdmsr_on_cpu(cpu, msr_no, l, h, 0);
102}
103
104/* These "safe" variants are slower and should be used when the target MSR
105   may not actually exist. */
106int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
107{
108	return _wrmsr_on_cpu(cpu, msr_no, l, h, 1);
109}
110
111int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
112{
113	return _rdmsr_on_cpu(cpu, msr_no, l, h, 1);
114}
115
116EXPORT_SYMBOL(rdmsr_on_cpu);
117EXPORT_SYMBOL(wrmsr_on_cpu);
118EXPORT_SYMBOL(rdmsr_safe_on_cpu);
119EXPORT_SYMBOL(wrmsr_safe_on_cpu);
120