xref: /openbmc/linux/arch/x86/lib/msr.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2e683014cSPaul Gortmaker #include <linux/export.h>
3e683014cSPaul Gortmaker #include <linux/percpu.h>
46bc1096dSBorislav Petkov #include <linux/preempt.h>
56bc1096dSBorislav Petkov #include <asm/msr.h>
67f47d8ccSAndi Kleen #define CREATE_TRACE_POINTS
77f47d8ccSAndi Kleen #include <asm/msr-trace.h>
86bc1096dSBorislav Petkov 
msrs_alloc(void)950542251SBorislav Petkov struct msr *msrs_alloc(void)
1050542251SBorislav Petkov {
1150542251SBorislav Petkov 	struct msr *msrs = NULL;
1250542251SBorislav Petkov 
1350542251SBorislav Petkov 	msrs = alloc_percpu(struct msr);
1450542251SBorislav Petkov 	if (!msrs) {
1522085a66SBorislav Petkov 		pr_warn("%s: error allocating msrs\n", __func__);
1650542251SBorislav Petkov 		return NULL;
1750542251SBorislav Petkov 	}
1850542251SBorislav Petkov 
1950542251SBorislav Petkov 	return msrs;
2050542251SBorislav Petkov }
2150542251SBorislav Petkov EXPORT_SYMBOL(msrs_alloc);
2250542251SBorislav Petkov 
msrs_free(struct msr * msrs)2350542251SBorislav Petkov void msrs_free(struct msr *msrs)
2450542251SBorislav Petkov {
2550542251SBorislav Petkov 	free_percpu(msrs);
2650542251SBorislav Petkov }
2750542251SBorislav Petkov EXPORT_SYMBOL(msrs_free);
2822085a66SBorislav Petkov 
2922085a66SBorislav Petkov /**
30*b26d3d05SRandy Dunlap  * msr_read - Read an MSR with error handling
3122085a66SBorislav Petkov  * @msr: MSR to read
3222085a66SBorislav Petkov  * @m: value to read into
3322085a66SBorislav Petkov  *
3422085a66SBorislav Petkov  * It returns read data only on success, otherwise it doesn't change the output
3522085a66SBorislav Petkov  * argument @m.
3622085a66SBorislav Petkov  *
37*b26d3d05SRandy Dunlap  * Return: %0 for success, otherwise an error code
3822085a66SBorislav Petkov  */
msr_read(u32 msr,struct msr * m)393e7bbe15SZhao Xuehui static int msr_read(u32 msr, struct msr *m)
4022085a66SBorislav Petkov {
4122085a66SBorislav Petkov 	int err;
4222085a66SBorislav Petkov 	u64 val;
4322085a66SBorislav Petkov 
4422085a66SBorislav Petkov 	err = rdmsrl_safe(msr, &val);
4522085a66SBorislav Petkov 	if (!err)
4622085a66SBorislav Petkov 		m->q = val;
4722085a66SBorislav Petkov 
4822085a66SBorislav Petkov 	return err;
4922085a66SBorislav Petkov }
5022085a66SBorislav Petkov 
5122085a66SBorislav Petkov /**
52*b26d3d05SRandy Dunlap  * msr_write - Write an MSR with error handling
5322085a66SBorislav Petkov  *
5422085a66SBorislav Petkov  * @msr: MSR to write
5522085a66SBorislav Petkov  * @m: value to write
56*b26d3d05SRandy Dunlap  *
57*b26d3d05SRandy Dunlap  * Return: %0 for success, otherwise an error code
5822085a66SBorislav Petkov  */
msr_write(u32 msr,struct msr * m)593e7bbe15SZhao Xuehui static int msr_write(u32 msr, struct msr *m)
6022085a66SBorislav Petkov {
6122085a66SBorislav Petkov 	return wrmsrl_safe(msr, m->q);
6222085a66SBorislav Petkov }
6322085a66SBorislav Petkov 
__flip_bit(u32 msr,u8 bit,bool set)6422085a66SBorislav Petkov static inline int __flip_bit(u32 msr, u8 bit, bool set)
6522085a66SBorislav Petkov {
6622085a66SBorislav Petkov 	struct msr m, m1;
6722085a66SBorislav Petkov 	int err = -EINVAL;
6822085a66SBorislav Petkov 
6922085a66SBorislav Petkov 	if (bit > 63)
7022085a66SBorislav Petkov 		return err;
7122085a66SBorislav Petkov 
7222085a66SBorislav Petkov 	err = msr_read(msr, &m);
7322085a66SBorislav Petkov 	if (err)
7422085a66SBorislav Petkov 		return err;
7522085a66SBorislav Petkov 
7622085a66SBorislav Petkov 	m1 = m;
7722085a66SBorislav Petkov 	if (set)
7822085a66SBorislav Petkov 		m1.q |=  BIT_64(bit);
7922085a66SBorislav Petkov 	else
8022085a66SBorislav Petkov 		m1.q &= ~BIT_64(bit);
8122085a66SBorislav Petkov 
8222085a66SBorislav Petkov 	if (m1.q == m.q)
8322085a66SBorislav Petkov 		return 0;
8422085a66SBorislav Petkov 
85722a0d22SAndres Freund 	err = msr_write(msr, &m1);
8622085a66SBorislav Petkov 	if (err)
8722085a66SBorislav Petkov 		return err;
8822085a66SBorislav Petkov 
8922085a66SBorislav Petkov 	return 1;
9022085a66SBorislav Petkov }
9122085a66SBorislav Petkov 
9222085a66SBorislav Petkov /**
93*b26d3d05SRandy Dunlap  * msr_set_bit - Set @bit in a MSR @msr.
94*b26d3d05SRandy Dunlap  * @msr: MSR to write
95*b26d3d05SRandy Dunlap  * @bit: bit number to set
9622085a66SBorislav Petkov  *
97*b26d3d05SRandy Dunlap  * Return:
98*b26d3d05SRandy Dunlap  * * < 0: An error was encountered.
99*b26d3d05SRandy Dunlap  * * = 0: Bit was already set.
100*b26d3d05SRandy Dunlap  * * > 0: Hardware accepted the MSR write.
10122085a66SBorislav Petkov  */
msr_set_bit(u32 msr,u8 bit)10222085a66SBorislav Petkov int msr_set_bit(u32 msr, u8 bit)
10322085a66SBorislav Petkov {
10422085a66SBorislav Petkov 	return __flip_bit(msr, bit, true);
10522085a66SBorislav Petkov }
10622085a66SBorislav Petkov 
10722085a66SBorislav Petkov /**
108*b26d3d05SRandy Dunlap  * msr_clear_bit - Clear @bit in a MSR @msr.
109*b26d3d05SRandy Dunlap  * @msr: MSR to write
110*b26d3d05SRandy Dunlap  * @bit: bit number to clear
11122085a66SBorislav Petkov  *
112*b26d3d05SRandy Dunlap  * Return:
113*b26d3d05SRandy Dunlap  * * < 0: An error was encountered.
114*b26d3d05SRandy Dunlap  * * = 0: Bit was already cleared.
115*b26d3d05SRandy Dunlap  * * > 0: Hardware accepted the MSR write.
11622085a66SBorislav Petkov  */
msr_clear_bit(u32 msr,u8 bit)11722085a66SBorislav Petkov int msr_clear_bit(u32 msr, u8 bit)
11822085a66SBorislav Petkov {
11922085a66SBorislav Petkov 	return __flip_bit(msr, bit, false);
12022085a66SBorislav Petkov }
1217f47d8ccSAndi Kleen 
1227f47d8ccSAndi Kleen #ifdef CONFIG_TRACEPOINTS
do_trace_write_msr(unsigned int msr,u64 val,int failed)1235d07c2ccSBorislav Petkov void do_trace_write_msr(unsigned int msr, u64 val, int failed)
1247f47d8ccSAndi Kleen {
1257f47d8ccSAndi Kleen 	trace_write_msr(msr, val, failed);
1267f47d8ccSAndi Kleen }
1277f47d8ccSAndi Kleen EXPORT_SYMBOL(do_trace_write_msr);
1287f47d8ccSAndi Kleen EXPORT_TRACEPOINT_SYMBOL(write_msr);
1297f47d8ccSAndi Kleen 
do_trace_read_msr(unsigned int msr,u64 val,int failed)1305d07c2ccSBorislav Petkov void do_trace_read_msr(unsigned int msr, u64 val, int failed)
1317f47d8ccSAndi Kleen {
1327f47d8ccSAndi Kleen 	trace_read_msr(msr, val, failed);
1337f47d8ccSAndi Kleen }
1347f47d8ccSAndi Kleen EXPORT_SYMBOL(do_trace_read_msr);
1357f47d8ccSAndi Kleen EXPORT_TRACEPOINT_SYMBOL(read_msr);
1367f47d8ccSAndi Kleen 
do_trace_rdpmc(unsigned counter,u64 val,int failed)1377f47d8ccSAndi Kleen void do_trace_rdpmc(unsigned counter, u64 val, int failed)
1387f47d8ccSAndi Kleen {
1397f47d8ccSAndi Kleen 	trace_rdpmc(counter, val, failed);
1407f47d8ccSAndi Kleen }
1417f47d8ccSAndi Kleen EXPORT_SYMBOL(do_trace_rdpmc);
1427f47d8ccSAndi Kleen EXPORT_TRACEPOINT_SYMBOL(rdpmc);
1437f47d8ccSAndi Kleen 
1447f47d8ccSAndi Kleen #endif
145