mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Suggested-by: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Juergen Gross <jgross@suse.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Xin Li <xin@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org>
		
			
				
	
	
		
			146 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
#include <linux/export.h>
 | 
						|
#include <linux/percpu.h>
 | 
						|
#include <linux/preempt.h>
 | 
						|
#include <asm/msr.h>
 | 
						|
#define CREATE_TRACE_POINTS
 | 
						|
#include <asm/msr-trace.h>
 | 
						|
 | 
						|
struct msr __percpu *msrs_alloc(void)
 | 
						|
{
 | 
						|
	struct msr __percpu *msrs = NULL;
 | 
						|
 | 
						|
	msrs = alloc_percpu(struct msr);
 | 
						|
	if (!msrs) {
 | 
						|
		pr_warn("%s: error allocating msrs\n", __func__);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return msrs;
 | 
						|
}
 | 
						|
EXPORT_SYMBOL(msrs_alloc);
 | 
						|
 | 
						|
void msrs_free(struct msr __percpu *msrs)
 | 
						|
{
 | 
						|
	free_percpu(msrs);
 | 
						|
}
 | 
						|
EXPORT_SYMBOL(msrs_free);
 | 
						|
 | 
						|
/**
 | 
						|
 * msr_read - 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.
 | 
						|
 *
 | 
						|
 * Return: %0 for success, otherwise an error code
 | 
						|
 */
 | 
						|
static int msr_read(u32 msr, struct msr *m)
 | 
						|
{
 | 
						|
	int err;
 | 
						|
	u64 val;
 | 
						|
 | 
						|
	err = rdmsrq_safe(msr, &val);
 | 
						|
	if (!err)
 | 
						|
		m->q = val;
 | 
						|
 | 
						|
	return err;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * msr_write - Write an MSR with error handling
 | 
						|
 *
 | 
						|
 * @msr: MSR to write
 | 
						|
 * @m: value to write
 | 
						|
 *
 | 
						|
 * Return: %0 for success, otherwise an error code
 | 
						|
 */
 | 
						|
static int msr_write(u32 msr, struct msr *m)
 | 
						|
{
 | 
						|
	return wrmsrq_safe(msr, m->q);
 | 
						|
}
 | 
						|
 | 
						|
static inline int __flip_bit(u32 msr, u8 bit, bool set)
 | 
						|
{
 | 
						|
	struct msr m, m1;
 | 
						|
	int err = -EINVAL;
 | 
						|
 | 
						|
	if (bit > 63)
 | 
						|
		return err;
 | 
						|
 | 
						|
	err = msr_read(msr, &m);
 | 
						|
	if (err)
 | 
						|
		return err;
 | 
						|
 | 
						|
	m1 = m;
 | 
						|
	if (set)
 | 
						|
		m1.q |=  BIT_64(bit);
 | 
						|
	else
 | 
						|
		m1.q &= ~BIT_64(bit);
 | 
						|
 | 
						|
	if (m1.q == m.q)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	err = msr_write(msr, &m1);
 | 
						|
	if (err)
 | 
						|
		return err;
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * msr_set_bit - Set @bit in a MSR @msr.
 | 
						|
 * @msr: MSR to write
 | 
						|
 * @bit: bit number to set
 | 
						|
 *
 | 
						|
 * Return:
 | 
						|
 * * < 0: An error was encountered.
 | 
						|
 * * = 0: Bit was already set.
 | 
						|
 * * > 0: Hardware accepted the MSR write.
 | 
						|
 */
 | 
						|
int msr_set_bit(u32 msr, u8 bit)
 | 
						|
{
 | 
						|
	return __flip_bit(msr, bit, true);
 | 
						|
}
 | 
						|
EXPORT_SYMBOL_GPL(msr_set_bit);
 | 
						|
 | 
						|
/**
 | 
						|
 * msr_clear_bit - Clear @bit in a MSR @msr.
 | 
						|
 * @msr: MSR to write
 | 
						|
 * @bit: bit number to clear
 | 
						|
 *
 | 
						|
 * Return:
 | 
						|
 * * < 0: An error was encountered.
 | 
						|
 * * = 0: Bit was already cleared.
 | 
						|
 * * > 0: Hardware accepted the MSR write.
 | 
						|
 */
 | 
						|
int msr_clear_bit(u32 msr, u8 bit)
 | 
						|
{
 | 
						|
	return __flip_bit(msr, bit, false);
 | 
						|
}
 | 
						|
EXPORT_SYMBOL_GPL(msr_clear_bit);
 | 
						|
 | 
						|
#ifdef CONFIG_TRACEPOINTS
 | 
						|
void do_trace_write_msr(u32 msr, u64 val, int failed)
 | 
						|
{
 | 
						|
	trace_write_msr(msr, val, failed);
 | 
						|
}
 | 
						|
EXPORT_SYMBOL(do_trace_write_msr);
 | 
						|
EXPORT_TRACEPOINT_SYMBOL(write_msr);
 | 
						|
 | 
						|
void do_trace_read_msr(u32 msr, u64 val, int failed)
 | 
						|
{
 | 
						|
	trace_read_msr(msr, val, failed);
 | 
						|
}
 | 
						|
EXPORT_SYMBOL(do_trace_read_msr);
 | 
						|
EXPORT_TRACEPOINT_SYMBOL(read_msr);
 | 
						|
 | 
						|
void do_trace_rdpmc(u32 msr, u64 val, int failed)
 | 
						|
{
 | 
						|
	trace_rdpmc(msr, val, failed);
 | 
						|
}
 | 
						|
EXPORT_SYMBOL(do_trace_rdpmc);
 | 
						|
EXPORT_TRACEPOINT_SYMBOL(rdpmc);
 | 
						|
 | 
						|
#endif
 |