Skip to content

Commit e3e6612

Browse files
committed
Merge branch 'thermal-intel'
Intel int340x thermal driver changes for 6.18: - Add support for new "power slider" firmware interface to the int340x thermal driver end enable it for Panther Lake platforms (Srinivas Pandruvada) - Remove a redundant ACPI control method evaluation from the int340x thermal driver (Salah Triki) and clean it up. * thermal-intel: thermal: intel: selftests: workload_hint: Mask unsupported types thermal: intel: int340x: Add module parameter to change slider offset thermal: intel: int340x: Add module parameter for balanced Slider thermal: intel: int340x: Enable power slider interface for Panther Lake thermal: intel: int340x: Add support for power slider thermal: intel: int340x: Remove redundant acpi_has_method() call
2 parents 5136380 + 0115d06 commit e3e6612

8 files changed

Lines changed: 315 additions & 4 deletions

File tree

drivers/thermal/intel/int340x_thermal/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ config INT340X_THERMAL
1212
select ACPI_THERMAL_LIB
1313
select INTEL_SOC_DTS_IOSF_CORE
1414
select INTEL_TCC
15+
select ACPI_PLATFORM_PROFILE
1516
select PROC_THERMAL_MMIO_RAPL if POWERCAP
1617
help
1718
Newer laptops and tablets that use ACPI may have thermal sensors and

drivers/thermal/intel/int340x_thermal/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
1414
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_req.o
1515
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o
1616
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_power_floor.o
17+
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_soc_slider.o
1718
obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o
1819
obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o

drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,6 @@ static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **ps
220220
int i, result = 0;
221221
struct psvt *psvts;
222222

223-
if (!acpi_has_method(handle, "PSVT"))
224-
return -ENODEV;
225-
226223
status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer);
227224
if (ACPI_FAILURE(status))
228225
return -ENODEV;

drivers/thermal/intel/int340x_thermal/processor_thermal_device.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,17 @@ static int tcc_offset_save = -1;
338338

339339
int proc_thermal_suspend(struct device *dev)
340340
{
341+
struct proc_thermal_device *proc_dev;
342+
341343
tcc_offset_save = intel_tcc_get_offset(-1);
342344
if (tcc_offset_save < 0)
343345
dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save);
344346

347+
proc_dev = dev_get_drvdata(dev);
348+
349+
if (proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER)
350+
proc_thermal_soc_power_slider_suspend(proc_dev);
351+
345352
return 0;
346353
}
347354
EXPORT_SYMBOL_GPL(proc_thermal_suspend);
@@ -357,6 +364,9 @@ int proc_thermal_resume(struct device *dev)
357364
if (tcc_offset_save >= 0)
358365
intel_tcc_set_offset(-1, tcc_offset_save);
359366

367+
if (proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER)
368+
proc_thermal_soc_power_slider_resume(proc_dev);
369+
360370
return 0;
361371
}
362372
EXPORT_SYMBOL_GPL(proc_thermal_resume);
@@ -432,8 +442,18 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
432442
}
433443
}
434444

445+
if (feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) {
446+
ret = proc_thermal_soc_power_slider_add(pdev, proc_priv);
447+
if (ret) {
448+
dev_info(&pdev->dev, "failed to add soc power efficiency slider\n");
449+
goto err_rem_wlt;
450+
}
451+
}
452+
435453
return 0;
436454

455+
err_rem_wlt:
456+
proc_thermal_wt_hint_remove(pdev);
437457
err_rem_rfim:
438458
proc_thermal_rfim_remove(pdev);
439459
err_rem_ptc:

