summaryrefslogtreecommitdiffstats
path: root/drivers/thermal/intel/intel_tcc.c
blob: 5e8b7f34b39510a28f2c253e585b0eec54397450 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// SPDX-License-Identifier: GPL-2.0-only
/*
 * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access
 * Copyright (c) 2022, Intel Corporation.
 */

#include <linux/errno.h>
#include <linux/intel_tcc.h>
#include <asm/msr.h>

/**
 * intel_tcc_get_tjmax() - returns the default TCC activation Temperature
 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
 *
 * Get the TjMax value, which is the default thermal throttling or TCC
 * activation temperature in degrees C.
 *
 * Return: Tjmax value in degrees C on success, negative error code otherwise.
 */
int intel_tcc_get_tjmax(int cpu)
{
	u32 low, high;
	int val, err;

	if (cpu < 0)
		err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
	else
		err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
	if (err)
		return err;

	val = (low >> 16) & 0xff;

	return val ? val : -ENODATA;
}
EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC);

/**
 * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
 *
 * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
 * activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
 *
 * Return: Tcc offset value in degrees C on success, negative error code otherwise.
 */
int intel_tcc_get_offset(int cpu)
{
	u32 low, high;
	int err;

	if (cpu < 0)
		err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
	else
		err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
	if (err)
		return err;

	return (low >> 24) & 0x3f;
}
EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC);

/**
 * intel_tcc_set_offset() - set the TCC offset value to Tjmax
 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
 * @offset: TCC offset value in degree C
 *
 * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
 * activation temperature equals "Tjmax" - "TCC Offset", in degree C.
 *
 * Return: On success returns 0, negative error code otherwise.
 */

int intel_tcc_set_offset(int cpu, int offset)
{
	u32 low, high;
	int err;

	if (offset < 0 || offset > 0x3f)
		return -EINVAL;

	if (cpu < 0)
		err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
	else
		err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
	if (err)
		return err;

	/* MSR Locked */
	if (low & BIT(31))
		return -EPERM;

	low &= ~(0x3f << 24);
	low |= offset << 24;

	if (cpu < 0)
		return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high);
	else
		return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high);
}
EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC);

/**
 * intel_tcc_get_temp() - returns the current temperature
 * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
 * @temp: pointer to the memory for saving cpu temperature.
 * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
 *
 * Get the current temperature returned by the CPU core/package level
 * thermal sensor, in degrees C.
 *
 * Return: 0 on success, negative error code otherwise.
 */
int intel_tcc_get_temp(int cpu, int *temp, bool pkg)
{
	u32 low, high;
	u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
	int tjmax, err;

	tjmax = intel_tcc_get_tjmax(cpu);
	if (tjmax < 0)
		return tjmax;

	if (cpu < 0)
		err = rdmsr_safe(msr, &low, &high);
	else
		err = rdmsr_safe_on_cpu(cpu, msr, &low, &high);
	if (err)
		return err;

	/* Temperature is beyond the valid thermal sensor range */
	if (!(low & BIT(31)))
		return -ENODATA;

	*temp = tjmax - ((low >> 16) & 0x7f);

	return 0;
}
EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC);