Skip to content

Commit 8aa4928

Browse files
committed
Merge branch 'thermal-intel'
Merge changes in Intel thermal control drivers for 6.7-rc1: - Add power floor notifications support to the int340x thermal control driver (Srinivas Pandruvada). - Rework updating trip points in the int340x thermal driver so that it does not access thermal zone internals directly (Rafael Wysocki). - Use param_get_byte() instead of param_get_int() as the max_idle module parameter .get() callback in the Intel powerclamp thermal driver to avoid possible out-of-bounds access (David Arcari). - Add workload hints support to the the int340x thermal driver (Srinivas Pandruvada). * thermal-intel: selftests/thermel/intel: Add test to read power floor status thermal: int340x: processor_thermal: Enable power floor support thermal: int340x: processor_thermal: Handle power floor interrupts thermal: int340x: processor_thermal: Support power floor notifications thermal: int340x: processor_thermal: Set feature mask before proc_thermal_add thermal: int340x: processor_thermal: Common function to clear SOC interrupt thermal: int340x: processor_thermal: Move interrupt status MMIO offset to common header thermal: intel: powerclamp: fix mismatch in get function for max_idle thermal: int340x: Use thermal_zone_for_each_trip() thermal: int340x: processor_thermal: Ack all PCI interrupts thermal: int340x: Add ArrowLake-S PCI ID selftests/thermel/intel: Add test to read workload hint thermal: int340x: Handle workload hint interrupts thermal: int340x: processor_thermal: Add workload type hint interface thermal: int340x: Remove PROC_THERMAL_FEATURE_WLT_REQ for Meteor Lake thermal: int340x: processor_thermal: Use non MSI interrupts by default thermal: int340x: processor_thermal: Add interrupt configuration function thermal: int340x: processor_thermal: Move mailbox code to common module
2 parents 598c20f + d4d27e5 commit 8aa4928

17 files changed

+1170
-206
lines changed

Documentation/driver-api/thermal/intel_dptf.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ ABI.
164164
``power_limit_1_tmax_us`` (RO)
165165
Maximum powercap sysfs constraint_1_time_window_us for Intel RAPL
166166

167+
``power_floor_status`` (RO)
168+
When set to 1, the power floor of the system in the current
169+
configuration has been reached. It needs to be reconfigured to allow
170+
power to be reduced any further.
171+
172+
``power_floor_enable`` (RW)
173+
When set to 1, enable reading and notification of the power floor
174+
status. Notifications are triggered for the power_floor_status
175+
attribute value changes.
176+
167177
:file:`/sys/bus/pci/devices/0000\:00\:04.0/`
168178

169179
``tcc_offset_degree_celsius`` (RW)
@@ -315,3 +325,57 @@ DPTF Fan Control
315325
----------------------------------------
316326

317327
Refer to Documentation/admin-guide/acpi/fan_performance_states.rst
328+
329+
Workload Type Hints
330+
----------------------------------------
331+
332+
The firmware in Meteor Lake processor generation is capable of identifying
333+
workload type and passing hints regarding it to the OS. A special sysfs
334+
interface is provided to allow user space to obtain workload type hints from
335+
the firmware and control the rate at which they are provided.
336+
337+
User space can poll attribute "workload_type_index" for the current hint or
338+
can receive a notification whenever the value of this attribute is updated.
339+
340+
file:`/sys/bus/pci/devices/0000:00:04.0/workload_hint/`
341+
Segment 0, bus 0, device 4, function 0 is reserved for the processor thermal
342+
device on all Intel client processors. So, the above path doesn't change
343+
based on the processor generation.
344+
345+
``workload_hint_enable`` (RW)
346+
Enable firmware to send workload type hints to user space.
347+
348+
``notification_delay_ms`` (RW)
349+
Minimum delay in milliseconds before firmware will notify OS. This is
350+
for the rate control of notifications. This delay is between changing
351+
the workload type prediction in the firmware and notifying the OS about
352+
the change. The default delay is 1024 ms. The delay of 0 is invalid.
353+
The delay is rounded up to the nearest power of 2 to simplify firmware
354+
programming of the delay value. The read of notification_delay_ms
355+
attribute shows the effective value used.
356+
357+
``workload_type_index`` (RO)
358+
Predicted workload type index. User space can get notification of
359+
change via existing sysfs attribute change notification mechanism.
360+
361+
The supported index values and their meaning for the Meteor Lake
362+
processor generation are as follows:
363+
364+
0 - Idle: System performs no tasks, power and idle residency are
365+
consistently low for long periods of time.
366+
367+
1 – Battery Life: Power is relatively low, but the processor may
368+
still be actively performing a task, such as video playback for
369+
a long period of time.
370+
371+
2 – Sustained: Power level that is relatively high for a long period
372+
of time, with very few to no periods of idleness, which will
373+
eventually exhaust RAPL Power Limit 1 and 2.
374+
375+
3 – Bursty: Consumes a relatively constant average amount of power, but
376+
periods of relative idleness are interrupted by bursts of
377+
activity. The bursts are relatively short and the periods of
378+
relative idleness between them typically prevent RAPL Power
379+
Limit 1 from being exhausted.
380+
381+
4 – Unknown: Can't classify.

