0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0008
0009 #include <linux/device.h>
0010 #include <linux/module.h>
0011 #include <linux/thermal.h>
0012 #include <asm/cpu_device_id.h>
0013
0014 #define TCC_SHIFT 24
0015 #define TCC_MASK (0x3fULL<<24)
0016 #define TCC_PROGRAMMABLE BIT(30)
0017
0018 static struct thermal_cooling_device *tcc_cdev;
0019
0020 static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
0021 *state)
0022 {
0023 *state = TCC_MASK >> TCC_SHIFT;
0024 return 0;
0025 }
0026
0027 static int tcc_offset_update(int tcc)
0028 {
0029 u64 val;
0030 int err;
0031
0032 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
0033 if (err)
0034 return err;
0035
0036 val &= ~TCC_MASK;
0037 val |= tcc << TCC_SHIFT;
0038
0039 err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
0040 if (err)
0041 return err;
0042
0043 return 0;
0044 }
0045
0046 static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
0047 *state)
0048 {
0049 u64 val;
0050 int err;
0051
0052 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
0053 if (err)
0054 return err;
0055
0056 *state = (val & TCC_MASK) >> TCC_SHIFT;
0057 return 0;
0058 }
0059
0060 static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
0061 state)
0062 {
0063 return tcc_offset_update(state);
0064 }
0065
0066 static const struct thermal_cooling_device_ops tcc_cooling_ops = {
0067 .get_max_state = tcc_get_max_state,
0068 .get_cur_state = tcc_get_cur_state,
0069 .set_cur_state = tcc_set_cur_state,
0070 };
0071
0072 static const struct x86_cpu_id tcc_ids[] __initconst = {
0073 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
0074 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
0075 X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
0076 X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
0077 X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
0078 X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
0079 X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
0080 X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
0081 X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
0082 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
0083 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
0084 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
0085 X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
0086 X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
0087 {}
0088 };
0089
0090 MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
0091
0092 static int __init tcc_cooling_init(void)
0093 {
0094 int ret;
0095 u64 val;
0096 const struct x86_cpu_id *id;
0097
0098 int err;
0099
0100 id = x86_match_cpu(tcc_ids);
0101 if (!id)
0102 return -ENODEV;
0103
0104 err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
0105 if (err)
0106 return err;
0107
0108 if (!(val & TCC_PROGRAMMABLE))
0109 return -ENODEV;
0110
0111 pr_info("Programmable TCC Offset detected\n");
0112
0113 tcc_cdev =
0114 thermal_cooling_device_register("TCC Offset", NULL,
0115 &tcc_cooling_ops);
0116 if (IS_ERR(tcc_cdev)) {
0117 ret = PTR_ERR(tcc_cdev);
0118 return ret;
0119 }
0120 return 0;
0121 }
0122
0123 module_init(tcc_cooling_init)
0124
0125 static void __exit tcc_cooling_exit(void)
0126 {
0127 thermal_cooling_device_unregister(tcc_cdev);
0128 }
0129
0130 module_exit(tcc_cooling_exit)
0131
0132 MODULE_DESCRIPTION("TCC offset cooling device Driver");
0133 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
0134 MODULE_LICENSE("GPL v2");