1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access
4 * Copyright (c) 2022, Intel Corporation.
5 */
6
7#include <linux/errno.h>
8#include <linux/intel_tcc.h>
9#include <asm/msr.h>
10
11/**
12 * intel_tcc_get_tjmax() - returns the default TCC activation Temperature
13 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
14 *
15 * Get the TjMax value, which is the default thermal throttling or TCC
16 * activation temperature in degrees C.
17 *
18 * Return: Tjmax value in degrees C on success, negative error code otherwise.
19 */
20int intel_tcc_get_tjmax(int cpu)
21{
22 u32 low, high;
23 int val, err;
24
25 if (cpu < 0)
26 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
27 else
28 err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: &low, h: &high);
29 if (err)
30 return err;
31
32 val = (low >> 16) & 0xff;
33
34 return val ? val : -ENODATA;
35}
36EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC);
37
38/**
39 * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
40 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
41 *
42 * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
43 * activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
44 *
45 * Return: Tcc offset value in degrees C on success, negative error code otherwise.
46 */
47int intel_tcc_get_offset(int cpu)
48{
49 u32 low, high;
50 int err;
51
52 if (cpu < 0)
53 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
54 else
55 err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: &low, h: &high);
56 if (err)
57 return err;
58
59 return (low >> 24) & 0x3f;
60}
61EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC);
62
63/**
64 * intel_tcc_set_offset() - set the TCC offset value to Tjmax
65 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
66 * @offset: TCC offset value in degree C
67 *
68 * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
69 * activation temperature equals "Tjmax" - "TCC Offset", in degree C.
70 *
71 * Return: On success returns 0, negative error code otherwise.
72 */
73
74int intel_tcc_set_offset(int cpu, int offset)
75{
76 u32 low, high;
77 int err;
78
79 if (offset < 0 || offset > 0x3f)
80 return -EINVAL;
81
82 if (cpu < 0)
83 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
84 else
85 err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: &low, h: &high);
86 if (err)
87 return err;
88
89 /* MSR Locked */
90 if (low & BIT(31))
91 return -EPERM;
92
93 low &= ~(0x3f << 24);
94 low |= offset << 24;
95
96 if (cpu < 0)
97 return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high);
98 else
99 return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, l: low, h: high);
100}
101EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC);
102
103/**
104 * intel_tcc_get_temp() - returns the current temperature
105 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
106 * @temp: pointer to the memory for saving cpu temperature.
107 * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
108 *
109 * Get the current temperature returned by the CPU core/package level
110 * thermal sensor, in degrees C.
111 *
112 * Return: 0 on success, negative error code otherwise.
113 */
114int intel_tcc_get_temp(int cpu, int *temp, bool pkg)
115{
116 u32 low, high;
117 u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
118 int tjmax, err;
119
120 tjmax = intel_tcc_get_tjmax(cpu);
121 if (tjmax < 0)
122 return tjmax;
123
124 if (cpu < 0)
125 err = rdmsr_safe(msr, &low, &high);
126 else
127 err = rdmsr_safe_on_cpu(cpu, msr_no: msr, l: &low, h: &high);
128 if (err)
129 return err;
130
131 /* Temperature is beyond the valid thermal sensor range */
132 if (!(low & BIT(31)))
133 return -ENODATA;
134
135 *temp = tjmax - ((low >> 16) & 0x7f);
136
137 return 0;
138}
139EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC);
140

source code of linux/drivers/thermal/intel/intel_tcc.c