2007-02-16 12:48:11 +03:00
# include <linux/module.h>
# include <linux/preempt.h>
# include <linux/smp.h>
# include <asm/msr.h>
struct msr_info {
u32 msr_no ;
2009-05-22 14:12:01 +04:00
struct msr reg ;
2009-05-22 15:52:19 +04:00
struct msr * msrs ;
int off ;
2007-05-08 19:22:01 +04:00
int err ;
2007-02-16 12:48:11 +03:00
} ;
static void __rdmsr_on_cpu ( void * info )
{
struct msr_info * rv = info ;
2009-05-22 15:52:19 +04:00
struct msr * reg ;
int this_cpu = raw_smp_processor_id ( ) ;
2007-02-16 12:48:11 +03:00
2009-05-22 15:52:19 +04:00
if ( rv - > msrs )
reg = & rv - > msrs [ this_cpu - rv - > off ] ;
else
reg = & rv - > reg ;
rdmsr ( rv - > msr_no , reg - > l , reg - > h ) ;
2007-02-16 12:48:11 +03:00
}
2008-08-26 04:44:03 +04:00
static void __wrmsr_on_cpu ( void * info )
2007-02-16 12:48:11 +03:00
{
2007-05-08 19:22:01 +04:00
struct msr_info * rv = info ;
2009-05-22 15:52:19 +04:00
struct msr * reg ;
int this_cpu = raw_smp_processor_id ( ) ;
if ( rv - > msrs )
reg = & rv - > msrs [ this_cpu - rv - > off ] ;
else
reg = & rv - > reg ;
2007-05-08 19:22:01 +04:00
2009-05-22 15:52:19 +04:00
wrmsr ( rv - > msr_no , reg - > l , reg - > h ) ;
2007-05-08 19:22:01 +04:00
}
2008-08-26 04:44:03 +04:00
int rdmsr_on_cpu ( unsigned int cpu , u32 msr_no , u32 * l , u32 * h )
2007-05-08 19:22:01 +04:00
{
2008-08-26 04:44:03 +04:00
int err ;
2007-10-17 20:04:38 +04:00
struct msr_info rv ;
2009-05-22 15:52:19 +04:00
memset ( & rv , 0 , sizeof ( rv ) ) ;
2007-10-17 20:04:38 +04:00
rv . msr_no = msr_no ;
2008-08-26 04:44:03 +04:00
err = smp_call_function_single ( cpu , __rdmsr_on_cpu , & rv , 1 ) ;
2009-05-22 14:12:01 +04:00
* l = rv . reg . l ;
* h = rv . reg . h ;
2007-10-17 20:04:38 +04:00
2007-05-08 19:22:01 +04:00
return err ;
2007-02-16 12:48:11 +03:00
}
2009-05-22 15:52:19 +04:00
EXPORT_SYMBOL ( rdmsr_on_cpu ) ;
2007-02-16 12:48:11 +03:00
2008-08-26 04:44:03 +04:00
int wrmsr_on_cpu ( unsigned int cpu , u32 msr_no , u32 l , u32 h )
{
int err ;
struct msr_info rv ;
2009-05-22 15:52:19 +04:00
memset ( & rv , 0 , sizeof ( rv ) ) ;
2008-08-26 04:44:03 +04:00
rv . msr_no = msr_no ;
2009-05-22 14:12:01 +04:00
rv . reg . l = l ;
rv . reg . h = h ;
2008-08-26 04:44:03 +04:00
err = smp_call_function_single ( cpu , __wrmsr_on_cpu , & rv , 1 ) ;
return err ;
}
2009-05-22 15:52:19 +04:00
EXPORT_SYMBOL ( wrmsr_on_cpu ) ;
/* rdmsr on a bunch of CPUs
*
* @ mask : which CPUs
* @ msr_no : which MSR
* @ msrs : array of MSR values
*
*/
void rdmsr_on_cpus ( const cpumask_t * mask , u32 msr_no , struct msr * msrs )
{
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 ;
2009-07-30 13:10:01 +04:00
this_cpu = get_cpu ( ) ;
if ( cpumask_test_cpu ( this_cpu , mask ) )
__rdmsr_on_cpu ( & rv ) ;
2009-05-22 15:52:19 +04:00
smp_call_function_many ( mask , __rdmsr_on_cpu , & rv , 1 ) ;
2009-07-30 13:10:01 +04:00
put_cpu ( ) ;
2009-05-22 15:52:19 +04:00
}
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 )
{
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 ;
2009-07-30 13:10:01 +04:00
this_cpu = get_cpu ( ) ;
if ( cpumask_test_cpu ( this_cpu , mask ) )
__wrmsr_on_cpu ( & rv ) ;
2009-05-22 15:52:19 +04:00
smp_call_function_many ( mask , __wrmsr_on_cpu , & rv , 1 ) ;
2009-07-30 13:10:01 +04:00
put_cpu ( ) ;
2009-05-22 15:52:19 +04:00
}
EXPORT_SYMBOL ( wrmsr_on_cpus ) ;
2008-08-26 04:44:03 +04:00
/* 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 )
2007-02-16 12:48:11 +03:00
{
struct msr_info * rv = info ;
2009-05-22 14:12:01 +04:00
rv - > err = rdmsr_safe ( rv - > msr_no , & rv - > reg . l , & rv - > reg . h ) ;
2007-02-16 12:48:11 +03:00
}
2007-05-08 19:22:01 +04:00
static void __wrmsr_safe_on_cpu ( void * info )
2007-02-16 12:48:11 +03:00
{
2007-05-08 19:22:01 +04:00
struct msr_info * rv = info ;
2009-05-22 14:12:01 +04:00
rv - > err = wrmsr_safe ( rv - > msr_no , rv - > reg . l , rv - > reg . h ) ;
2007-05-08 19:22:01 +04:00
}
2008-08-26 04:44:03 +04:00
int rdmsr_safe_on_cpu ( unsigned int cpu , u32 msr_no , u32 * l , u32 * h )
2007-05-08 19:22:01 +04:00
{
2008-08-26 04:44:03 +04:00
int err ;
2007-10-17 20:04:38 +04:00
struct msr_info rv ;
2009-05-22 15:52:19 +04:00
memset ( & rv , 0 , sizeof ( rv ) ) ;
2007-10-17 20:04:38 +04:00
rv . msr_no = msr_no ;
2008-08-26 04:44:03 +04:00
err = smp_call_function_single ( cpu , __rdmsr_safe_on_cpu , & rv , 1 ) ;
2009-05-22 14:12:01 +04:00
* l = rv . reg . l ;
* h = rv . reg . h ;
2007-05-08 19:22:01 +04:00
2008-08-26 04:44:03 +04:00
return err ? err : rv . err ;
2007-05-08 19:22:01 +04:00
}
2009-05-22 15:52:19 +04:00
EXPORT_SYMBOL ( rdmsr_safe_on_cpu ) ;
2007-05-08 19:22:01 +04:00
int wrmsr_safe_on_cpu ( unsigned int cpu , u32 msr_no , u32 l , u32 h )
{
2008-08-26 04:44:03 +04:00
int err ;
struct msr_info rv ;
2007-05-08 19:22:01 +04:00
2009-05-22 15:52:19 +04:00
memset ( & rv , 0 , sizeof ( rv ) ) ;
2008-08-26 04:44:03 +04:00
rv . msr_no = msr_no ;
2009-05-22 14:12:01 +04:00
rv . reg . l = l ;
rv . reg . h = h ;
2008-08-26 04:44:03 +04:00
err = smp_call_function_single ( cpu , __wrmsr_safe_on_cpu , & rv , 1 ) ;
return err ? err : rv . err ;
2007-02-16 12:48:11 +03:00
}
2007-05-08 19:22:01 +04:00
EXPORT_SYMBOL ( wrmsr_safe_on_cpu ) ;