Commit | Line | Data |
---|---|---|
b077ffb3 AD |
1 | #include <linux/module.h> |
2 | #include <linux/preempt.h> | |
b077ffb3 AD |
3 | #include <asm/msr.h> |
4 | ||
50542251 BP |
5 | struct msr *msrs_alloc(void) |
6 | { | |
7 | struct msr *msrs = NULL; | |
8 | ||
9 | msrs = alloc_percpu(struct msr); | |
10 | if (!msrs) { | |
22085a66 | 11 | pr_warn("%s: error allocating msrs\n", __func__); |
50542251 BP |
12 | return NULL; |
13 | } | |
14 | ||
15 | return msrs; | |
16 | } | |
17 | EXPORT_SYMBOL(msrs_alloc); | |
18 | ||
19 | void msrs_free(struct msr *msrs) | |
20 | { | |
21 | free_percpu(msrs); | |
22 | } | |
23 | EXPORT_SYMBOL(msrs_free); | |
22085a66 BP |
24 | |
25 | /** | |
26 | * Read an MSR with error handling | |
27 | * | |
28 | * @msr: MSR to read | |
29 | * @m: value to read into | |
30 | * | |
31 | * It returns read data only on success, otherwise it doesn't change the output | |
32 | * argument @m. | |
33 | * | |
34 | */ | |
35 | int msr_read(u32 msr, struct msr *m) | |
36 | { | |
37 | int err; | |
38 | u64 val; | |
39 | ||
40 | err = rdmsrl_safe(msr, &val); | |
41 | if (!err) | |
42 | m->q = val; | |
43 | ||
44 | return err; | |
45 | } | |
46 | ||
47 | /** | |
48 | * Write an MSR with error handling | |
49 | * | |
50 | * @msr: MSR to write | |
51 | * @m: value to write | |
52 | */ | |
53 | int msr_write(u32 msr, struct msr *m) | |
54 | { | |
55 | return wrmsrl_safe(msr, m->q); | |
56 | } | |
57 | ||
58 | static inline int __flip_bit(u32 msr, u8 bit, bool set) | |
59 | { | |
60 | struct msr m, m1; | |
61 | int err = -EINVAL; | |
62 | ||
63 | if (bit > 63) | |
64 | return err; | |
65 | ||
66 | err = msr_read(msr, &m); | |
67 | if (err) | |
68 | return err; | |
69 | ||
70 | m1 = m; | |
71 | if (set) | |
72 | m1.q |= BIT_64(bit); | |
73 | else | |
74 | m1.q &= ~BIT_64(bit); | |
75 | ||
76 | if (m1.q == m.q) | |
77 | return 0; | |
78 | ||
722a0d22 | 79 | err = msr_write(msr, &m1); |
22085a66 BP |
80 | if (err) |
81 | return err; | |
82 | ||
83 | return 1; | |
84 | } | |
85 | ||
86 | /** | |
87 | * Set @bit in a MSR @msr. | |
88 | * | |
89 | * Retval: | |
90 | * < 0: An error was encountered. | |
91 | * = 0: Bit was already set. | |
92 | * > 0: Hardware accepted the MSR write. | |
93 | */ | |
94 | int msr_set_bit(u32 msr, u8 bit) | |
95 | { | |
96 | return __flip_bit(msr, bit, true); | |
97 | } | |
98 | ||
99 | /** | |
100 | * Clear @bit in a MSR @msr. | |
101 | * | |
102 | * Retval: | |
103 | * < 0: An error was encountered. | |
104 | * = 0: Bit was already cleared. | |
105 | * > 0: Hardware accepted the MSR write. | |
106 | */ | |
107 | int msr_clear_bit(u32 msr, u8 bit) | |
108 | { | |
109 | return __flip_bit(msr, bit, false); | |
110 | } |