Loading...
Note: File does not exist in v3.1.
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#define TCC_LOCKED BIT(31)
18
19static struct thermal_cooling_device *tcc_cdev;
20
21static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
22 *state)
23{
24 *state = TCC_MASK >> TCC_SHIFT;
25 return 0;
26}
27
28static int tcc_offset_update(int tcc)
29{
30 u64 val;
31 int err;
32
33 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
34 if (err)
35 return err;
36
37 val &= ~TCC_MASK;
38 val |= tcc << TCC_SHIFT;
39
40 err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
41 if (err)
42 return err;
43
44 return 0;
45}
46
47static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
48 *state)
49{
50 u64 val;
51 int err;
52
53 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
54 if (err)
55 return err;
56
57 *state = (val & TCC_MASK) >> TCC_SHIFT;
58 return 0;
59}
60
61static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
62 state)
63{
64 return tcc_offset_update(state);
65}
66
67static const struct thermal_cooling_device_ops tcc_cooling_ops = {
68 .get_max_state = tcc_get_max_state,
69 .get_cur_state = tcc_get_cur_state,
70 .set_cur_state = tcc_set_cur_state,
71};
72
73static const struct x86_cpu_id tcc_ids[] __initconst = {
74 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
75 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
76 X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
77 X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
78 X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
79 X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
80 X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
81 X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
82 X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
83 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
84 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
85 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
86 X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
87 X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
88 X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, NULL),
89 {}
90};
91
92MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
93
94static int __init tcc_cooling_init(void)
95{
96 int ret;
97 u64 val;
98 const struct x86_cpu_id *id;
99
100 int err;
101
102 id = x86_match_cpu(tcc_ids);
103 if (!id)
104 return -ENODEV;
105
106 err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
107 if (err)
108 return err;
109
110 if (!(val & TCC_PROGRAMMABLE))
111 return -ENODEV;
112
113 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
114 if (err)
115 return err;
116
117 if (val & TCC_LOCKED) {
118 pr_info("TCC Offset locked\n");
119 return -ENODEV;
120 }
121
122 pr_info("Programmable TCC Offset detected\n");
123
124 tcc_cdev =
125 thermal_cooling_device_register("TCC Offset", NULL,
126 &tcc_cooling_ops);
127 if (IS_ERR(tcc_cdev)) {
128 ret = PTR_ERR(tcc_cdev);
129 return ret;
130 }
131 return 0;
132}
133
134module_init(tcc_cooling_init)
135
136static void __exit tcc_cooling_exit(void)
137{
138 thermal_cooling_device_unregister(tcc_cdev);
139}
140
141module_exit(tcc_cooling_exit)
142
143MODULE_DESCRIPTION("TCC offset cooling device Driver");
144MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
145MODULE_LICENSE("GPL v2");