Line data Source code
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 0 : struct msr *msrs_alloc(void)
10 : {
11 0 : struct msr *msrs = NULL;
12 :
13 0 : msrs = alloc_percpu(struct msr);
14 0 : if (!msrs) {
15 0 : pr_warn("%s: error allocating msrs\n", __func__);
16 0 : return NULL;
17 : }
18 :
19 : return msrs;
20 : }
21 : EXPORT_SYMBOL(msrs_alloc);
22 :
23 0 : void msrs_free(struct msr *msrs)
24 : {
25 0 : free_percpu(msrs);
26 0 : }
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 9 : int msr_read(u32 msr, struct msr *m)
40 : {
41 9 : int err;
42 9 : u64 val;
43 :
44 9 : err = rdmsrl_safe(msr, &val);
45 9 : if (!err)
46 9 : m->q = val;
47 :
48 9 : 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 0 : int msr_write(u32 msr, struct msr *m)
58 : {
59 0 : return wrmsrl_safe(msr, m->q);
60 : }
61 :
62 9 : static inline int __flip_bit(u32 msr, u8 bit, bool set)
63 : {
64 9 : struct msr m, m1;
65 9 : int err = -EINVAL;
66 :
67 9 : if (bit > 63)
68 : return err;
69 :
70 9 : err = msr_read(msr, &m);
71 9 : if (err)
72 : return err;
73 :
74 9 : m1 = m;
75 9 : if (set)
76 0 : m1.q |= BIT_64(bit);
77 : else
78 9 : m1.q &= ~BIT_64(bit);
79 :
80 9 : if (m1.q == m.q)
81 : return 0;
82 :
83 0 : err = msr_write(msr, &m1);
84 0 : if (err)
85 0 : 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 0 : int msr_set_bit(u32 msr, u8 bit)
99 : {
100 0 : 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 9 : int msr_clear_bit(u32 msr, u8 bit)
112 : {
113 9 : return __flip_bit(msr, bit, false);
114 : }
115 :
116 : #ifdef CONFIG_TRACEPOINTS
117 0 : void do_trace_write_msr(unsigned int msr, u64 val, int failed)
118 : {
119 0 : trace_write_msr(msr, val, failed);
120 0 : }
121 : EXPORT_SYMBOL(do_trace_write_msr);
122 : EXPORT_TRACEPOINT_SYMBOL(write_msr);
123 :
124 0 : void do_trace_read_msr(unsigned int msr, u64 val, int failed)
125 : {
126 0 : trace_read_msr(msr, val, failed);
127 0 : }
128 : EXPORT_SYMBOL(do_trace_read_msr);
129 : EXPORT_TRACEPOINT_SYMBOL(read_msr);
130 :
131 0 : void do_trace_rdpmc(unsigned counter, u64 val, int failed)
132 : {
133 0 : trace_rdpmc(counter, val, failed);
134 0 : }
135 : EXPORT_SYMBOL(do_trace_rdpmc);
136 : EXPORT_TRACEPOINT_SYMBOL(rdpmc);
137 :
138 : #endif
|