// SPDX-License-Identifier: GPL-2.0 #include <linux/syscore_ops.h> #include <linux/suspend.h> #include <linux/cpu.h> #include <asm/msr.h> #include <asm/mwait.h> #define UMWAIT_C02_ENABLE … #define UMWAIT_CTRL_VAL(max_time, c02_disable) … /* * Cache IA32_UMWAIT_CONTROL MSR. This is a systemwide control. By default, * umwait max time is 100000 in TSC-quanta and C0.2 is enabled */ static u32 umwait_control_cached = …; /* * Cache the original IA32_UMWAIT_CONTROL MSR value which is configured by * hardware or BIOS before kernel boot. */ static u32 orig_umwait_control_cached __ro_after_init; /* * Serialize access to umwait_control_cached and IA32_UMWAIT_CONTROL MSR in * the sysfs write functions. */ static DEFINE_MUTEX(umwait_lock); static void umwait_update_control_msr(void * unused) { … } /* * The CPU hotplug callback sets the control MSR to the global control * value. * * Disable interrupts so the read of umwait_control_cached and the WRMSR * are protected against a concurrent sysfs write. Otherwise the sysfs * write could update the cached value after it had been read on this CPU * and issue the IPI before the old value had been written. The IPI would * interrupt, write the new value and after return from IPI the previous * value would be written by this CPU. * * With interrupts disabled the upcoming CPU either sees the new control * value or the IPI is updating this CPU to the new control value after * interrupts have been reenabled. */ static int umwait_cpu_online(unsigned int cpu) { … } /* * The CPU hotplug callback sets the control MSR to the original control * value. */ static int umwait_cpu_offline(unsigned int cpu) { … } /* * On resume, restore IA32_UMWAIT_CONTROL MSR on the boot processor which * is the only active CPU at this time. The MSR is set up on the APs via the * CPU hotplug callback. * * This function is invoked on resume from suspend and hibernation. On * resume from suspend the restore should be not required, but we neither * trust the firmware nor does it matter if the same value is written * again. */ static void umwait_syscore_resume(void) { … } static struct syscore_ops umwait_syscore_ops = …; /* sysfs interface */ /* * When bit 0 in IA32_UMWAIT_CONTROL MSR is 1, C0.2 is disabled. * Otherwise, C0.2 is enabled. */ static inline bool umwait_ctrl_c02_enabled(u32 ctrl) { … } static inline u32 umwait_ctrl_max_time(u32 ctrl) { … } static inline void umwait_update_control(u32 maxtime, bool c02_enable) { … } static ssize_t enable_c02_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static ssize_t enable_c02_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { … } static DEVICE_ATTR_RW(enable_c02); static ssize_t max_time_show(struct device *kobj, struct device_attribute *attr, char *buf) { … } static ssize_t max_time_store(struct device *kobj, struct device_attribute *attr, const char *buf, size_t count) { … } static DEVICE_ATTR_RW(max_time); static struct attribute *umwait_attrs[] = …; static struct attribute_group umwait_attr_group = …; static int __init umwait_init(void) { … } device_initcall(umwait_init);