Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'thermal-intel'

Merge an update of the Intel int340x thermal driver adding Platform
Temperature Control (PTC) support to it (Srinivas Pandruvada).

* thermal-intel:
thermal: int340x: processor_thermal: Platform temperature control documentation
thermal: intel: int340x: Enable platform temperature control
thermal: intel: int340x: Add platform temperature control interface

+285 -3
+21
Documentation/driver-api/thermal/intel_dptf.rst
··· 191 191 User space can specify any one of the available workload type using 192 192 this interface. 193 193 194 + :file:`/sys/bus/pci/devices/0000\:00\:04.0/ptc_0_control` 195 + :file:`/sys/bus/pci/devices/0000\:00\:04.0/ptc_1_control` 196 + :file:`/sys/bus/pci/devices/0000\:00\:04.0/ptc_2_control` 197 + 198 + All these controls needs admin privilege to update. 199 + 200 + ``enable`` (RW) 201 + 1 for enable, 0 for disable. Shows the current enable status of 202 + platform temperature control feature. User space can enable/disable 203 + hardware controls. 204 + 205 + ``temperature_target`` (RW) 206 + Update a new temperature target in milli degree celsius for hardware to 207 + use for the temperature control. 208 + 209 + Given that this is platform temperature control, it is expected that a 210 + single user-level manager owns and manages the controls. If multiple 211 + user-level software applications attempt to write different targets, it 212 + can lead to unexpected behavior. 213 + 214 + 194 215 DPTF Processor thermal RFIM interface 195 216 -------------------------------------------- 196 217
+1
drivers/thermal/intel/int340x_thermal/Makefile
··· 9 9 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o 10 10 obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o 11 11 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o 12 + obj-$(CONFIG_INT340X_THERMAL) += platform_temperature_control.o 12 13 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o 13 14 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_req.o 14 15 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o
+243
drivers/thermal/intel/int340x_thermal/platform_temperature_control.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * processor thermal device platform temperature controls 4 + * Copyright (c) 2025, Intel Corporation. 5 + */ 6 + 7 + /* 8 + * Platform temperature controls hardware interface 9 + * 10 + * The hardware control interface is via MMIO offsets in the processor 11 + * thermal device MMIO space. There are three instances of MMIO registers. 12 + * All registers are 64 bit wide with RW access. 13 + * 14 + * Name: PLATFORM_TEMPERATURE_CONTROL 15 + * Offsets: 0x5B20, 0x5B28, 0x5B30 16 + * 17 + * Bits Description 18 + * 7:0 TARGET_TEMP : Target temperature limit to which the control 19 + * mechanism is regulating. Units: 0.5C. 20 + * 8:8 ENABLE: Read current enable status of the feature or enable 21 + * feature. 22 + * 11:9 GAIN: Sets the aggressiveness of control loop from 0 to 7 23 + * 7 graceful, favors performance at the expense of temperature 24 + * overshoots 25 + * 0 aggressive, favors tight regulation over performance 26 + * 12:12 TEMPERATURE_OVERRIDE_EN 27 + * When set, hardware will use TEMPERATURE_OVERRIDE values instead 28 + * of reading from corresponding sensor. 29 + * 15:13 RESERVED 30 + * 23:16 MIN_PERFORMANCE_LEVEL: Minimum Performance level below which the 31 + * there will be no throttling. 0 - all levels of throttling allowed 32 + * including survivability actions. 255 - no throttling allowed. 33 + * 31:24 TEMPERATURE_OVERRIDE: Allows SW to override the input temperature. 34 + * hardware will use this value instead of the sensor temperature. 35 + * Units: 0.5C. 36 + * 63:32 RESERVED 37 + */ 38 + 39 + #include <linux/kernel.h> 40 + #include <linux/module.h> 41 + #include <linux/pci.h> 42 + #include "processor_thermal_device.h" 43 + 44 + struct mmio_reg { 45 + int bits; 46 + u16 mask; 47 + u16 shift; 48 + u16 units; 49 + }; 50 + 51 + #define MAX_ATTR_GROUP_NAME_LEN 32 52 + #define PTC_MAX_ATTRS 3 53 + 54 + struct ptc_data { 55 + u32 offset; 56 + struct attribute_group ptc_attr_group; 57 + struct attribute *ptc_attrs[PTC_MAX_ATTRS]; 58 + struct device_attribute temperature_target_attr; 59 + struct device_attribute enable_attr; 60 + char group_name[MAX_ATTR_GROUP_NAME_LEN]; 61 + }; 62 + 63 + static const struct mmio_reg ptc_mmio_regs[] = { 64 + { 8, 0xFF, 0, 500}, /* temperature_target, units 0.5C*/ 65 + { 1, 0x01, 8, 0}, /* enable */ 66 + { 3, 0x7, 9, 0}, /* gain */ 67 + { 8, 0xFF, 16, 0}, /* min_performance_level */ 68 + { 1, 0x1, 12, 0}, /* temperature_override_enable */ 69 + { 8, 0xFF, 24, 500}, /* temperature_override, units 0.5C */ 70 + }; 71 + 72 + #define PTC_MAX_INSTANCES 3 73 + 74 + /* Unique offset for each PTC instance */ 75 + static u32 ptc_offsets[PTC_MAX_INSTANCES] = {0x5B20, 0x5B28, 0x5B30}; 76 + 77 + /* These will represent sysfs attribute names */ 78 + static const char * const ptc_strings[] = { 79 + "temperature_target", 80 + "enable", 81 + NULL 82 + }; 83 + 84 + /* Lock to protect concurrent read/write and read-modify-write */ 85 + static DEFINE_MUTEX(ptc_lock); 86 + 87 + static ssize_t ptc_mmio_show(struct ptc_data *data, struct device *dev, 88 + struct device_attribute *attr, char *buf) 89 + { 90 + struct pci_dev *pdev = to_pci_dev(dev); 91 + struct proc_thermal_device *proc_priv; 92 + const struct mmio_reg *mmio_regs; 93 + int ret, units; 94 + u64 reg_val; 95 + 96 + proc_priv = pci_get_drvdata(pdev); 97 + mmio_regs = ptc_mmio_regs; 98 + ret = match_string(ptc_strings, -1, attr->attr.name); 99 + if (ret < 0) 100 + return ret; 101 + 102 + units = mmio_regs[ret].units; 103 + 104 + guard(mutex)(&ptc_lock); 105 + 106 + reg_val = readq((void __iomem *) (proc_priv->mmio_base + data->offset)); 107 + ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask; 108 + if (units) 109 + ret *= units; 110 + 111 + return sysfs_emit(buf, "%d\n", ret); 112 + } 113 + 114 + #define PTC_SHOW(suffix)\ 115 + static ssize_t suffix##_show(struct device *dev,\ 116 + struct device_attribute *attr,\ 117 + char *buf)\ 118 + {\ 119 + struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\ 120 + return ptc_mmio_show(data, dev, attr, buf);\ 121 + } 122 + 123 + static void ptc_mmio_write(struct pci_dev *pdev, u32 offset, int index, u32 value) 124 + { 125 + struct proc_thermal_device *proc_priv; 126 + u64 mask, reg_val; 127 + 128 + proc_priv = pci_get_drvdata(pdev); 129 + 130 + mask = GENMASK_ULL(ptc_mmio_regs[index].shift + ptc_mmio_regs[index].bits - 1, 131 + ptc_mmio_regs[index].shift); 132 + 133 + guard(mutex)(&ptc_lock); 134 + 135 + reg_val = readq((void __iomem *) (proc_priv->mmio_base + offset)); 136 + reg_val &= ~mask; 137 + reg_val |= (value << ptc_mmio_regs[index].shift); 138 + writeq(reg_val, (void __iomem *) (proc_priv->mmio_base + offset)); 139 + } 140 + 141 + static int ptc_store(struct ptc_data *data, struct device *dev, struct device_attribute *attr, 142 + const char *buf, size_t count) 143 + { 144 + struct pci_dev *pdev = to_pci_dev(dev); 145 + unsigned int input; 146 + int ret; 147 + 148 + ret = kstrtouint(buf, 10, &input); 149 + if (ret) 150 + return ret; 151 + 152 + ret = match_string(ptc_strings, -1, attr->attr.name); 153 + if (ret < 0) 154 + return ret; 155 + 156 + if (ptc_mmio_regs[ret].units) 157 + input /= ptc_mmio_regs[ret].units; 158 + 159 + if (input > ptc_mmio_regs[ret].mask) 160 + return -EINVAL; 161 + 162 + ptc_mmio_write(pdev, data->offset, ret, input); 163 + 164 + return count; 165 + } 166 + 167 + #define PTC_STORE(suffix)\ 168 + static ssize_t suffix##_store(struct device *dev,\ 169 + struct device_attribute *attr,\ 170 + const char *buf, size_t count)\ 171 + {\ 172 + struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\ 173 + return ptc_store(data, dev, attr, buf, count);\ 174 + } 175 + 176 + PTC_SHOW(temperature_target); 177 + PTC_STORE(temperature_target); 178 + PTC_SHOW(enable); 179 + PTC_STORE(enable); 180 + 181 + #define ptc_init_attribute(_name)\ 182 + do {\ 183 + sysfs_attr_init(&data->_name##_attr.attr);\ 184 + data->_name##_attr.show = _name##_show;\ 185 + data->_name##_attr.store = _name##_store;\ 186 + data->_name##_attr.attr.name = #_name;\ 187 + data->_name##_attr.attr.mode = 0644;\ 188 + } while (0) 189 + 190 + static int ptc_create_groups(struct pci_dev *pdev, int instance, struct ptc_data *data) 191 + { 192 + int ret, index = 0; 193 + 194 + ptc_init_attribute(temperature_target); 195 + ptc_init_attribute(enable); 196 + 197 + data->ptc_attrs[index++] = &data->temperature_target_attr.attr; 198 + data->ptc_attrs[index++] = &data->enable_attr.attr; 199 + data->ptc_attrs[index] = NULL; 200 + 201 + snprintf(data->group_name, MAX_ATTR_GROUP_NAME_LEN, 202 + "ptc_%d_control", instance); 203 + data->ptc_attr_group.name = data->group_name; 204 + data->ptc_attr_group.attrs = data->ptc_attrs; 205 + 206 + ret = sysfs_create_group(&pdev->dev.kobj, &data->ptc_attr_group); 207 + 208 + return ret; 209 + } 210 + 211 + static struct ptc_data ptc_instance[PTC_MAX_INSTANCES]; 212 + 213 + int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 214 + { 215 + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) { 216 + int i; 217 + 218 + for (i = 0; i < PTC_MAX_INSTANCES; i++) { 219 + ptc_instance[i].offset = ptc_offsets[i]; 220 + ptc_create_groups(pdev, i, &ptc_instance[i]); 221 + } 222 + } 223 + 224 + return 0; 225 + } 226 + EXPORT_SYMBOL_GPL(proc_thermal_ptc_add); 227 + 228 + void proc_thermal_ptc_remove(struct pci_dev *pdev) 229 + { 230 + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); 231 + 232 + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) { 233 + int i; 234 + 235 + for (i = 0; i < PTC_MAX_INSTANCES; i++) 236 + sysfs_remove_group(&pdev->dev.kobj, &ptc_instance[i].ptc_attr_group); 237 + } 238 + } 239 + EXPORT_SYMBOL_GPL(proc_thermal_ptc_remove); 240 + 241 + MODULE_IMPORT_NS("INT340X_THERMAL"); 242 + MODULE_LICENSE("GPL"); 243 + MODULE_DESCRIPTION("Processor Thermal PTC Interface");
+14 -1
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
··· 399 399 } 400 400 } 401 401 402 + if (feature_mask & PROC_THERMAL_FEATURE_PTC) { 403 + ret = proc_thermal_ptc_add(pdev, proc_priv); 404 + if (ret) { 405 + dev_err(&pdev->dev, "failed to add PTC MMIO interface\n"); 406 + goto err_rem_rapl; 407 + } 408 + } 409 + 402 410 if (feature_mask & PROC_THERMAL_FEATURE_FIVR || 403 411 feature_mask & PROC_THERMAL_FEATURE_DVFS || 404 412 feature_mask & PROC_THERMAL_FEATURE_DLVR) { 405 413 ret = proc_thermal_rfim_add(pdev, proc_priv); 406 414 if (ret) { 407 415 dev_err(&pdev->dev, "failed to add RFIM interface\n"); 408 - goto err_rem_rapl; 416 + goto err_rem_ptc; 409 417 } 410 418 } 411 419 ··· 435 427 436 428 err_rem_rfim: 437 429 proc_thermal_rfim_remove(pdev); 430 + err_rem_ptc: 431 + proc_thermal_ptc_remove(pdev); 438 432 err_rem_rapl: 439 433 proc_thermal_rapl_remove(); 440 434 ··· 448 438 { 449 439 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL) 450 440 proc_thermal_rapl_remove(); 441 + 442 + if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) 443 + proc_thermal_ptc_remove(pdev); 451 444 452 445 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR || 453 446 proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS ||
+3
drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
··· 67 67 #define PROC_THERMAL_FEATURE_WT_HINT 0x20 68 68 #define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40 69 69 #define PROC_THERMAL_FEATURE_MSI_SUPPORT 0x80 70 + #define PROC_THERMAL_FEATURE_PTC 0x100 70 71 71 72 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL) 72 73 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); ··· 124 123 struct proc_thermal_device *proc_priv, 125 124 kernel_ulong_t feature_mask); 126 125 void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); 126 + int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); 127 + void proc_thermal_ptc_remove(struct pci_dev *pdev); 127 128 #endif
+3 -2
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
··· 486 486 PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) }, 487 487 { PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT | 488 488 PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | 489 - PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) }, 489 + PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR | 490 + PROC_THERMAL_FEATURE_PTC) }, 490 491 { PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL | 491 492 PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR | 492 493 PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) }, ··· 498 497 { PCI_DEVICE_DATA(INTEL, PTL_THERMAL, PROC_THERMAL_FEATURE_RAPL | 499 498 PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | 500 499 PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT | 501 - PROC_THERMAL_FEATURE_POWER_FLOOR) }, 500 + PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) }, 502 501 { }, 503 502 }; 504 503