]> asedeno.scripts.mit.edu Git - linux.git/blob - arch/x86/kernel/cpu/umwait.c
6a204e7336c12211de4de8fcf3ba1477f1d39160
[linux.git] / arch / x86 / kernel / cpu / umwait.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/syscore_ops.h>
3 #include <linux/suspend.h>
4 #include <linux/cpu.h>
5
6 #include <asm/msr.h>
7
8 #define UMWAIT_C02_ENABLE       0
9
10 #define UMWAIT_CTRL_VAL(max_time, c02_disable)                          \
11         (((max_time) & MSR_IA32_UMWAIT_CONTROL_TIME_MASK) |             \
12         ((c02_disable) & MSR_IA32_UMWAIT_CONTROL_C02_DISABLE))
13
14 /*
15  * Cache IA32_UMWAIT_CONTROL MSR. This is a systemwide control. By default,
16  * umwait max time is 100000 in TSC-quanta and C0.2 is enabled
17  */
18 static u32 umwait_control_cached = UMWAIT_CTRL_VAL(100000, UMWAIT_C02_ENABLE);
19
20 /*
21  * Serialize access to umwait_control_cached and IA32_UMWAIT_CONTROL MSR in
22  * the sysfs write functions.
23  */
24 static DEFINE_MUTEX(umwait_lock);
25
26 static void umwait_update_control_msr(void * unused)
27 {
28         lockdep_assert_irqs_disabled();
29         wrmsr(MSR_IA32_UMWAIT_CONTROL, READ_ONCE(umwait_control_cached), 0);
30 }
31
32 /*
33  * The CPU hotplug callback sets the control MSR to the global control
34  * value.
35  *
36  * Disable interrupts so the read of umwait_control_cached and the WRMSR
37  * are protected against a concurrent sysfs write. Otherwise the sysfs
38  * write could update the cached value after it had been read on this CPU
39  * and issue the IPI before the old value had been written. The IPI would
40  * interrupt, write the new value and after return from IPI the previous
41  * value would be written by this CPU.
42  *
43  * With interrupts disabled the upcoming CPU either sees the new control
44  * value or the IPI is updating this CPU to the new control value after
45  * interrupts have been reenabled.
46  */
47 static int umwait_cpu_online(unsigned int cpu)
48 {
49         local_irq_disable();
50         umwait_update_control_msr(NULL);
51         local_irq_enable();
52         return 0;
53 }
54
55 /*
56  * On resume, restore IA32_UMWAIT_CONTROL MSR on the boot processor which
57  * is the only active CPU at this time. The MSR is set up on the APs via the
58  * CPU hotplug callback.
59  *
60  * This function is invoked on resume from suspend and hibernation. On
61  * resume from suspend the restore should be not required, but we neither
62  * trust the firmware nor does it matter if the same value is written
63  * again.
64  */
65 static void umwait_syscore_resume(void)
66 {
67         umwait_update_control_msr(NULL);
68 }
69
70 static struct syscore_ops umwait_syscore_ops = {
71         .resume = umwait_syscore_resume,
72 };
73
74 /* sysfs interface */
75
76 /*
77  * When bit 0 in IA32_UMWAIT_CONTROL MSR is 1, C0.2 is disabled.
78  * Otherwise, C0.2 is enabled.
79  */
80 static inline bool umwait_ctrl_c02_enabled(u32 ctrl)
81 {
82         return !(ctrl & MSR_IA32_UMWAIT_CONTROL_C02_DISABLE);
83 }
84
85 static inline u32 umwait_ctrl_max_time(u32 ctrl)
86 {
87         return ctrl & MSR_IA32_UMWAIT_CONTROL_TIME_MASK;
88 }
89
90 static inline void umwait_update_control(u32 maxtime, bool c02_enable)
91 {
92         u32 ctrl = maxtime & MSR_IA32_UMWAIT_CONTROL_TIME_MASK;
93
94         if (!c02_enable)
95                 ctrl |= MSR_IA32_UMWAIT_CONTROL_C02_DISABLE;
96
97         WRITE_ONCE(umwait_control_cached, ctrl);
98         /* Propagate to all CPUs */
99         on_each_cpu(umwait_update_control_msr, NULL, 1);
100 }
101
102 static ssize_t
103 enable_c02_show(struct device *dev, struct device_attribute *attr, char *buf)
104 {
105         u32 ctrl = READ_ONCE(umwait_control_cached);
106
107         return sprintf(buf, "%d\n", umwait_ctrl_c02_enabled(ctrl));
108 }
109
110 static ssize_t enable_c02_store(struct device *dev,
111                                 struct device_attribute *attr,
112                                 const char *buf, size_t count)
113 {
114         bool c02_enable;
115         u32 ctrl;
116         int ret;
117
118         ret = kstrtobool(buf, &c02_enable);
119         if (ret)
120                 return ret;
121
122         mutex_lock(&umwait_lock);
123
124         ctrl = READ_ONCE(umwait_control_cached);
125         if (c02_enable != umwait_ctrl_c02_enabled(ctrl))
126                 umwait_update_control(ctrl, c02_enable);
127
128         mutex_unlock(&umwait_lock);
129
130         return count;
131 }
132 static DEVICE_ATTR_RW(enable_c02);
133
134 static ssize_t
135 max_time_show(struct device *kobj, struct device_attribute *attr, char *buf)
136 {
137         u32 ctrl = READ_ONCE(umwait_control_cached);
138
139         return sprintf(buf, "%u\n", umwait_ctrl_max_time(ctrl));
140 }
141
142 static ssize_t max_time_store(struct device *kobj,
143                               struct device_attribute *attr,
144                               const char *buf, size_t count)
145 {
146         u32 max_time, ctrl;
147         int ret;
148
149         ret = kstrtou32(buf, 0, &max_time);
150         if (ret)
151                 return ret;
152
153         /* bits[1:0] must be zero */
154         if (max_time & ~MSR_IA32_UMWAIT_CONTROL_TIME_MASK)
155                 return -EINVAL;
156
157         mutex_lock(&umwait_lock);
158
159         ctrl = READ_ONCE(umwait_control_cached);
160         if (max_time != umwait_ctrl_max_time(ctrl))
161                 umwait_update_control(max_time, umwait_ctrl_c02_enabled(ctrl));
162
163         mutex_unlock(&umwait_lock);
164
165         return count;
166 }
167 static DEVICE_ATTR_RW(max_time);
168
169 static struct attribute *umwait_attrs[] = {
170         &dev_attr_enable_c02.attr,
171         &dev_attr_max_time.attr,
172         NULL
173 };
174
175 static struct attribute_group umwait_attr_group = {
176         .attrs = umwait_attrs,
177         .name = "umwait_control",
178 };
179
180 static int __init umwait_init(void)
181 {
182         struct device *dev;
183         int ret;
184
185         if (!boot_cpu_has(X86_FEATURE_WAITPKG))
186                 return -ENODEV;
187
188         ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "umwait:online",
189                                 umwait_cpu_online, NULL);
190
191         register_syscore_ops(&umwait_syscore_ops);
192
193         /*
194          * Add umwait control interface. Ignore failure, so at least the
195          * default values are set up in case the machine manages to boot.
196          */
197         dev = cpu_subsys.dev_root;
198         return sysfs_create_group(&dev->kobj, &umwait_attr_group);
199 }
200 device_initcall(umwait_init);