18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/export.h>
38c2ecf20Sopenharmony_ci#include <linux/preempt.h>
48c2ecf20Sopenharmony_ci#include <linux/smp.h>
58c2ecf20Sopenharmony_ci#include <linux/completion.h>
68c2ecf20Sopenharmony_ci#include <asm/msr.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cistatic void __rdmsr_on_cpu(void *info)
98c2ecf20Sopenharmony_ci{
108c2ecf20Sopenharmony_ci	struct msr_info *rv = info;
118c2ecf20Sopenharmony_ci	struct msr *reg;
128c2ecf20Sopenharmony_ci	int this_cpu = raw_smp_processor_id();
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	if (rv->msrs)
158c2ecf20Sopenharmony_ci		reg = per_cpu_ptr(rv->msrs, this_cpu);
168c2ecf20Sopenharmony_ci	else
178c2ecf20Sopenharmony_ci		reg = &rv->reg;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	rdmsr(rv->msr_no, reg->l, reg->h);
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void __wrmsr_on_cpu(void *info)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct msr_info *rv = info;
258c2ecf20Sopenharmony_ci	struct msr *reg;
268c2ecf20Sopenharmony_ci	int this_cpu = raw_smp_processor_id();
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	if (rv->msrs)
298c2ecf20Sopenharmony_ci		reg = per_cpu_ptr(rv->msrs, this_cpu);
308c2ecf20Sopenharmony_ci	else
318c2ecf20Sopenharmony_ci		reg = &rv->reg;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	wrmsr(rv->msr_no, reg->l, reg->h);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	int err;
398c2ecf20Sopenharmony_ci	struct msr_info rv;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
448c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
458c2ecf20Sopenharmony_ci	*l = rv.reg.l;
468c2ecf20Sopenharmony_ci	*h = rv.reg.h;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	return err;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdmsr_on_cpu);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	int err;
558c2ecf20Sopenharmony_ci	struct msr_info rv;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
608c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
618c2ecf20Sopenharmony_ci	*q = rv.reg.q;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return err;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdmsrl_on_cpu);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciint wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	int err;
708c2ecf20Sopenharmony_ci	struct msr_info rv;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
758c2ecf20Sopenharmony_ci	rv.reg.l = l;
768c2ecf20Sopenharmony_ci	rv.reg.h = h;
778c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return err;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wrmsr_on_cpu);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ciint wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	int err;
868c2ecf20Sopenharmony_ci	struct msr_info rv;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
918c2ecf20Sopenharmony_ci	rv.reg.q = q;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return err;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wrmsrl_on_cpu);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
1008c2ecf20Sopenharmony_ci			    struct msr *msrs,
1018c2ecf20Sopenharmony_ci			    void (*msr_func) (void *info))
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct msr_info rv;
1048c2ecf20Sopenharmony_ci	int this_cpu;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	rv.msrs	  = msrs;
1098c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	this_cpu = get_cpu();
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (cpumask_test_cpu(this_cpu, mask))
1148c2ecf20Sopenharmony_ci		msr_func(&rv);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	smp_call_function_many(mask, msr_func, &rv, 1);
1178c2ecf20Sopenharmony_ci	put_cpu();
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/* rdmsr on a bunch of CPUs
1218c2ecf20Sopenharmony_ci *
1228c2ecf20Sopenharmony_ci * @mask:       which CPUs
1238c2ecf20Sopenharmony_ci * @msr_no:     which MSR
1248c2ecf20Sopenharmony_ci * @msrs:       array of MSR values
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_civoid rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	__rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdmsr_on_cpus);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/*
1348c2ecf20Sopenharmony_ci * wrmsr on a bunch of CPUs
1358c2ecf20Sopenharmony_ci *
1368c2ecf20Sopenharmony_ci * @mask:       which CPUs
1378c2ecf20Sopenharmony_ci * @msr_no:     which MSR
1388c2ecf20Sopenharmony_ci * @msrs:       array of MSR values
1398c2ecf20Sopenharmony_ci *
1408c2ecf20Sopenharmony_ci */
1418c2ecf20Sopenharmony_civoid wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	__rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wrmsr_on_cpus);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistruct msr_info_completion {
1488c2ecf20Sopenharmony_ci	struct msr_info		msr;
1498c2ecf20Sopenharmony_ci	struct completion	done;
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/* These "safe" variants are slower and should be used when the target MSR
1538c2ecf20Sopenharmony_ci   may not actually exist. */
1548c2ecf20Sopenharmony_cistatic void __rdmsr_safe_on_cpu(void *info)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct msr_info_completion *rv = info;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	rv->msr.err = rdmsr_safe(rv->msr.msr_no, &rv->msr.reg.l, &rv->msr.reg.h);
1598c2ecf20Sopenharmony_ci	complete(&rv->done);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic void __wrmsr_safe_on_cpu(void *info)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct msr_info *rv = info;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ciint rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct msr_info_completion rv;
1728c2ecf20Sopenharmony_ci	call_single_data_t csd = {
1738c2ecf20Sopenharmony_ci		.func	= __rdmsr_safe_on_cpu,
1748c2ecf20Sopenharmony_ci		.info	= &rv,
1758c2ecf20Sopenharmony_ci	};
1768c2ecf20Sopenharmony_ci	int err;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
1798c2ecf20Sopenharmony_ci	init_completion(&rv.done);
1808c2ecf20Sopenharmony_ci	rv.msr.msr_no = msr_no;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	err = smp_call_function_single_async(cpu, &csd);
1838c2ecf20Sopenharmony_ci	if (!err) {
1848c2ecf20Sopenharmony_ci		wait_for_completion(&rv.done);
1858c2ecf20Sopenharmony_ci		err = rv.msr.err;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci	*l = rv.msr.reg.l;
1888c2ecf20Sopenharmony_ci	*h = rv.msr.reg.h;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	return err;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdmsr_safe_on_cpu);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciint wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	int err;
1978c2ecf20Sopenharmony_ci	struct msr_info rv;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
2028c2ecf20Sopenharmony_ci	rv.reg.l = l;
2038c2ecf20Sopenharmony_ci	rv.reg.h = h;
2048c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return err ? err : rv.err;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wrmsr_safe_on_cpu);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciint wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	int err;
2138c2ecf20Sopenharmony_ci	struct msr_info rv;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	rv.msr_no = msr_no;
2188c2ecf20Sopenharmony_ci	rv.reg.q = q;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return err ? err : rv.err;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wrmsrl_safe_on_cpu);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ciint rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	u32 low, high;
2298c2ecf20Sopenharmony_ci	int err;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	err = rdmsr_safe_on_cpu(cpu, msr_no, &low, &high);
2328c2ecf20Sopenharmony_ci	*q = (u64)high << 32 | low;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return err;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdmsrl_safe_on_cpu);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/*
2398c2ecf20Sopenharmony_ci * These variants are significantly slower, but allows control over
2408c2ecf20Sopenharmony_ci * the entire 32-bit GPR set.
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_cistatic void __rdmsr_safe_regs_on_cpu(void *info)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct msr_regs_info *rv = info;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	rv->err = rdmsr_safe_regs(rv->regs);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic void __wrmsr_safe_regs_on_cpu(void *info)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct msr_regs_info *rv = info;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	rv->err = wrmsr_safe_regs(rv->regs);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciint rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	int err;
2598c2ecf20Sopenharmony_ci	struct msr_regs_info rv;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	rv.regs   = regs;
2628c2ecf20Sopenharmony_ci	rv.err    = -EIO;
2638c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return err ? err : rv.err;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rdmsr_safe_regs_on_cpu);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ciint wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	int err;
2728c2ecf20Sopenharmony_ci	struct msr_regs_info rv;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	rv.regs = regs;
2758c2ecf20Sopenharmony_ci	rv.err  = -EIO;
2768c2ecf20Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return err ? err : rv.err;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wrmsr_safe_regs_on_cpu);
281