Branch data 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 : 28 : int msr_read(u32 msr, struct msr *m)
40 : : {
41 : 28 : int err;
42 : 28 : u64 val;
43 : :
44 : 0 : err = rdmsrl_safe(msr, &val);
45 [ + - - - ]: 28 : if (!err)
46 : 28 : m->q = val;
47 : :
48 : 28 : 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 : 28 : int msr_write(u32 msr, struct msr *m)
58 : : {
59 : 0 : return wrmsrl_safe(msr, m->q);
60 : : }
61 : :
62 : 28 : static inline int __flip_bit(u32 msr, u8 bit, bool set)
63 : : {
64 : 28 : struct msr m, m1;
65 : 28 : int err = -EINVAL;
66 : :
67 [ + - ]: 28 : if (bit > 63)
68 : : return err;
69 : :
70 : 28 : err = msr_read(msr, &m);
71 [ + - ]: 28 : if (err)
72 : : return err;
73 : :
74 : 28 : m1 = m;
75 [ + - ]: 28 : if (set)
76 : 28 : m1.q |= BIT_64(bit);
77 : : else
78 : 0 : m1.q &= ~BIT_64(bit);
79 : :
80 [ + - ]: 28 : if (m1.q == m.q)
81 : : return 0;
82 : :
83 : 28 : err = msr_write(msr, &m1);
84 [ - + ]: 28 : 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 : 28 : int msr_set_bit(u32 msr, u8 bit)
99 : : {
100 : 28 : 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 : 0 : int msr_clear_bit(u32 msr, u8 bit)
112 : : {
113 : 0 : 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
|