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(msrs); |
26 | } |
27 | EXPORT_SYMBOL(msrs_free); |
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 | |
83 | err = msr_write(msr, &m1); |
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 | } |
115 | |
116 | #ifdef CONFIG_TRACEPOINTS |
117 | void do_trace_write_msr(unsigned int msr, u64 val, int failed) |
118 | { |
119 | trace_write_msr(msr, val, failed); |
120 | } |
121 | EXPORT_SYMBOL(do_trace_write_msr); |
122 | EXPORT_TRACEPOINT_SYMBOL(write_msr); |
123 | |
124 | void do_trace_read_msr(unsigned int msr, u64 val, int failed) |
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 |
139 | |