From: Kan Liang <kan.li...@intel.com> Having msr_set/clear_bit on many cpus or given CPU can avoid extra unnecessory IPIs and simplify MSR content manipulation, when it only needs to flip a bit. There is already msr_set/clear_bit, but missing the _on_cpu and _on_cpus version.
Signed-off-by: Kan Liang <kan.li...@intel.com> --- arch/x86/include/asm/msr.h | 29 ++++++++++++++++++ arch/x86/lib/msr-smp.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 898dba2..9bc999b 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -20,6 +20,11 @@ struct msr { }; }; +struct msr_bit_info { + u32 msr_no; + u8 bit; +}; + struct msr_info { u32 msr_no; struct msr reg; @@ -314,6 +319,10 @@ int msr_set_bit(u32 msr, u8 bit); int msr_clear_bit(u32 msr, u8 bit); #ifdef CONFIG_SMP +int msr_set_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit); +int msr_clear_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit); +void msr_set_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit); +void msr_clear_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit); int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q); @@ -327,6 +336,26 @@ int wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q); int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); #else /* CONFIG_SMP */ +static inline int msr_set_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit) +{ + return msr_set_bit(msr, bit); +} + +static inline int msr_clear_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit) +{ + return msr_clear_bit(msr, bit); +} + +static inline void msr_set_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit) +{ + msr_set_bit(msr, bit); +} + +static inline void msr_clear_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit) +{ + msr_clear_bit(msr, bit); +} + static inline int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) { rdmsr(msr_no, *l, *h); diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c index ce68b6a..100b3cb 100644 --- a/arch/x86/lib/msr-smp.c +++ b/arch/x86/lib/msr-smp.c @@ -3,6 +3,82 @@ #include <linux/smp.h> #include <asm/msr.h> +static void __msr_set_bit_on_cpu(void *info) +{ + struct msr_bit_info *bit_info = info; + + msr_set_bit(bit_info->msr_no, bit_info->bit); +} + +static void __msr_clear_bit_on_cpu(void *info) +{ + struct msr_bit_info *bit_info = info; + + msr_clear_bit(bit_info->msr_no, bit_info->bit); +} + +int msr_set_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit) +{ + struct msr_bit_info info; + int err; + + info.msr_no = msr; + info.bit = bit; + + err = smp_call_function_single(cpu, __msr_set_bit_on_cpu, &info, 1); + + return err; +} +EXPORT_SYMBOL(msr_set_bit_on_cpu); + +int msr_clear_bit_on_cpu(unsigned int cpu, u32 msr, u8 bit) +{ + struct msr_bit_info info; + int err; + + info.msr_no = msr; + info.bit = bit; + + err = smp_call_function_single(cpu, __msr_clear_bit_on_cpu, &info, 1); + + return err; +} +EXPORT_SYMBOL(msr_clear_bit_on_cpu); + +void msr_set_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit) +{ + struct msr_bit_info info; + int this_cpu; + + info.msr_no = msr; + info.bit = bit; + + this_cpu = get_cpu(); + if (cpumask_test_cpu(this_cpu, mask)) + __msr_set_bit_on_cpu(&info); + + smp_call_function_many(mask, __msr_set_bit_on_cpu, &info, 1); + put_cpu(); +} +EXPORT_SYMBOL(msr_set_bit_on_cpus); + +void msr_clear_bit_on_cpus(const struct cpumask *mask, u32 msr, u8 bit) +{ + struct msr_bit_info info; + int this_cpu; + + info.msr_no = msr; + info.bit = bit; + + this_cpu = get_cpu(); + if (cpumask_test_cpu(this_cpu, mask)) + __msr_clear_bit_on_cpu(&info); + + smp_call_function_many(mask, __msr_clear_bit_on_cpu, &info, 1); + put_cpu(); +} +EXPORT_SYMBOL(msr_clear_bit_on_cpus); + static void __rdmsr_on_cpu(void *info) { struct msr_info *rv = info; -- 2.7.4