1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/export.h> |
3 | #include <linux/percpu.h> |
4 | #include <linux/preempt.h> |
5 | #include <asm/msr.h> |
6 | #define CREATE_TRACE_POINTS |
7 | #include <asm/msr-trace.h> |
8 | |
9 | struct msr *msrs_alloc(void) |
10 | { |
11 | struct msr *msrs = NULL; |
12 | |
13 | msrs = alloc_percpu(struct msr); |
14 | if (!msrs) { |
15 | pr_warn("%s: error allocating msrs\n" , __func__); |
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(pdata: msrs); |
26 | } |
27 | EXPORT_SYMBOL(msrs_free); |
28 | |
29 | /** |
30 | * msr_read - Read an MSR with error handling |
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 | * Return: %0 for success, otherwise an error code |
38 | */ |
39 | static int msr_read(u32 msr, struct msr *m) |
40 | { |
41 | int err; |
42 | u64 val; |
43 | |
44 | err = rdmsrl_safe(msr, p: &val); |
45 | if (!err) |
46 | m->q = val; |
47 | |
48 | return err; |
49 | } |
50 | |
51 | /** |
52 | * msr_write - Write an MSR with error handling |
53 | * |
54 | * @msr: MSR to write |
55 | * @m: value to write |
56 | * |
57 | * Return: %0 for success, otherwise an error code |
58 | */ |
59 | static int msr_write(u32 msr, struct msr *m) |
60 | { |
61 | return wrmsrl_safe(msr, val: m->q); |
62 | } |
63 | |
64 | static inline int __flip_bit(u32 msr, u8 bit, bool set) |
65 | { |
66 | struct msr m, m1; |
67 | int err = -EINVAL; |
68 | |
69 | if (bit > 63) |
70 | return err; |
71 | |
72 | err = msr_read(msr, m: &m); |
73 | if (err) |
74 | return err; |
75 | |
76 | m1 = m; |
77 | if (set) |
78 | m1.q |= BIT_64(bit); |
79 | else |
80 | m1.q &= ~BIT_64(bit); |
81 | |
82 | if (m1.q == m.q) |
83 | return 0; |
84 | |
85 | err = msr_write(msr, m: &m1); |
86 | if (err) |
87 | return err; |
88 | |
89 | return 1; |
90 | } |
91 | |
92 | /** |
93 | * msr_set_bit - Set @bit in a MSR @msr. |
94 | * @msr: MSR to write |
95 | * @bit: bit number to set |
96 | * |
97 | * Return: |
98 | * * < 0: An error was encountered. |
99 | * * = 0: Bit was already set. |
100 | * * > 0: Hardware accepted the MSR write. |
101 | */ |
102 | int msr_set_bit(u32 msr, u8 bit) |
103 | { |
104 | return __flip_bit(msr, bit, set: true); |
105 | } |
106 | |
107 | /** |
108 | * msr_clear_bit - Clear @bit in a MSR @msr. |
109 | * @msr: MSR to write |
110 | * @bit: bit number to clear |
111 | * |
112 | * Return: |
113 | * * < 0: An error was encountered. |
114 | * * = 0: Bit was already cleared. |
115 | * * > 0: Hardware accepted the MSR write. |
116 | */ |
117 | int msr_clear_bit(u32 msr, u8 bit) |
118 | { |
119 | return __flip_bit(msr, bit, set: false); |
120 | } |
121 | |
122 | #ifdef CONFIG_TRACEPOINTS |
123 | void do_trace_write_msr(unsigned int msr, u64 val, int failed) |
124 | { |
125 | trace_write_msr(msr, val, failed); |
126 | } |
127 | EXPORT_SYMBOL(do_trace_write_msr); |
128 | EXPORT_TRACEPOINT_SYMBOL(write_msr); |
129 | |
130 | void do_trace_read_msr(unsigned int msr, u64 val, int failed) |
131 | { |
132 | trace_read_msr(msr, val, failed); |
133 | } |
134 | EXPORT_SYMBOL(do_trace_read_msr); |
135 | EXPORT_TRACEPOINT_SYMBOL(read_msr); |
136 | |
137 | void do_trace_rdpmc(unsigned counter, u64 val, int failed) |
138 | { |
139 | trace_rdpmc(msr: counter, val, failed); |
140 | } |
141 | EXPORT_SYMBOL(do_trace_rdpmc); |
142 | EXPORT_TRACEPOINT_SYMBOL(rdpmc); |
143 | |
144 | #endif |
145 | |