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