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