blob: 01b868ba82f8c21fd8384a426236e3a315f82dea [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;
8 u32 l, h;
Rudolf Marek4e9baad2007-05-08 17:22:01 +02009 int err;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080010};
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
Rudolf Marek4e9baad2007-05-08 17:22:01 +020019static void __rdmsr_safe_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080020{
Rudolf Marek4e9baad2007-05-08 17:22:01 +020021 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;
Avi Kivity5f1f9352007-10-17 18:04:38 +020029 struct msr_info rv;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080030
Avi Kivity5f1f9352007-10-17 18:04:38 +020031 rv.msr_no = msr_no;
32 if (safe) {
H. Peter Anvinc6f31932008-08-25 17:27:21 -070033 err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu,
34 &rv, 1);
35 err = err ? err : rv.err;
Avi Kivity5f1f9352007-10-17 18:04:38 +020036 } else {
H. Peter Anvinc6f31932008-08-25 17:27:21 -070037 err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080038 }
Avi Kivity5f1f9352007-10-17 18:04:38 +020039 *l = rv.l;
40 *h = rv.h;
41
Rudolf Marek4e9baad2007-05-08 17:22:01 +020042 return err;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080043}
44
45static void __wrmsr_on_cpu(void *info)
46{
47 struct msr_info *rv = info;
48
49 wrmsr(rv->msr_no, rv->l, rv->h);
50}
51
Rudolf Marek4e9baad2007-05-08 17:22:01 +020052static void __wrmsr_safe_on_cpu(void *info)
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080053{
Rudolf Marek4e9baad2007-05-08 17:22:01 +020054 struct msr_info *rv = info;
55
56 rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h);
57}
58
59static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe)
60{
61 int err = 0;
Avi Kivity5f1f9352007-10-17 18:04:38 +020062 struct msr_info rv;
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080063
Avi Kivity5f1f9352007-10-17 18:04:38 +020064 rv.msr_no = msr_no;
65 rv.l = l;
66 rv.h = h;
67 if (safe) {
H. Peter Anvinc6f31932008-08-25 17:27:21 -070068 err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu,
69 &rv, 1);
70 err = err ? err : rv.err;
Avi Kivity5f1f9352007-10-17 18:04:38 +020071 } else {
H. Peter Anvinc6f31932008-08-25 17:27:21 -070072 err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080073 }
Avi Kivity5f1f9352007-10-17 18:04:38 +020074
Rudolf Marek4e9baad2007-05-08 17:22:01 +020075 return err;
76}
77
H. Peter Anvinc6f31932008-08-25 17:27:21 -070078int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
Rudolf Marek4e9baad2007-05-08 17:22:01 +020079{
H. Peter Anvinc6f31932008-08-25 17:27:21 -070080 return _wrmsr_on_cpu(cpu, msr_no, l, h, 0);
Rudolf Marek4e9baad2007-05-08 17:22:01 +020081}
82
H. Peter Anvinc6f31932008-08-25 17:27:21 -070083int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
Rudolf Marek4e9baad2007-05-08 17:22:01 +020084{
H. Peter Anvinc6f31932008-08-25 17:27:21 -070085 return _rdmsr_on_cpu(cpu, msr_no, l, h, 0);
Rudolf Marek4e9baad2007-05-08 17:22:01 +020086}
87
88/* These "safe" variants are slower and should be used when the target MSR
89 may not actually exist. */
90int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
91{
92 return _wrmsr_on_cpu(cpu, msr_no, l, h, 1);
93}
94
95int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
96{
97 return _rdmsr_on_cpu(cpu, msr_no, l, h, 1);
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080098}
Alexey Dobriyanb077ffb2007-02-16 01:48:11 -080099
100EXPORT_SYMBOL(rdmsr_on_cpu);
101EXPORT_SYMBOL(wrmsr_on_cpu);
Rudolf Marek4e9baad2007-05-08 17:22:01 +0200102EXPORT_SYMBOL(rdmsr_safe_on_cpu);
103EXPORT_SYMBOL(wrmsr_safe_on_cpu);