diff options
Diffstat (limited to 'arch/x86/lib/msr.c')
| -rw-r--r-- | arch/x86/lib/msr.c | 217 |
1 files changed, 72 insertions, 145 deletions
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index 1440b9c0547..43623739c7c 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c @@ -1,183 +1,110 @@ #include <linux/module.h> #include <linux/preempt.h> -#include <linux/smp.h> #include <asm/msr.h> -struct msr_info { - u32 msr_no; - struct msr reg; - struct msr *msrs; - int off; - int err; -}; - -static void __rdmsr_on_cpu(void *info) +struct msr *msrs_alloc(void) { - struct msr_info *rv = info; - struct msr *reg; - int this_cpu = raw_smp_processor_id(); + struct msr *msrs = NULL; - if (rv->msrs) - reg = &rv->msrs[this_cpu - rv->off]; - else - reg = &rv->reg; + msrs = alloc_percpu(struct msr); + if (!msrs) { + pr_warn("%s: error allocating msrs\n", __func__); + return NULL; + } - rdmsr(rv->msr_no, reg->l, reg->h); + return msrs; } +EXPORT_SYMBOL(msrs_alloc); -static void __wrmsr_on_cpu(void *info) +void msrs_free(struct msr *msrs) { - struct msr_info *rv = info; - struct msr *reg; - int this_cpu = raw_smp_processor_id(); - - if (rv->msrs) - reg = &rv->msrs[this_cpu - rv->off]; - else - reg = &rv->reg; - - wrmsr(rv->msr_no, reg->l, reg->h); + free_percpu(msrs); } +EXPORT_SYMBOL(msrs_free); -int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -{ - int err; - struct msr_info rv; - - memset(&rv, 0, sizeof(rv)); - - rv.msr_no = msr_no; - err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); - *l = rv.reg.l; - *h = rv.reg.h; - - return err; -} -EXPORT_SYMBOL(rdmsr_on_cpu); - -int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +/** + * Read an MSR with error handling + * + * @msr: MSR to read + * @m: value to read into + * + * It returns read data only on success, otherwise it doesn't change the output + * argument @m. + * + */ +int msr_read(u32 msr, struct msr *m) { int err; - struct msr_info rv; + u64 val; - memset(&rv, 0, sizeof(rv)); - - rv.msr_no = msr_no; - rv.reg.l = l; - rv.reg.h = h; - err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); + err = rdmsrl_safe(msr, &val); + if (!err) + m->q = val; return err; } -EXPORT_SYMBOL(wrmsr_on_cpu); -/* rdmsr on a bunch of CPUs - * - * @mask: which CPUs - * @msr_no: which MSR - * @msrs: array of MSR values +/** + * Write an MSR with error handling * + * @msr: MSR to write + * @m: value to write */ -void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) +int msr_write(u32 msr, struct msr *m) { - struct msr_info rv; - int this_cpu; - - memset(&rv, 0, sizeof(rv)); - - rv.off = cpumask_first(mask); - rv.msrs = msrs; - rv.msr_no = msr_no; - - preempt_disable(); - /* - * FIXME: handle the CPU we're executing on separately for now until - * smp_call_function_many has been fixed to not skip it. - */ - this_cpu = raw_smp_processor_id(); - smp_call_function_single(this_cpu, __rdmsr_on_cpu, &rv, 1); - - smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1); - preempt_enable(); + return wrmsrl_safe(msr, m->q); } -EXPORT_SYMBOL(rdmsr_on_cpus); -/* - * wrmsr on a bunch of CPUs - * - * @mask: which CPUs - * @msr_no: which MSR - * @msrs: array of MSR values - * - */ -void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) +static inline int __flip_bit(u32 msr, u8 bit, bool set) { - struct msr_info rv; - int this_cpu; - - memset(&rv, 0, sizeof(rv)); - - rv.off = cpumask_first(mask); - rv.msrs = msrs; - rv.msr_no = msr_no; + struct msr m, m1; + int err = -EINVAL; - preempt_disable(); - /* - * FIXME: handle the CPU we're executing on separately for now until - * smp_call_function_many has been fixed to not skip it. - */ - this_cpu = raw_smp_processor_id(); - smp_call_function_single(this_cpu, __wrmsr_on_cpu, &rv, 1); + if (bit > 63) + return err; - smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1); - preempt_enable(); -} -EXPORT_SYMBOL(wrmsr_on_cpus); + err = msr_read(msr, &m); + if (err) + return err; -/* These "safe" variants are slower and should be used when the target MSR - may not actually exist. */ -static void __rdmsr_safe_on_cpu(void *info) -{ - struct msr_info *rv = info; + m1 = m; + if (set) + m1.q |= BIT_64(bit); + else + m1.q &= ~BIT_64(bit); - rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); -} + if (m1.q == m.q) + return 0; -static void __wrmsr_safe_on_cpu(void *info) -{ - struct msr_info *rv = info; + err = msr_write(msr, &m1); + if (err) + return err; - rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h); + return 1; } -int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) +/** + * Set @bit in a MSR @msr. + * + * Retval: + * < 0: An error was encountered. + * = 0: Bit was already set. + * > 0: Hardware accepted the MSR write. + */ +int msr_set_bit(u32 msr, u8 bit) { - int err; - struct msr_info rv; - - memset(&rv, 0, sizeof(rv)); - - rv.msr_no = msr_no; - err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); - *l = rv.reg.l; - *h = rv.reg.h; - - return err ? err : rv.err; + return __flip_bit(msr, bit, true); } -EXPORT_SYMBOL(rdmsr_safe_on_cpu); -int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +/** + * Clear @bit in a MSR @msr. + * + * Retval: + * < 0: An error was encountered. + * = 0: Bit was already cleared. + * > 0: Hardware accepted the MSR write. + */ +int msr_clear_bit(u32 msr, u8 bit) { - int err; - struct msr_info rv; - - memset(&rv, 0, sizeof(rv)); - - rv.msr_no = msr_no; - rv.reg.l = l; - rv.reg.h = h; - err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); - - return err ? err : rv.err; + return __flip_bit(msr, bit, false); } -EXPORT_SYMBOL(wrmsr_safe_on_cpu); |
