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  
msrs_alloc(void)9  struct msr __percpu *msrs_alloc(void)
10  {
11  	struct msr __percpu *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  
msrs_free(struct msr __percpu * msrs)23  void msrs_free(struct msr __percpu *msrs)
24  {
25  	free_percpu(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   */
msr_read(u32 msr,struct msr * m)39  static 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   * 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   */
msr_write(u32 msr,struct msr * m)59  static int msr_write(u32 msr, struct msr *m)
60  {
61  	return wrmsrl_safe(msr, m->q);
62  }
63  
__flip_bit(u32 msr,u8 bit,bool set)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);
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, &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   */
msr_set_bit(u32 msr,u8 bit)102  int msr_set_bit(u32 msr, u8 bit)
103  {
104  	return __flip_bit(msr, bit, 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   */
msr_clear_bit(u32 msr,u8 bit)117  int msr_clear_bit(u32 msr, u8 bit)
118  {
119  	return __flip_bit(msr, bit, false);
120  }
121  
122  #ifdef CONFIG_TRACEPOINTS
do_trace_write_msr(unsigned int msr,u64 val,int failed)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  
do_trace_read_msr(unsigned int msr,u64 val,int failed)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  
do_trace_rdpmc(unsigned counter,u64 val,int failed)137  void do_trace_rdpmc(unsigned counter, u64 val, int failed)
138  {
139  	trace_rdpmc(counter, val, failed);
140  }
141  EXPORT_SYMBOL(do_trace_rdpmc);
142  EXPORT_TRACEPOINT_SYMBOL(rdpmc);
143  
144  #endif
145