Merge tag 'char-misc-5.15-rc1-lkdtm' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / thermal / intel / intel_tcc_cooling.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * cooling device driver that activates the processor throttling by
4  * programming the TCC Offset register.
5  * Copyright (c) 2021, Intel Corporation.
6  */
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
9 #include <linux/device.h>
10 #include <linux/module.h>
11 #include <linux/thermal.h>
12 #include <asm/cpu_device_id.h>
13
14 #define TCC_SHIFT 24
15 #define TCC_MASK        (0x3fULL<<24)
16 #define TCC_PROGRAMMABLE        BIT(30)
17
18 static struct thermal_cooling_device *tcc_cdev;
19
20 static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
21                              *state)
22 {
23         *state = TCC_MASK >> TCC_SHIFT;
24         return 0;
25 }
26
27 static int tcc_offset_update(int tcc)
28 {
29         u64 val;
30         int err;
31
32         err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
33         if (err)
34                 return err;
35
36         val &= ~TCC_MASK;
37         val |= tcc << TCC_SHIFT;
38
39         err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
40         if (err)
41                 return err;
42
43         return 0;
44 }
45
46 static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
47                              *state)
48 {
49         u64 val;
50         int err;
51
52         err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
53         if (err)
54                 return err;
55
56         *state = (val & TCC_MASK) >> TCC_SHIFT;
57         return 0;
58 }
59
60 static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
61                              state)
62 {
63         return tcc_offset_update(state);
64 }
65
66 static const struct thermal_cooling_device_ops tcc_cooling_ops = {
67         .get_max_state = tcc_get_max_state,
68         .get_cur_state = tcc_get_cur_state,
69         .set_cur_state = tcc_set_cur_state,
70 };
71
72 static const struct x86_cpu_id tcc_ids[] __initconst = {
73         X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
74         X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
75         X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
76         X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
77         X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
78         X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
79         X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
80         X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
81         X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
82         X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
83         X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
84         {}
85 };
86
87 MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
88
89 static int __init tcc_cooling_init(void)
90 {
91         int ret;
92         u64 val;
93         const struct x86_cpu_id *id;
94
95         int err;
96
97         id = x86_match_cpu(tcc_ids);
98         if (!id)
99                 return -ENODEV;
100
101         err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
102         if (err)
103                 return err;
104
105         if (!(val & TCC_PROGRAMMABLE))
106                 return -ENODEV;
107
108         pr_info("Programmable TCC Offset detected\n");
109
110         tcc_cdev =
111             thermal_cooling_device_register("TCC Offset", NULL,
112                                             &tcc_cooling_ops);
113         if (IS_ERR(tcc_cdev)) {
114                 ret = PTR_ERR(tcc_cdev);
115                 return ret;
116         }
117         return 0;
118 }
119
120 module_init(tcc_cooling_init)
121
122 static void __exit tcc_cooling_exit(void)
123 {
124         thermal_cooling_device_unregister(tcc_cdev);
125 }
126
127 module_exit(tcc_cooling_exit)
128
129 MODULE_DESCRIPTION("TCC offset cooling device Driver");
130 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
131 MODULE_LICENSE("GPL v2");