drivers/thermal/intel/int340x_thermal/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o
1010
obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
1111
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o
1212
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
13+
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_req.o
14+
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o
15+
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_power_floor.o
1316
obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o
1417
obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o

drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
6767
.critical = int340x_thermal_critical,
6868
};
6969

70+
static inline void *int_to_trip_priv(int i)
71+
{
72+
return (void *)(long)i;
73+
}
74+
75+
static inline int trip_priv_to_int(const struct thermal_trip *trip)
76+
{
77+
return (long)trip->priv;
78+
}
79+
7080
static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
7181
struct thermal_trip *zone_trips,
7282
int trip_cnt)
@@ -101,6 +111,7 @@ static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
101111
break;
102112

103113
zone_trips[trip_cnt].type = THERMAL_TRIP_ACTIVE;
114+
zone_trips[trip_cnt].priv = int_to_trip_priv(i);
104115
trip_cnt++;
105116
}
106117

@@ -212,45 +223,40 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_zone)
212223
}
213224
EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
214225

215-
void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)
226+
static int int340x_update_one_trip(struct thermal_trip *trip, void *arg)
216227
{
217-
struct acpi_device *zone_adev = int34x_zone->adev;
218-
struct thermal_trip *zone_trips = int34x_zone->trips;
219-
int trip_cnt = int34x_zone->zone->num_trips;
220-
int act_trip_nr = 0;
221-
int i;
222-
223-
mutex_lock(&int34x_zone->zone->lock);
224-
225-
for (i = int34x_zone->aux_trip_nr; i < trip_cnt; i++) {
226-
int temp, err;
227-
228-
switch (zone_trips[i].type) {
229-
case THERMAL_TRIP_CRITICAL:
230-
err = thermal_acpi_critical_trip_temp(zone_adev, &temp);
231-
break;
232-
case THERMAL_TRIP_HOT:
233-
err = thermal_acpi_hot_trip_temp(zone_adev, &temp);
234-
break;
235-
case THERMAL_TRIP_PASSIVE:
236-
err = thermal_acpi_passive_trip_temp(zone_adev, &temp);
237-
break;
238-
case THERMAL_TRIP_ACTIVE:
239-
err = thermal_acpi_active_trip_temp(zone_adev, act_trip_nr++,
240-
&temp);
241-
break;
242-
default:
243-
err = -ENODEV;
244-
}
245-
if (err) {
246-
zone_trips[i].temperature = THERMAL_TEMP_INVALID;
247-
continue;
248-
}
249-
250-
zone_trips[i].temperature = temp;
228+
struct acpi_device *zone_adev = arg;
229+
int temp, err;
230+
231+
switch (trip->type) {
232+
case THERMAL_TRIP_CRITICAL:
233+
err = thermal_acpi_critical_trip_temp(zone_adev, &temp);
234+
break;
235+
case THERMAL_TRIP_HOT:
236+
err = thermal_acpi_hot_trip_temp(zone_adev, &temp);
237+
break;
238+
case THERMAL_TRIP_PASSIVE:
239+
err = thermal_acpi_passive_trip_temp(zone_adev, &temp);
240+
break;
241+
case THERMAL_TRIP_ACTIVE:
242+
err = thermal_acpi_active_trip_temp(zone_adev,
243+
trip_priv_to_int(trip),
244+
&temp);
245+
break;
246+
default:
247+
err = -ENODEV;
251248
}
249+
if (err)
250+
temp = THERMAL_TEMP_INVALID;
252251

253-
mutex_unlock(&int34x_zone->zone->lock);
252+
trip->temperature = temp;
253+
return 0;
254+
}
255+
256+
void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)
257+
{
258+
thermal_zone_for_each_trip(int34x_zone->zone, int340x_update_one_trip,
259+
int34x_zone->adev);
254260
}
255261
EXPORT_SYMBOL_GPL(int340x_thermal_update_trips);
256262

