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