Linux Audio

Check our new training course

Embedded Linux training

Mar 31-Apr 8, 2025
Register
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");