drivers/thermal/intel/int340x_thermal/processor_thermal_device.c

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,48 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
2626
(unsigned long)proc_dev->power_limits[index].suffix * 1000); \
2727
}
2828

29+
static ssize_t power_floor_status_show(struct device *dev,
30+
struct device_attribute *attr,
31+
char *buf)
32+
{
33+
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev);
34+
int ret;
35+
36+
ret = proc_thermal_read_power_floor_status(proc_dev);
37+
38+
return sysfs_emit(buf, "%d\n", ret);
39+
}
40+
41+
static ssize_t power_floor_enable_show(struct device *dev,
42+
struct device_attribute *attr,
43+
char *buf)
44+
{
45+
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev);
46+
bool ret;
47+
48+
ret = proc_thermal_power_floor_get_state(proc_dev);
49+
50+
return sysfs_emit(buf, "%d\n", ret);
51+
}
52+
53+
static ssize_t power_floor_enable_store(struct device *dev,
54+
struct device_attribute *attr,
55+
const char *buf, size_t count)
56+
{
57+
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev);
58+
u8 state;
59+
int ret;
60+
61+
if (kstrtou8(buf, 0, &state))
62+
return -EINVAL;
63+
64+
ret = proc_thermal_power_floor_set_state(proc_dev, !!state);
65+
if (ret)
66+
return ret;
67+
68+
return count;
69+
}
70+
2971
POWER_LIMIT_SHOW(0, min_uw)
3072
POWER_LIMIT_SHOW(0, max_uw)
3173
POWER_LIMIT_SHOW(0, step_uw)
@@ -50,6 +92,9 @@ static DEVICE_ATTR_RO(power_limit_1_step_uw);
5092
static DEVICE_ATTR_RO(power_limit_1_tmin_us);
5193
static DEVICE_ATTR_RO(power_limit_1_tmax_us);
5294

95+
static DEVICE_ATTR_RO(power_floor_status);
96+
static DEVICE_ATTR_RW(power_floor_enable);
97+
5398
static struct attribute *power_limit_attrs[] = {
5499
&dev_attr_power_limit_0_min_uw.attr,
55100
&dev_attr_power_limit_1_min_uw.attr,
@@ -61,12 +106,30 @@ static struct attribute *power_limit_attrs[] = {
61106
&dev_attr_power_limit_1_tmin_us.attr,
62107
&dev_attr_power_limit_0_tmax_us.attr,
63108
&dev_attr_power_limit_1_tmax_us.attr,
109+
&dev_attr_power_floor_status.attr,
110+
&dev_attr_power_floor_enable.attr,
64111
NULL
65112
};
66113

114+
static umode_t power_limit_attr_visible(struct kobject *kobj, struct attribute *attr, int unused)
115+
{
116+
struct device *dev = kobj_to_dev(kobj);
117+
struct proc_thermal_device *proc_dev;
118+
119+
if (attr != &dev_attr_power_floor_status.attr && attr != &dev_attr_power_floor_enable.attr)
120+
return attr->mode;
121+
122+
proc_dev = dev_get_drvdata(dev);
123+
if (!proc_dev || !(proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR))
124+
return 0;
125+
126+
return attr->mode;
127+
}
128+
67129
static const struct attribute_group power_limit_attribute_group = {
68130
.attrs = power_limit_attrs,
69-
.name = "power_limits"
131+
.name = "power_limits",
132+
.is_visible = power_limit_attr_visible,
70133
};
71134

72135
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
@@ -346,12 +409,18 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
346409
}
347410
}
348411

