Commit | Line | Data |
---|---|---|
b077ffb3 AD |
1 | #include <linux/module.h> |
2 | #include <linux/preempt.h> | |
b077ffb3 | 3 | #include <asm/msr.h> |
7f47d8cc AK |
4 | #define CREATE_TRACE_POINTS |
5 | #include <asm/msr-trace.h> | |
b077ffb3 | 6 | |
50542251 BP |
7 | struct msr *msrs_alloc(void) |
8 | { | |
9 | struct msr *msrs = NULL; | |
10 | ||
11 | msrs = alloc_percpu(struct msr); | |
12 | if (!msrs) { | |
22085a66 | 13 | pr_warn("%s: error allocating msrs\n", __func__); |
50542251 BP |
14 | return NULL; |
15 | } | |
16 | ||
17 | return msrs; | |
18 | } | |
19 | EXPORT_SYMBOL(msrs_alloc); | |
20 | ||
21 | void msrs_free(struct msr *msrs) | |
22 | { | |
23 | free_percpu(msrs); | |
24 | } | |
25 | EXPORT_SYMBOL(msrs_free); | |
22085a66 BP |
26 | |
27 | /** | |
28 | * Read an MSR with error handling | |
29 | * | |
30 | * @msr: MSR to read | |
31 | * @m: value to read into | |
32 | * | |
33 | * It returns read data only on success, otherwise it doesn't change the output | |
34 | * argument @m. | |
35 | * | |
36 | */ | |
37 | int msr_read(u32 msr, struct msr *m) | |
38 | { | |
39 | int err; | |
40 | u64 val; | |
41 | ||
42 | err = rdmsrl_safe(msr, &val); | |
43 | if (!err) | |
44 | m->q = val; | |
45 | ||
46 | return err; | |
47 | } | |
48 | ||
49 | /** | |
50 | * Write an MSR with error handling | |
51 | * | |
52 | * @msr: MSR to write | |
53 | * @m: value to write | |
54 | */ | |
55 | int msr_write(u32 msr, struct msr *m) | |
56 | { | |
57 | return wrmsrl_safe(msr, m->q); | |
58 | } | |
59 | ||
60 | static inline int __flip_bit(u32 msr, u8 bit, bool set) | |
61 | { | |
62 | struct msr m, m1; | |
63 | int err = -EINVAL; | |
64 | ||
65 | if (bit > 63) | |
66 | return err; | |
67 | ||
68 | err = msr_read(msr, &m); | |
69 | if (err) | |
70 | return err; | |
71 | ||
72 | m1 = m; | |
73 | if (set) | |
74 | m1.q |= BIT_64(bit); | |
75 | else | |
76 | m1.q &= ~BIT_64(bit); | |
77 | ||
78 | if (m1.q == m.q) | |
79 | return 0; | |
80 | ||
722a0d22 | 81 | err = msr_write(msr, &m1); |
22085a66 BP |
82 | if (err) |
83 | return err; | |
84 | ||
85 | return 1; | |
86 | } | |
87 | ||
88 | /** | |
89 | * Set @bit in a MSR @msr. | |
90 | * | |
91 | * Retval: | |
92 | * < 0: An error was encountered. | |
93 | * = 0: Bit was already set. | |
94 | * > 0: Hardware accepted the MSR write. | |
95 | */ | |
96 | int msr_set_bit(u32 msr, u8 bit) | |
97 | { | |
98 | return __flip_bit(msr, bit, true); | |
99 | } | |
100 | ||
101 | /** | |
102 | * Clear @bit in a MSR @msr. | |
103 | * | |
104 | * Retval: | |
105 | * < 0: An error was encountered. | |
106 | * = 0: Bit was already cleared. | |
107 | * > 0: Hardware accepted the MSR write. | |
108 | */ | |
109 | int msr_clear_bit(u32 msr, u8 bit) | |
110 | { | |
111 | return __flip_bit(msr, bit, false); | |
112 | } | |
7f47d8cc AK |
113 | |
114 | #ifdef CONFIG_TRACEPOINTS | |
115 | void do_trace_write_msr(unsigned msr, u64 val, int failed) | |
116 | { | |
117 | trace_write_msr(msr, val, failed); | |
118 | } | |
119 | EXPORT_SYMBOL(do_trace_write_msr); | |
120 | EXPORT_TRACEPOINT_SYMBOL(write_msr); | |
121 | ||
122 | void do_trace_read_msr(unsigned msr, u64 val, int failed) | |
123 | { | |
124 | trace_read_msr(msr, val, failed); | |
125 | } | |
126 | EXPORT_SYMBOL(do_trace_read_msr); | |
127 | EXPORT_TRACEPOINT_SYMBOL(read_msr); | |
128 | ||
129 | void do_trace_rdpmc(unsigned counter, u64 val, int failed) | |
130 | { | |
131 | trace_rdpmc(counter, val, failed); | |
132 | } | |
133 | EXPORT_SYMBOL(do_trace_rdpmc); | |
134 | EXPORT_TRACEPOINT_SYMBOL(rdpmc); | |
135 | ||
136 | #endif |