162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/export.h>
362306a36Sopenharmony_ci#include <linux/preempt.h>
462306a36Sopenharmony_ci#include <linux/smp.h>
562306a36Sopenharmony_ci#include <linux/completion.h>
662306a36Sopenharmony_ci#include <asm/msr.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistatic void __rdmsr_on_cpu(void *info)
962306a36Sopenharmony_ci{
1062306a36Sopenharmony_ci	struct msr_info *rv = info;
1162306a36Sopenharmony_ci	struct msr *reg;
1262306a36Sopenharmony_ci	int this_cpu = raw_smp_processor_id();
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	if (rv->msrs)
1562306a36Sopenharmony_ci		reg = per_cpu_ptr(rv->msrs, this_cpu);
1662306a36Sopenharmony_ci	else
1762306a36Sopenharmony_ci		reg = &rv->reg;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	rdmsr(rv->msr_no, reg->l, reg->h);
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic void __wrmsr_on_cpu(void *info)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct msr_info *rv = info;
2562306a36Sopenharmony_ci	struct msr *reg;
2662306a36Sopenharmony_ci	int this_cpu = raw_smp_processor_id();
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (rv->msrs)
2962306a36Sopenharmony_ci		reg = per_cpu_ptr(rv->msrs, this_cpu);
3062306a36Sopenharmony_ci	else
3162306a36Sopenharmony_ci		reg = &rv->reg;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	wrmsr(rv->msr_no, reg->l, reg->h);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciint rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	int err;
3962306a36Sopenharmony_ci	struct msr_info rv;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	rv.msr_no = msr_no;
4462306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
4562306a36Sopenharmony_ci	*l = rv.reg.l;
4662306a36Sopenharmony_ci	*h = rv.reg.h;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return err;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ciEXPORT_SYMBOL(rdmsr_on_cpu);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	int err;
5562306a36Sopenharmony_ci	struct msr_info rv;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	rv.msr_no = msr_no;
6062306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1);
6162306a36Sopenharmony_ci	*q = rv.reg.q;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return err;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ciEXPORT_SYMBOL(rdmsrl_on_cpu);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciint wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int err;
7062306a36Sopenharmony_ci	struct msr_info rv;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	rv.msr_no = msr_no;
7562306a36Sopenharmony_ci	rv.reg.l = l;
7662306a36Sopenharmony_ci	rv.reg.h = h;
7762306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return err;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ciEXPORT_SYMBOL(wrmsr_on_cpu);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciint wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	int err;
8662306a36Sopenharmony_ci	struct msr_info rv;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	rv.msr_no = msr_no;
9162306a36Sopenharmony_ci	rv.reg.q = q;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return err;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ciEXPORT_SYMBOL(wrmsrl_on_cpu);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
10062306a36Sopenharmony_ci			    struct msr *msrs,
10162306a36Sopenharmony_ci			    void (*msr_func) (void *info))
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct msr_info rv;
10462306a36Sopenharmony_ci	int this_cpu;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	rv.msrs	  = msrs;
10962306a36Sopenharmony_ci	rv.msr_no = msr_no;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	this_cpu = get_cpu();
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (cpumask_test_cpu(this_cpu, mask))
11462306a36Sopenharmony_ci		msr_func(&rv);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	smp_call_function_many(mask, msr_func, &rv, 1);
11762306a36Sopenharmony_ci	put_cpu();
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* rdmsr on a bunch of CPUs
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * @mask:       which CPUs
12362306a36Sopenharmony_ci * @msr_no:     which MSR
12462306a36Sopenharmony_ci * @msrs:       array of MSR values
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_civoid rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	__rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ciEXPORT_SYMBOL(rdmsr_on_cpus);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * wrmsr on a bunch of CPUs
13562306a36Sopenharmony_ci *
13662306a36Sopenharmony_ci * @mask:       which CPUs
13762306a36Sopenharmony_ci * @msr_no:     which MSR
13862306a36Sopenharmony_ci * @msrs:       array of MSR values
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_civoid wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	__rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ciEXPORT_SYMBOL(wrmsr_on_cpus);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct msr_info_completion {
14862306a36Sopenharmony_ci	struct msr_info		msr;
14962306a36Sopenharmony_ci	struct completion	done;
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* These "safe" variants are slower and should be used when the target MSR
15362306a36Sopenharmony_ci   may not actually exist. */
15462306a36Sopenharmony_cistatic void __rdmsr_safe_on_cpu(void *info)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct msr_info_completion *rv = info;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	rv->msr.err = rdmsr_safe(rv->msr.msr_no, &rv->msr.reg.l, &rv->msr.reg.h);
15962306a36Sopenharmony_ci	complete(&rv->done);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void __wrmsr_safe_on_cpu(void *info)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct msr_info *rv = info;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ciint rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct msr_info_completion rv;
17262306a36Sopenharmony_ci	call_single_data_t csd;
17362306a36Sopenharmony_ci	int err;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	INIT_CSD(&csd, __rdmsr_safe_on_cpu, &rv);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
17862306a36Sopenharmony_ci	init_completion(&rv.done);
17962306a36Sopenharmony_ci	rv.msr.msr_no = msr_no;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	err = smp_call_function_single_async(cpu, &csd);
18262306a36Sopenharmony_ci	if (!err) {
18362306a36Sopenharmony_ci		wait_for_completion(&rv.done);
18462306a36Sopenharmony_ci		err = rv.msr.err;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci	*l = rv.msr.reg.l;
18762306a36Sopenharmony_ci	*h = rv.msr.reg.h;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return err;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ciEXPORT_SYMBOL(rdmsr_safe_on_cpu);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ciint wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	int err;
19662306a36Sopenharmony_ci	struct msr_info rv;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	rv.msr_no = msr_no;
20162306a36Sopenharmony_ci	rv.reg.l = l;
20262306a36Sopenharmony_ci	rv.reg.h = h;
20362306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return err ? err : rv.err;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ciEXPORT_SYMBOL(wrmsr_safe_on_cpu);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciint wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int err;
21262306a36Sopenharmony_ci	struct msr_info rv;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	memset(&rv, 0, sizeof(rv));
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	rv.msr_no = msr_no;
21762306a36Sopenharmony_ci	rv.reg.q = q;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return err ? err : rv.err;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ciEXPORT_SYMBOL(wrmsrl_safe_on_cpu);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciint rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	u32 low, high;
22862306a36Sopenharmony_ci	int err;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	err = rdmsr_safe_on_cpu(cpu, msr_no, &low, &high);
23162306a36Sopenharmony_ci	*q = (u64)high << 32 | low;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return err;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ciEXPORT_SYMBOL(rdmsrl_safe_on_cpu);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/*
23862306a36Sopenharmony_ci * These variants are significantly slower, but allows control over
23962306a36Sopenharmony_ci * the entire 32-bit GPR set.
24062306a36Sopenharmony_ci */
24162306a36Sopenharmony_cistatic void __rdmsr_safe_regs_on_cpu(void *info)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct msr_regs_info *rv = info;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	rv->err = rdmsr_safe_regs(rv->regs);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void __wrmsr_safe_regs_on_cpu(void *info)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct msr_regs_info *rv = info;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	rv->err = wrmsr_safe_regs(rv->regs);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ciint rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	int err;
25862306a36Sopenharmony_ci	struct msr_regs_info rv;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	rv.regs   = regs;
26162306a36Sopenharmony_ci	rv.err    = -EIO;
26262306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return err ? err : rv.err;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ciEXPORT_SYMBOL(rdmsr_safe_regs_on_cpu);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ciint wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	int err;
27162306a36Sopenharmony_ci	struct msr_regs_info rv;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	rv.regs = regs;
27462306a36Sopenharmony_ci	rv.err  = -EIO;
27562306a36Sopenharmony_ci	err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return err ? err : rv.err;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ciEXPORT_SYMBOL(wrmsr_safe_regs_on_cpu);
280