18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/export.h> 38c2ecf20Sopenharmony_ci#include <linux/percpu.h> 48c2ecf20Sopenharmony_ci#include <linux/preempt.h> 58c2ecf20Sopenharmony_ci#include <asm/msr.h> 68c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 78c2ecf20Sopenharmony_ci#include <asm/msr-trace.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistruct msr *msrs_alloc(void) 108c2ecf20Sopenharmony_ci{ 118c2ecf20Sopenharmony_ci struct msr *msrs = NULL; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci msrs = alloc_percpu(struct msr); 148c2ecf20Sopenharmony_ci if (!msrs) { 158c2ecf20Sopenharmony_ci pr_warn("%s: error allocating msrs\n", __func__); 168c2ecf20Sopenharmony_ci return NULL; 178c2ecf20Sopenharmony_ci } 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci return msrs; 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(msrs_alloc); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_civoid msrs_free(struct msr *msrs) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci free_percpu(msrs); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(msrs_free); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/** 308c2ecf20Sopenharmony_ci * Read an MSR with error handling 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * @msr: MSR to read 338c2ecf20Sopenharmony_ci * @m: value to read into 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * It returns read data only on success, otherwise it doesn't change the output 368c2ecf20Sopenharmony_ci * argument @m. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ciint msr_read(u32 msr, struct msr *m) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci int err; 428c2ecf20Sopenharmony_ci u64 val; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci err = rdmsrl_safe(msr, &val); 458c2ecf20Sopenharmony_ci if (!err) 468c2ecf20Sopenharmony_ci m->q = val; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci return err; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/** 528c2ecf20Sopenharmony_ci * Write an MSR with error handling 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * @msr: MSR to write 558c2ecf20Sopenharmony_ci * @m: value to write 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ciint msr_write(u32 msr, struct msr *m) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return wrmsrl_safe(msr, m->q); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline int __flip_bit(u32 msr, u8 bit, bool set) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct msr m, m1; 658c2ecf20Sopenharmony_ci int err = -EINVAL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (bit > 63) 688c2ecf20Sopenharmony_ci return err; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci err = msr_read(msr, &m); 718c2ecf20Sopenharmony_ci if (err) 728c2ecf20Sopenharmony_ci return err; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci m1 = m; 758c2ecf20Sopenharmony_ci if (set) 768c2ecf20Sopenharmony_ci m1.q |= BIT_64(bit); 778c2ecf20Sopenharmony_ci else 788c2ecf20Sopenharmony_ci m1.q &= ~BIT_64(bit); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (m1.q == m.q) 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci err = msr_write(msr, &m1); 848c2ecf20Sopenharmony_ci if (err) 858c2ecf20Sopenharmony_ci return err; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return 1; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/** 918c2ecf20Sopenharmony_ci * Set @bit in a MSR @msr. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Retval: 948c2ecf20Sopenharmony_ci * < 0: An error was encountered. 958c2ecf20Sopenharmony_ci * = 0: Bit was already set. 968c2ecf20Sopenharmony_ci * > 0: Hardware accepted the MSR write. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ciint msr_set_bit(u32 msr, u8 bit) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci return __flip_bit(msr, bit, true); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * Clear @bit in a MSR @msr. 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * Retval: 1078c2ecf20Sopenharmony_ci * < 0: An error was encountered. 1088c2ecf20Sopenharmony_ci * = 0: Bit was already cleared. 1098c2ecf20Sopenharmony_ci * > 0: Hardware accepted the MSR write. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ciint msr_clear_bit(u32 msr, u8 bit) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return __flip_bit(msr, bit, false); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#ifdef CONFIG_TRACEPOINTS 1178c2ecf20Sopenharmony_civoid do_trace_write_msr(unsigned int msr, u64 val, int failed) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci trace_write_msr(msr, val, failed); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(do_trace_write_msr); 1228c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(write_msr); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_civoid do_trace_read_msr(unsigned int msr, u64 val, int failed) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci trace_read_msr(msr, val, failed); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(do_trace_read_msr); 1298c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(read_msr); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid do_trace_rdpmc(unsigned counter, u64 val, int failed) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci trace_rdpmc(counter, val, failed); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(do_trace_rdpmc); 1368c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(rdpmc); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#endif 139