drivers/thermal/intel/int340x_thermal/processor_thermal_device.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ struct rapl_mmio_regs {
6969
#define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40
7070
#define PROC_THERMAL_FEATURE_MSI_SUPPORT 0x80
7171
#define PROC_THERMAL_FEATURE_PTC 0x100
72+
#define PROC_THERMAL_FEATURE_SOC_POWER_SLIDER 0x200
7273

7374
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
7475
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -127,4 +128,9 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
127128
void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
128129
int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
129130
void proc_thermal_ptc_remove(struct pci_dev *pdev);
131+
132+
int proc_thermal_soc_power_slider_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
133+
void proc_thermal_soc_power_slider_suspend(struct proc_thermal_device *proc_priv);
134+
void proc_thermal_soc_power_slider_resume(struct proc_thermal_device *proc_priv);
135+
130136
#endif

drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
498498
{ PCI_DEVICE_DATA(INTEL, PTL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
499499
PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
500500
PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT |
501-
PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) },
501+
PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC |
502+
PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) },
502503
{ PCI_DEVICE_DATA(INTEL, WCL_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
503504
PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR |
504505
PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_HINT |
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Processor Thermal Device Interface for Reading and Writing
4+
* SoC Power Slider Values from User Space.
5+
*
6+
* Operation:
7+
* The SOC_EFFICIENCY_SLIDER_0_0_0_MCHBAR register is accessed
8+
* using the MMIO (Memory-Mapped I/O) interface with an MMIO offset of 0x5B38.
9+
* Although this register is 64 bits wide, only bits 7:0 are used,
10+
* and the other bits remain unchanged.
11+
*
12+
* Bit definitions
13+
*
14+
* Bits 2:0 (Slider value):
15+
* The SoC optimizer slider value indicates the system wide energy performance
16+
* hint. The slider has no specific units and ranges from 0 (highest
17+
* performance) to 6 (highest energy efficiency). Value of 7 is reserved.
18+
* Bits 3 : Reserved
19+
* Bits 6:4 (Offset)
20+
* Offset allows the SoC to automatically switch slider position in range
21+
* [slider value (bits 2:0) + offset] to improve power efficiency based on
22+
* internal SoC algorithms.
23+
* Bit 7 (Enable):
24+
* If this bit is set, the SoC Optimization sliders will be processed by the
25+
* SoC firmware.
26+
*
27+
* Copyright (c) 2025, Intel Corporation.
28+
*/
29+
30+
#include <linux/bitfield.h>
31+
#include <linux/pci.h>
32+
#include <linux/platform_profile.h>
33+
#include "processor_thermal_device.h"
34+
35+
#define SOC_POWER_SLIDER_OFFSET 0x5B38
36+
37+
enum power_slider_preference {
38+
SOC_POWER_SLIDER_PERFORMANCE,
39+
SOC_POWER_SLIDER_BALANCE,
40+
SOC_POWER_SLIDER_POWERSAVE,
41+
};
42+
43+
#define SOC_SLIDER_VALUE_MINIMUM 0x00
44+
#define SOC_SLIDER_VALUE_BALANCE 0x03
45+
#define SOC_SLIDER_VALUE_MAXIMUM 0x06
46+
47+
#define SLIDER_MASK GENMASK_ULL(2, 0)
48+
#define SLIDER_ENABLE_BIT 7
49+
50+
static u8 slider_values[] = {
51+
[SOC_POWER_SLIDER_PERFORMANCE] = SOC_SLIDER_VALUE_MINIMUM,
52+
[SOC_POWER_SLIDER_BALANCE] = SOC_SLIDER_VALUE_BALANCE,
53+
[SOC_POWER_SLIDER_POWERSAVE] = SOC_SLIDER_VALUE_MAXIMUM,
54+
};
55+
56+
/* Lock to protect module param updates */
57+
static DEFINE_MUTEX(slider_param_lock);
58+
59+
static int slider_balanced_param = SOC_SLIDER_VALUE_BALANCE;
60+
61+
static int slider_def_balance_set(const char *arg, const struct kernel_param *kp)
62+
{
63+
u8 slider_val;
64+
int ret;
65+
66+
guard(mutex)(&slider_param_lock);
67+
68+
ret = kstrtou8(arg, 16, &slider_val);
69+
if (!ret) {
70+
if (slider_val > SOC_SLIDER_VALUE_MAXIMUM)
71+
return -EINVAL;
72+
73+
slider_balanced_param = slider_val;
74+
}
75+
76+
return ret;
77+
}
78+
79+
static int slider_def_balance_get(char *buf, const struct kernel_param *kp)
80+
{
81+
guard(mutex)(&slider_param_lock);
82+
return sysfs_emit(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]);
83+
}
84+
85+
static const struct kernel_param_ops slider_def_balance_ops = {
86+
.set = slider_def_balance_set,
87+
.get = slider_def_balance_get,
88+
};
89+
90+
module_param_cb(slider_balance, &slider_def_balance_ops, NULL, 0644);
91+
MODULE_PARM_DESC(slider_balance, "Set slider default value for balance");
92+
93+
static u8 slider_offset;
94+
95+
static int slider_def_offset_set(const char *arg, const struct kernel_param *kp)
96+
{
97+
u8 offset;
98+
int ret;
99+
100+
guard(mutex)(&slider_param_lock);
101+
102+
ret = kstrtou8(arg, 16, &offset);
103+
if (!ret) {
104+
if (offset > SOC_SLIDER_VALUE_MAXIMUM)
105+
return -EINVAL;
106+
107+
slider_offset = offset;
108+
}
109+
110+
return ret;
111+
}
112+
113+
static int slider_def_offset_get(char *buf, const struct kernel_param *kp)
114+
{
115+
guard(mutex)(&slider_param_lock);
116+
return sysfs_emit(buf, "%02x\n", slider_offset);
117+
}
118+
119+
static const struct kernel_param_ops slider_offset_ops = {
120+
.set = slider_def_offset_set,
121+
.get = slider_def_offset_get,
122+
};
123+
124+
/*
125+
* To enhance power efficiency dynamically, the firmware can optionally
126+
* auto-adjust the slider value based on the current workload. This
127+
* adjustment is controlled by the "slider_offset" module parameter.
128+
* This offset permits the firmware to increase the slider value
129+
* up to and including "SoC slider + slider offset,".
130+
*/
131+
module_param_cb(slider_offset, &slider_offset_ops, NULL, 0644);
132+
MODULE_PARM_DESC(slider_offset, "Set slider offset");
133+
134+
/* Convert from platform power profile option to SoC slider value */
135+
static int convert_profile_to_power_slider(enum platform_profile_option profile)
136+
{
137+
switch (profile) {
138+
case PLATFORM_PROFILE_LOW_POWER:
139+
return slider_values[SOC_POWER_SLIDER_POWERSAVE];
140+
case PLATFORM_PROFILE_BALANCED:
141+
return slider_values[SOC_POWER_SLIDER_BALANCE];
142+
case PLATFORM_PROFILE_PERFORMANCE:
143+
return slider_values[SOC_POWER_SLIDER_PERFORMANCE];
144+
default:
145+
break;
146+
}
147+
148+
return -EOPNOTSUPP;
149+
}
150+
151+
/* Convert to platform power profile option from SoC slider values */
152+
static int convert_power_slider_to_profile(u8 slider)
153+
{
154+
if (slider == slider_values[SOC_POWER_SLIDER_PERFORMANCE])
155+
return PLATFORM_PROFILE_PERFORMANCE;
156+
if (slider == slider_values[SOC_POWER_SLIDER_BALANCE])
157+
return PLATFORM_PROFILE_BALANCED;
158+
if (slider == slider_values[SOC_POWER_SLIDER_POWERSAVE])
159+
return PLATFORM_PROFILE_LOW_POWER;
160+
161+
return -EOPNOTSUPP;
162+
}
163+
164+
static inline u64 read_soc_slider(struct proc_thermal_device *proc_priv)
165+
{
166+
return readq(proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET);
167+
}
168+
169+
static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 val)
170+
{
171+
writeq(val, proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET);
172+
}
173+
174+
#define SLIDER_OFFSET_MASK GENMASK_ULL(6, 4)
175+
176+
static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider)
177+
{
178+
u64 val;
179+
180+
val = read_soc_slider(proc_priv);
181+
val &= ~SLIDER_MASK;
182+
val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT);
183+
184+
/* Set the slider offset from module params */
185+
val &= ~SLIDER_OFFSET_MASK;
186+
val |= FIELD_PREP(SLIDER_OFFSET_MASK, slider_offset);
187+
188+
write_soc_slider(proc_priv, val);
189+
}
190+
191+
/* profile get/set callbacks are called with a profile lock, so no need for local locks */
192+
193+
static int power_slider_platform_profile_set(struct device *dev,
194+
enum platform_profile_option profile)
195+
{
196+
struct proc_thermal_device *proc_priv;
197+
int slider;
198+
199+
proc_priv = dev_get_drvdata(dev);
200+
if (!proc_priv)
201+
return -EOPNOTSUPP;
202+
203+
guard(mutex)(&slider_param_lock);
204+
205+
slider_values[SOC_POWER_SLIDER_BALANCE] = slider_balanced_param;
206+
207+
slider = convert_profile_to_power_slider(profile);
208+
if (slider < 0)
209+
return slider;
210+
211+
set_soc_power_profile(proc_priv, slider);
212+
213+
return 0;
214+
}
215+
216+
static int power_slider_platform_profile_get(struct device *dev,
217+
enum platform_profile_option *profile)
218+
{
219+
struct proc_thermal_device *proc_priv;
220+
int slider, ret;
221+
u64 val;
222+
223+
proc_priv = dev_get_drvdata(dev);
224+
if (!proc_priv)
225+
return -EOPNOTSUPP;
226+
227+
val = read_soc_slider(proc_priv);
228+
slider = FIELD_GET(SLIDER_MASK, val);
229+
230+
ret = convert_power_slider_to_profile(slider);
231+
if (ret < 0)
232+
return ret;
233+
234+
*profile = ret;
235+
236+
return 0;
237+
}
238+
239+
static int power_slider_platform_profile_probe(void *drvdata, unsigned long *choices)
240+
{
241+
set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
242+
set_bit(PLATFORM_PROFILE_BALANCED, choices);
243+
set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
244+
245+
return 0;
246+
}
247+
248+
static const struct platform_profile_ops power_slider_platform_profile_ops = {
249+
.probe = power_slider_platform_profile_probe,
250+
.profile_get = power_slider_platform_profile_get,
251+
.profile_set = power_slider_platform_profile_set,
252+
};
253+
254+
int proc_thermal_soc_power_slider_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
255+
{
256+
struct device *ppdev;
257+
258+
set_soc_power_profile(proc_priv, slider_values[SOC_POWER_SLIDER_BALANCE]);
259+
260+
ppdev = devm_platform_profile_register(&pdev->dev, "SoC Power Slider", proc_priv,
261+
&power_slider_platform_profile_ops);
262+
263+
return PTR_ERR_OR_ZERO(ppdev);
264+
}
265+
EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_add, "INT340X_THERMAL");
266+
267+
static u64 soc_slider_save;
268+
269+
void proc_thermal_soc_power_slider_suspend(struct proc_thermal_device *proc_priv)
270+
{
271+
soc_slider_save = read_soc_slider(proc_priv);
272+
}
273+
EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_suspend, "INT340X_THERMAL");
274+
275+
void proc_thermal_soc_power_slider_resume(struct proc_thermal_device *proc_priv)
276+
{
277+
write_soc_slider(proc_priv, soc_slider_save);
278+
}
279+
EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_resume, "INT340X_THERMAL");
280+
281+
MODULE_IMPORT_NS("INT340X_THERMAL");
282+
MODULE_LICENSE("GPL");
283+
MODULE_DESCRIPTION("Processor Thermal Power Slider Interface");

tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ int main(int argc, char **argv)
144144
ret = sscanf(index_str, "%d", &index);
145145
if (ret < 0)
146146
break;
147+
148+
index &= 0x0f;
147149
if (index > WORKLOAD_TYPE_MAX_INDEX)
148150
printf("Invalid workload type index\n");
149151
else

0 commit comments

Comments
 (0)