| 
									
										
										
										
											2007-02-16 01:48:11 -08:00
										 |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/preempt.h>
 | 
					
						
							|  |  |  | #include <asm/msr.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 18:14:40 +01:00
										 |  |  | struct msr *msrs_alloc(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct msr *msrs = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	msrs = alloc_percpu(struct msr); | 
					
						
							|  |  |  | 	if (!msrs) { | 
					
						
							| 
									
										
										
										
											2014-03-09 18:05:23 +01:00
										 |  |  | 		pr_warn("%s: error allocating msrs\n", __func__); | 
					
						
							| 
									
										
										
										
											2009-12-11 18:14:40 +01:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return msrs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(msrs_alloc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void msrs_free(struct msr *msrs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free_percpu(msrs); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(msrs_free); | 
					
						
							| 
									
										
										
										
											2014-03-09 18:05:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * 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; | 
					
						
							|  |  |  | 	u64 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = rdmsrl_safe(msr, &val); | 
					
						
							|  |  |  | 	if (!err) | 
					
						
							|  |  |  | 		m->q = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Write an MSR with error handling | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @msr: MSR to write | 
					
						
							|  |  |  |  * @m: value to write | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int msr_write(u32 msr, struct msr *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return wrmsrl_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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-09 03:29:16 +02:00
										 |  |  | 	err = msr_write(msr, &m1); | 
					
						
							| 
									
										
										
										
											2014-03-09 18:05:23 +01:00
										 |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * 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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return __flip_bit(msr, bit, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * 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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return __flip_bit(msr, bit, false); | 
					
						
							|  |  |  | } |