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 __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 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 */ 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 */ 59 static int msr_write(u32 msr, struct msr *m) 60 { 61 return wrmsrl_safe(msr, 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); 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 */ 102 int msr_set_bit(u32 msr, u8 bit) 103 { 104 return __flip_bit(msr, bit, true); 105 } 106 EXPORT_SYMBOL_GPL(msr_set_bit); 107 108 /** 109 * msr_clear_bit - Clear @bit in a MSR @msr. 110 * @msr: MSR to write 111 * @bit: bit number to clear 112 * 113 * Return: 114 * * < 0: An error was encountered. 115 * * = 0: Bit was already cleared. 116 * * > 0: Hardware accepted the MSR write. 117 */ 118 int msr_clear_bit(u32 msr, u8 bit) 119 { 120 return __flip_bit(msr, bit, false); 121 } 122 EXPORT_SYMBOL_GPL(msr_clear_bit); 123 124 #ifdef CONFIG_TRACEPOINTS 125 void do_trace_write_msr(unsigned int msr, u64 val, int failed) 126 { 127 trace_write_msr(msr, val, failed); 128 } 129 EXPORT_SYMBOL(do_trace_write_msr); 130 EXPORT_TRACEPOINT_SYMBOL(write_msr); 131 132 void do_trace_read_msr(unsigned int msr, u64 val, int failed) 133 { 134 trace_read_msr(msr, val, failed); 135 } 136 EXPORT_SYMBOL(do_trace_read_msr); 137 EXPORT_TRACEPOINT_SYMBOL(read_msr); 138 139 void do_trace_rdpmc(unsigned counter, u64 val, int failed) 140 { 141 trace_rdpmc(counter, val, failed); 142 } 143 EXPORT_SYMBOL(do_trace_rdpmc); 144 EXPORT_TRACEPOINT_SYMBOL(rdpmc); 145 146 #endif 147