349-
if (feature_mask & PROC_THERMAL_FEATURE_MBOX) {
350-
ret = proc_thermal_mbox_add(pdev, proc_priv);
412+
if (feature_mask & PROC_THERMAL_FEATURE_WT_REQ) {
413+
ret = proc_thermal_wt_req_add(pdev, proc_priv);
351414
if (ret) {
352415
dev_err(&pdev->dev, "failed to add MBOX interface\n");
353416
goto err_rem_rfim;
354417
}
418+
} else if (feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
419+
ret = proc_thermal_wt_hint_add(pdev, proc_priv);
420+
if (ret) {
421+
dev_err(&pdev->dev, "failed to add WT Hint\n");
422+
goto err_rem_rfim;
423+
}
355424
}
356425

357426
return 0;
@@ -374,12 +443,18 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *
374443
proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
375444
proc_thermal_rfim_remove(pdev);
376445

377-
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
378-
proc_thermal_mbox_remove(pdev);
446+
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR)
447+
proc_thermal_power_floor_set_state(proc_priv, false);
448+
449+
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_REQ)
450+
proc_thermal_wt_req_remove(pdev);
451+
else if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT)
452+
proc_thermal_wt_hint_remove(pdev);
379453
}
380454
EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);
381455

382456
MODULE_IMPORT_NS(INTEL_TCC);
457+
MODULE_IMPORT_NS(INT340X_THERMAL);
383458
MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
384459
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
385460
MODULE_LICENSE("GPL v2");

drivers/thermal/intel/int340x_thermal/processor_thermal_device.h

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/intel_rapl.h>
1111

1212
#define PCI_DEVICE_ID_INTEL_ADL_THERMAL 0x461d
13+
#define PCI_DEVICE_ID_INTEL_ARL_S_THERMAL 0xAD03
1314
#define PCI_DEVICE_ID_INTEL_BDW_THERMAL 0x1603
1415
#define PCI_DEVICE_ID_INTEL_BSW_THERMAL 0x22DC
1516

@@ -59,8 +60,10 @@ struct rapl_mmio_regs {
5960
#define PROC_THERMAL_FEATURE_RAPL 0x01
6061
#define PROC_THERMAL_FEATURE_FIVR 0x02
6162
#define PROC_THERMAL_FEATURE_DVFS 0x04
62-
#define PROC_THERMAL_FEATURE_MBOX 0x08
63+
#define PROC_THERMAL_FEATURE_WT_REQ 0x08
6364
#define PROC_THERMAL_FEATURE_DLVR 0x10
65+
#define PROC_THERMAL_FEATURE_WT_HINT 0x20
66+
#define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40
6467

6568
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
6669
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -80,13 +83,37 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
8083
int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
8184
void proc_thermal_rfim_remove(struct pci_dev *pdev);
8285

83-
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
84-
void proc_thermal_mbox_remove(struct pci_dev *pdev);
86+
int proc_thermal_wt_req_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
87+
void proc_thermal_wt_req_remove(struct pci_dev *pdev);
88+
89+
#define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E
90+
#define MBOX_CMD_WORKLOAD_TYPE_WRITE 0x0F
91+
92+
#define MBOX_DATA_BIT_AC_DC 30
93+
#define MBOX_DATA_BIT_VALID 31
94+
95+
#define SOC_WT_RES_INT_STATUS_OFFSET 0x5B18
96+
#define SOC_WT_RES_INT_STATUS_MASK GENMASK_ULL(3, 2)
97+
98+
int proc_thermal_read_power_floor_status(struct proc_thermal_device *proc_priv);
99+
int proc_thermal_power_floor_set_state(struct proc_thermal_device *proc_priv, bool enable);
100+
bool proc_thermal_power_floor_get_state(struct proc_thermal_device *proc_priv);
101+
void proc_thermal_power_floor_intr_callback(struct pci_dev *pdev,
102+
struct proc_thermal_device *proc_priv);
103+
bool proc_thermal_check_power_floor_intr(struct proc_thermal_device *proc_priv);
85104

86105
int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp);
87106
int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data);
107+
int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable, int enable_bit,
108+
int time_window);
88109
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
89110
void proc_thermal_remove(struct proc_thermal_device *proc_priv);
111+
112+
int proc_thermal_wt_hint_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
113+
void proc_thermal_wt_hint_remove(struct pci_dev *pdev);
114+
void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
115+
bool proc_thermal_check_wt_intr(struct proc_thermal_device *proc_priv);
116+
90117
int proc_thermal_suspend(struct device *dev);
91118
int proc_thermal_resume(struct device *dev);
92119
int proc_thermal_mmio_add(struct pci_dev *pdev,

0 commit comments

Comments
 (0)