diff options
Diffstat (limited to 'arch/x86/lib/msr.c')
| -rw-r--r-- | arch/x86/lib/msr.c | 256 |
1 files changed, 70 insertions, 186 deletions
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index 33a1e3ca22d..43623739c7c 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c @@ -1,226 +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; - - rdmsr(rv->msr_no, reg->l, reg->h); -} - -static void __wrmsr_on_cpu(void *info) -{ - 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; + msrs = alloc_percpu(struct msr); + if (!msrs) { + pr_warn("%s: error allocating msrs\n", __func__); + return NULL; + } - wrmsr(rv->msr_no, reg->l, reg->h); -} - -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; + return msrs; } -EXPORT_SYMBOL(rdmsr_on_cpu); +EXPORT_SYMBOL(msrs_alloc); -int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +void msrs_free(struct msr *msrs) { - 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_on_cpu, &rv, 1); - - return err; + free_percpu(msrs); } -EXPORT_SYMBOL(wrmsr_on_cpu); +EXPORT_SYMBOL(msrs_free); -/* rdmsr on a bunch of CPUs +/** + * Read an MSR with error handling * - * @mask: which CPUs - * @msr_no: which MSR - * @msrs: array of MSR values + * @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. * */ -void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) +int msr_read(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; - - this_cpu = get_cpu(); + int err; + u64 val; - if (cpumask_test_cpu(this_cpu, mask)) - __rdmsr_on_cpu(&rv); + err = rdmsrl_safe(msr, &val); + if (!err) + m->q = val; - smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1); - put_cpu(); + return err; } -EXPORT_SYMBOL(rdmsr_on_cpus); -/* - * wrmsr 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 wrmsr_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; - - this_cpu = get_cpu(); - - if (cpumask_test_cpu(this_cpu, mask)) - __wrmsr_on_cpu(&rv); - - smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1); - put_cpu(); + return wrmsrl_safe(msr, m->q); } -EXPORT_SYMBOL(wrmsr_on_cpus); -/* 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) +static inline int __flip_bit(u32 msr, u8 bit, bool set) { - struct msr_info *rv = info; + struct msr m, m1; + int err = -EINVAL; - rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); -} - -static void __wrmsr_safe_on_cpu(void *info) -{ - struct msr_info *rv = info; - - rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h); -} - -int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -{ - int err; - struct msr_info rv; - - memset(&rv, 0, sizeof(rv)); + if (bit > 63) + return err; - 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; + err = msr_read(msr, &m); + if (err) + return err; - return err ? err : rv.err; -} -EXPORT_SYMBOL(rdmsr_safe_on_cpu); - -int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) -{ - int err; - struct msr_info rv; + m1 = m; + if (set) + m1.q |= BIT_64(bit); + else + m1.q &= ~BIT_64(bit); - memset(&rv, 0, sizeof(rv)); + if (m1.q == m.q) + return 0; - 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); + err = msr_write(msr, &m1); + if (err) + return err; - return err ? err : rv.err; + return 1; } -EXPORT_SYMBOL(wrmsr_safe_on_cpu); -/* - * These variants are significantly slower, but allows control over - * the entire 32-bit GPR set. +/** + * Set @bit in a MSR @msr. + * + * Retval: + * < 0: An error was encountered. + * = 0: Bit was already set. + * > 0: Hardware accepted the MSR write. */ -struct msr_regs_info { - u32 *regs; - int err; -}; - -static void __rdmsr_safe_regs_on_cpu(void *info) +int msr_set_bit(u32 msr, u8 bit) { - struct msr_regs_info *rv = info; - - rv->err = rdmsr_safe_regs(rv->regs); -} - -static void __wrmsr_safe_regs_on_cpu(void *info) -{ - struct msr_regs_info *rv = info; - - rv->err = wrmsr_safe_regs(rv->regs); -} - -int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) -{ - int err; - struct msr_regs_info rv; - - rv.regs = regs; - rv.err = -EIO; - err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1); - - return err ? err : rv.err; + return __flip_bit(msr, bit, true); } -EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu); -int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) +/** + * 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_regs_info rv; - - rv.regs = regs; - rv.err = -EIO; - err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1); - - return err ? err : rv.err; + return __flip_bit(msr, bit, false); } -EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu); |
