processor_thermal_device.c (10822B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * processor_thermal_device.c 4 * Copyright (c) 2014, Intel Corporation. 5 */ 6#include <linux/acpi.h> 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/pci.h> 10#include <linux/thermal.h> 11#include "int340x_thermal_zone.h" 12#include "processor_thermal_device.h" 13#include "../intel_soc_dts_iosf.h" 14 15#define DRV_NAME "proc_thermal" 16 17#define POWER_LIMIT_SHOW(index, suffix) \ 18static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ 19 struct device_attribute *attr, \ 20 char *buf) \ 21{ \ 22 struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \ 23 \ 24 return sprintf(buf, "%lu\n",\ 25 (unsigned long)proc_dev->power_limits[index].suffix * 1000); \ 26} 27 28POWER_LIMIT_SHOW(0, min_uw) 29POWER_LIMIT_SHOW(0, max_uw) 30POWER_LIMIT_SHOW(0, step_uw) 31POWER_LIMIT_SHOW(0, tmin_us) 32POWER_LIMIT_SHOW(0, tmax_us) 33 34POWER_LIMIT_SHOW(1, min_uw) 35POWER_LIMIT_SHOW(1, max_uw) 36POWER_LIMIT_SHOW(1, step_uw) 37POWER_LIMIT_SHOW(1, tmin_us) 38POWER_LIMIT_SHOW(1, tmax_us) 39 40static DEVICE_ATTR_RO(power_limit_0_min_uw); 41static DEVICE_ATTR_RO(power_limit_0_max_uw); 42static DEVICE_ATTR_RO(power_limit_0_step_uw); 43static DEVICE_ATTR_RO(power_limit_0_tmin_us); 44static DEVICE_ATTR_RO(power_limit_0_tmax_us); 45 46static DEVICE_ATTR_RO(power_limit_1_min_uw); 47static DEVICE_ATTR_RO(power_limit_1_max_uw); 48static DEVICE_ATTR_RO(power_limit_1_step_uw); 49static DEVICE_ATTR_RO(power_limit_1_tmin_us); 50static DEVICE_ATTR_RO(power_limit_1_tmax_us); 51 52static struct attribute *power_limit_attrs[] = { 53 &dev_attr_power_limit_0_min_uw.attr, 54 &dev_attr_power_limit_1_min_uw.attr, 55 &dev_attr_power_limit_0_max_uw.attr, 56 &dev_attr_power_limit_1_max_uw.attr, 57 &dev_attr_power_limit_0_step_uw.attr, 58 &dev_attr_power_limit_1_step_uw.attr, 59 &dev_attr_power_limit_0_tmin_us.attr, 60 &dev_attr_power_limit_1_tmin_us.attr, 61 &dev_attr_power_limit_0_tmax_us.attr, 62 &dev_attr_power_limit_1_tmax_us.attr, 63 NULL 64}; 65 66static const struct attribute_group power_limit_attribute_group = { 67 .attrs = power_limit_attrs, 68 .name = "power_limits" 69}; 70 71static int tcc_get_offset(void) 72{ 73 u64 val; 74 int err; 75 76 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); 77 if (err) 78 return err; 79 80 return (val >> 24) & 0x3f; 81} 82 83static ssize_t tcc_offset_degree_celsius_show(struct device *dev, 84 struct device_attribute *attr, 85 char *buf) 86{ 87 int tcc; 88 89 tcc = tcc_get_offset(); 90 if (tcc < 0) 91 return tcc; 92 93 return sprintf(buf, "%d\n", tcc); 94} 95 96static int tcc_offset_update(unsigned int tcc) 97{ 98 u64 val; 99 int err; 100 101 if (tcc > 63) 102 return -EINVAL; 103 104 err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); 105 if (err) 106 return err; 107 108 if (val & BIT(31)) 109 return -EPERM; 110 111 val &= ~GENMASK_ULL(29, 24); 112 val |= (tcc & 0x3f) << 24; 113 114 err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); 115 if (err) 116 return err; 117 118 return 0; 119} 120 121static ssize_t tcc_offset_degree_celsius_store(struct device *dev, 122 struct device_attribute *attr, const char *buf, 123 size_t count) 124{ 125 unsigned int tcc; 126 u64 val; 127 int err; 128 129 err = rdmsrl_safe(MSR_PLATFORM_INFO, &val); 130 if (err) 131 return err; 132 133 if (!(val & BIT(30))) 134 return -EACCES; 135 136 if (kstrtouint(buf, 0, &tcc)) 137 return -EINVAL; 138 139 err = tcc_offset_update(tcc); 140 if (err) 141 return err; 142 143 return count; 144} 145 146static DEVICE_ATTR_RW(tcc_offset_degree_celsius); 147 148static int stored_tjmax; /* since it is fixed, we can have local storage */ 149 150static int get_tjmax(void) 151{ 152 u32 eax, edx; 153 u32 val; 154 int err; 155 156 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 157 if (err) 158 return err; 159 160 val = (eax >> 16) & 0xff; 161 if (val) 162 return val; 163 164 return -EINVAL; 165} 166 167static int read_temp_msr(int *temp) 168{ 169 int cpu; 170 u32 eax, edx; 171 int err; 172 unsigned long curr_temp_off = 0; 173 174 *temp = 0; 175 176 for_each_online_cpu(cpu) { 177 err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, 178 &edx); 179 if (err) 180 goto err_ret; 181 else { 182 if (eax & 0x80000000) { 183 curr_temp_off = (eax >> 16) & 0x7f; 184 if (!*temp || curr_temp_off < *temp) 185 *temp = curr_temp_off; 186 } else { 187 err = -EINVAL; 188 goto err_ret; 189 } 190 } 191 } 192 193 return 0; 194err_ret: 195 return err; 196} 197 198static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, 199 int *temp) 200{ 201 int ret; 202 203 ret = read_temp_msr(temp); 204 if (!ret) 205 *temp = (stored_tjmax - *temp) * 1000; 206 207 return ret; 208} 209 210static struct thermal_zone_device_ops proc_thermal_local_ops = { 211 .get_temp = proc_thermal_get_zone_temp, 212}; 213 214static int proc_thermal_read_ppcc(struct proc_thermal_device *proc_priv) 215{ 216 int i; 217 acpi_status status; 218 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; 219 union acpi_object *elements, *ppcc; 220 union acpi_object *p; 221 int ret = 0; 222 223 status = acpi_evaluate_object(proc_priv->adev->handle, "PPCC", 224 NULL, &buf); 225 if (ACPI_FAILURE(status)) 226 return -ENODEV; 227 228 p = buf.pointer; 229 if (!p || (p->type != ACPI_TYPE_PACKAGE)) { 230 dev_err(proc_priv->dev, "Invalid PPCC data\n"); 231 ret = -EFAULT; 232 goto free_buffer; 233 } 234 235 if (!p->package.count) { 236 dev_err(proc_priv->dev, "Invalid PPCC package size\n"); 237 ret = -EFAULT; 238 goto free_buffer; 239 } 240 241 for (i = 0; i < min((int)p->package.count - 1, 2); ++i) { 242 elements = &(p->package.elements[i+1]); 243 if (elements->type != ACPI_TYPE_PACKAGE || 244 elements->package.count != 6) { 245 ret = -EFAULT; 246 goto free_buffer; 247 } 248 ppcc = elements->package.elements; 249 proc_priv->power_limits[i].index = ppcc[0].integer.value; 250 proc_priv->power_limits[i].min_uw = ppcc[1].integer.value; 251 proc_priv->power_limits[i].max_uw = ppcc[2].integer.value; 252 proc_priv->power_limits[i].tmin_us = ppcc[3].integer.value; 253 proc_priv->power_limits[i].tmax_us = ppcc[4].integer.value; 254 proc_priv->power_limits[i].step_uw = ppcc[5].integer.value; 255 } 256 257free_buffer: 258 kfree(buf.pointer); 259 260 return ret; 261} 262 263#define PROC_POWER_CAPABILITY_CHANGED 0x83 264static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) 265{ 266 struct proc_thermal_device *proc_priv = data; 267 268 if (!proc_priv) 269 return; 270 271 switch (event) { 272 case PROC_POWER_CAPABILITY_CHANGED: 273 proc_thermal_read_ppcc(proc_priv); 274 int340x_thermal_zone_device_update(proc_priv->int340x_zone, 275 THERMAL_DEVICE_POWER_CAPABILITY_CHANGED); 276 break; 277 default: 278 dev_dbg(proc_priv->dev, "Unsupported event [0x%x]\n", event); 279 break; 280 } 281} 282 283int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv) 284{ 285 struct acpi_device *adev; 286 acpi_status status; 287 unsigned long long tmp; 288 struct thermal_zone_device_ops *ops = NULL; 289 int ret; 290 291 adev = ACPI_COMPANION(dev); 292 if (!adev) 293 return -ENODEV; 294 295 proc_priv->dev = dev; 296 proc_priv->adev = adev; 297 298 ret = proc_thermal_read_ppcc(proc_priv); 299 if (ret) 300 return ret; 301 302 status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); 303 if (ACPI_FAILURE(status)) { 304 /* there is no _TMP method, add local method */ 305 stored_tjmax = get_tjmax(); 306 if (stored_tjmax > 0) 307 ops = &proc_thermal_local_ops; 308 } 309 310 proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); 311 if (IS_ERR(proc_priv->int340x_zone)) { 312 return PTR_ERR(proc_priv->int340x_zone); 313 } else 314 ret = 0; 315 316 ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, 317 proc_thermal_notify, 318 (void *)proc_priv); 319 if (ret) 320 goto remove_zone; 321 322 ret = sysfs_create_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); 323 if (ret) 324 goto remove_notify; 325 326 ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group); 327 if (ret) { 328 sysfs_remove_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); 329 goto remove_notify; 330 } 331 332 return 0; 333 334remove_notify: 335 acpi_remove_notify_handler(adev->handle, 336 ACPI_DEVICE_NOTIFY, proc_thermal_notify); 337remove_zone: 338 int340x_thermal_zone_remove(proc_priv->int340x_zone); 339 340 return ret; 341} 342EXPORT_SYMBOL_GPL(proc_thermal_add); 343 344void proc_thermal_remove(struct proc_thermal_device *proc_priv) 345{ 346 acpi_remove_notify_handler(proc_priv->adev->handle, 347 ACPI_DEVICE_NOTIFY, proc_thermal_notify); 348 int340x_thermal_zone_remove(proc_priv->int340x_zone); 349 sysfs_remove_file(&proc_priv->dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); 350 sysfs_remove_group(&proc_priv->dev->kobj, 351 &power_limit_attribute_group); 352} 353EXPORT_SYMBOL_GPL(proc_thermal_remove); 354 355static int tcc_offset_save = -1; 356 357int proc_thermal_suspend(struct device *dev) 358{ 359 tcc_offset_save = tcc_get_offset(); 360 if (tcc_offset_save < 0) 361 dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save); 362 363 return 0; 364} 365EXPORT_SYMBOL_GPL(proc_thermal_suspend); 366 367int proc_thermal_resume(struct device *dev) 368{ 369 struct proc_thermal_device *proc_dev; 370 371 proc_dev = dev_get_drvdata(dev); 372 proc_thermal_read_ppcc(proc_dev); 373 374 /* Do not update if saving failed */ 375 if (tcc_offset_save >= 0) 376 tcc_offset_update(tcc_offset_save); 377 378 return 0; 379} 380EXPORT_SYMBOL_GPL(proc_thermal_resume); 381 382#define MCHBAR 0 383 384static int proc_thermal_set_mmio_base(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 385{ 386 int ret; 387 388 ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME); 389 if (ret) { 390 dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); 391 return -ENOMEM; 392 } 393 394 proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR]; 395 396 return 0; 397} 398 399int proc_thermal_mmio_add(struct pci_dev *pdev, 400 struct proc_thermal_device *proc_priv, 401 kernel_ulong_t feature_mask) 402{ 403 int ret; 404 405 proc_priv->mmio_feature_mask = feature_mask; 406 407 if (feature_mask) { 408 ret = proc_thermal_set_mmio_base(pdev, proc_priv); 409 if (ret) 410 return ret; 411 } 412 413 if (feature_mask & PROC_THERMAL_FEATURE_RAPL) { 414 ret = proc_thermal_rapl_add(pdev, proc_priv); 415 if (ret) { 416 dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n"); 417 return ret; 418 } 419 } 420 421 if (feature_mask & PROC_THERMAL_FEATURE_FIVR || 422 feature_mask & PROC_THERMAL_FEATURE_DVFS) { 423 ret = proc_thermal_rfim_add(pdev, proc_priv); 424 if (ret) { 425 dev_err(&pdev->dev, "failed to add RFIM interface\n"); 426 goto err_rem_rapl; 427 } 428 } 429 430 if (feature_mask & PROC_THERMAL_FEATURE_MBOX) { 431 ret = proc_thermal_mbox_add(pdev, proc_priv); 432 if (ret) { 433 dev_err(&pdev->dev, "failed to add MBOX interface\n"); 434 goto err_rem_rfim; 435 } 436 } 437 438 return 0; 439 440err_rem_rfim: 441 proc_thermal_rfim_remove(pdev); 442err_rem_rapl: 443 proc_thermal_rapl_remove(); 444 445 return ret; 446} 447EXPORT_SYMBOL_GPL(proc_thermal_mmio_add); 448 449void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 450{ 451 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL) 452 proc_thermal_rapl_remove(); 453 454 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR || 455 proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) 456 proc_thermal_rfim_remove(pdev); 457 458 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX) 459 proc_thermal_mbox_remove(pdev); 460} 461EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove); 462 463MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 464MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); 465MODULE_LICENSE("GPL v2");