]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
thermal: int340x: processor_thermal: Enable slow workload type hints
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Thu, 18 Dec 2025 22:25:58 +0000 (14:25 -0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 7 Jan 2026 20:42:10 +0000 (21:42 +0100)
On processors starting from Panther Lake, additional workload type hints
are provided.

The hardware analyzes workload residencies over an extended period to
determine whether the workload classification tends toward idle/battery
life states or sustained/performance states. Based on this long-term
analysis, it classifies:

 Power Classification: If the workload exhibits more idle or battery
  life residencies, it is classified as "power". This is indicated by
  setting bit 4 of the current workload type.

 Performance Classification: If the workload exhibits more sustained
  or performance residencies, it is classified as "performance". This
  is indicated by clearing bit 4 of the current workload type.

This approach enables applications to ignore short-term workload
fluctuations and instead respond to longer-term power vs. performance
trends. Hints of this type are called slow workload hints.

To get notifications for slow workload hints, bit 22 in the thermal
mailbox can be used for configuring workload interrupts. It is possible
to exclusively enable slow workload hints or enable them in addition to
the current workload hints.

To enable slow workload hints, a new sysfs attribute is added to the
existing workload hint attributes:

 workload_slow_hint_enable (RW): Write 1 to enable, 0 to disable.

Reading this attribute shows the current state.

This attribute is not present on any previous generation of processors.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
[ rjw: Dropped redundant local variables, changelog edits ]
Link: https://patch.msgid.link/20251218222559.4110027-2-srinivas.pandruvada@linux.intel.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Documentation/driver-api/thermal/intel_dptf.rst
drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c

index 916bf0f36a03668d92c39ae470f6a7efd41f5a39..4adfa1eb74dbf6730cdc608903fb6af86f08a486 100644 (file)
@@ -375,6 +375,9 @@ based on the processor generation.
 ``workload_hint_enable`` (RW)
        Enable firmware to send workload type hints to user space.
 
+``workload_slow_hint_enable`` (RW)
+       Enable firmware to send slow workload type hints to user space.
+
 ``notification_delay_ms`` (RW)
        Minimum delay in milliseconds before firmware will notify OS. This is
        for the rate control of notifications. This delay is between changing
index 68e8391af8f4e1ac34dedb1b9ee0fb1434cebdcf..f8c33e8e5b7a80a4357518bef47bd7696131c0d4 100644 (file)
@@ -34,6 +34,7 @@
 
 #define SOC_WT                         GENMASK_ULL(47, 40)
 
+#define SOC_WT_SLOW_PREDICTION_INT_ENABLE_BIT  22
 #define SOC_WT_PREDICTION_INT_ENABLE_BIT       23
 
 #define SOC_WT_PREDICTION_INT_ACTIVE   BIT(2)
@@ -47,6 +48,7 @@ static u16 notify_delay_ms = 1024;
 
 static DEFINE_MUTEX(wt_lock);
 static u8 wt_enable;
+static u8 wt_slow_enable;
 
 /* Show current predicted workload type index */
 static ssize_t workload_type_index_show(struct device *dev,
@@ -59,7 +61,7 @@ static ssize_t workload_type_index_show(struct device *dev,
        int wt;
 
        mutex_lock(&wt_lock);
-       if (!wt_enable) {
+       if (!wt_enable && !wt_slow_enable) {
                mutex_unlock(&wt_lock);
                return -ENODATA;
        }
@@ -84,9 +86,9 @@ static ssize_t workload_hint_enable_show(struct device *dev,
        return sysfs_emit(buf, "%d\n", wt_enable);
 }
 
-static ssize_t workload_hint_enable_store(struct device *dev,
-                                         struct device_attribute *attr,
-                                         const char *buf, size_t size)
+static ssize_t workload_hint_enable(struct device *dev, u8 enable_bit, u8 *status,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t size)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        u8 mode;
@@ -99,17 +101,17 @@ static ssize_t workload_hint_enable_store(struct device *dev,
 
        if (mode)
                ret = processor_thermal_mbox_interrupt_config(pdev, true,
-                                                             SOC_WT_PREDICTION_INT_ENABLE_BIT,
+                                                             enable_bit,
                                                              notify_delay);
        else
                ret = processor_thermal_mbox_interrupt_config(pdev, false,
-                                                             SOC_WT_PREDICTION_INT_ENABLE_BIT, 0);
+                                                             enable_bit, 0);
 
        if (ret)
                goto ret_enable_store;
 
        ret = size;
-       wt_enable = mode;
+       *status = mode;
 
 ret_enable_store:
        mutex_unlock(&wt_lock);
@@ -117,8 +119,28 @@ ret_enable_store:
        return ret;
 }
 
+static ssize_t workload_hint_enable_store(struct device *dev, struct device_attribute *attr,
+                                         const char *buf, size_t size)
+{
+       return workload_hint_enable(dev, SOC_WT_PREDICTION_INT_ENABLE_BIT, &wt_enable,
+                                   attr, buf, size);
+}
 static DEVICE_ATTR_RW(workload_hint_enable);
 
+static ssize_t workload_slow_hint_enable_show(struct device *dev, struct device_attribute *attr,
+                                              char *buf)
+{
+       return sysfs_emit(buf, "%d\n", wt_slow_enable);
+}
+
+static ssize_t workload_slow_hint_enable_store(struct device *dev, struct device_attribute *attr,
+                                              const char *buf, size_t size)
+{
+       return workload_hint_enable(dev, SOC_WT_SLOW_PREDICTION_INT_ENABLE_BIT, &wt_slow_enable,
+                                   attr, buf, size);
+}
+static DEVICE_ATTR_RW(workload_slow_hint_enable);
+
 static ssize_t notification_delay_ms_show(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
@@ -178,16 +200,35 @@ static ssize_t notification_delay_ms_store(struct device *dev,
 
 static DEVICE_ATTR_RW(notification_delay_ms);
 
+static umode_t workload_hint_attr_visible(struct kobject *kobj, struct attribute *attr, int unused)
+{
+       if (attr != &dev_attr_workload_slow_hint_enable.attr)
+               return attr->mode;
+
+       switch (to_pci_dev(kobj_to_dev(kobj))->device) {
+       case PCI_DEVICE_ID_INTEL_LNLM_THERMAL:
+       case PCI_DEVICE_ID_INTEL_MTLP_THERMAL:
+       case PCI_DEVICE_ID_INTEL_ARL_S_THERMAL:
+               return 0;
+       default:
+               break;
+       }
+
+       return attr->mode;
+}
+
 static struct attribute *workload_hint_attrs[] = {
        &dev_attr_workload_type_index.attr,
        &dev_attr_workload_hint_enable.attr,
+       &dev_attr_workload_slow_hint_enable.attr,
        &dev_attr_notification_delay_ms.attr,
        NULL
 };
 
 static const struct attribute_group workload_hint_attribute_group = {
        .attrs = workload_hint_attrs,
-       .name = "workload_hint"
+       .name = "workload_hint",
+       .is_visible = workload_hint_attr_visible
 };
 
 /*