intel_menlow.c (12730B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Intel menlow Driver for thermal management extension 4 * 5 * Copyright (C) 2008 Intel Corp 6 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 7 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 8 * 9 * This driver creates the sys I/F for programming the sensors. 10 * It also implements the driver for intel menlow memory controller (hardware 11 * id is INT0002) which makes use of the platform specific ACPI methods 12 * to get/set bandwidth. 13 */ 14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 17#include <linux/acpi.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/pci.h> 21#include <linux/pm.h> 22#include <linux/slab.h> 23#include <linux/thermal.h> 24#include <linux/types.h> 25#include <linux/units.h> 26 27MODULE_AUTHOR("Thomas Sujith"); 28MODULE_AUTHOR("Zhang Rui"); 29MODULE_DESCRIPTION("Intel Menlow platform specific driver"); 30MODULE_LICENSE("GPL v2"); 31 32/* 33 * Memory controller device control 34 */ 35 36#define MEMORY_GET_BANDWIDTH "GTHS" 37#define MEMORY_SET_BANDWIDTH "STHS" 38#define MEMORY_ARG_CUR_BANDWIDTH 1 39#define MEMORY_ARG_MAX_BANDWIDTH 0 40 41static void intel_menlow_unregister_sensor(void); 42 43/* 44 * GTHS returning 'n' would mean that [0,n-1] states are supported 45 * In that case max_cstate would be n-1 46 * GTHS returning '0' would mean that no bandwidth control states are supported 47 */ 48static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev, 49 unsigned long *max_state) 50{ 51 struct acpi_device *device = cdev->devdata; 52 acpi_handle handle = device->handle; 53 unsigned long long value; 54 struct acpi_object_list arg_list; 55 union acpi_object arg; 56 acpi_status status = AE_OK; 57 58 arg_list.count = 1; 59 arg_list.pointer = &arg; 60 arg.type = ACPI_TYPE_INTEGER; 61 arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; 62 status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, 63 &arg_list, &value); 64 if (ACPI_FAILURE(status)) 65 return -EFAULT; 66 67 if (!value) 68 return -EINVAL; 69 70 *max_state = value - 1; 71 return 0; 72} 73 74static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, 75 unsigned long *value) 76{ 77 struct acpi_device *device = cdev->devdata; 78 acpi_handle handle = device->handle; 79 unsigned long long result; 80 struct acpi_object_list arg_list; 81 union acpi_object arg; 82 acpi_status status = AE_OK; 83 84 arg_list.count = 1; 85 arg_list.pointer = &arg; 86 arg.type = ACPI_TYPE_INTEGER; 87 arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; 88 status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, 89 &arg_list, &result); 90 if (ACPI_FAILURE(status)) 91 return -EFAULT; 92 93 *value = result; 94 return 0; 95} 96 97static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, 98 unsigned long state) 99{ 100 struct acpi_device *device = cdev->devdata; 101 acpi_handle handle = device->handle; 102 struct acpi_object_list arg_list; 103 union acpi_object arg; 104 acpi_status status; 105 unsigned long long temp; 106 unsigned long max_state; 107 108 if (memory_get_max_bandwidth(cdev, &max_state)) 109 return -EFAULT; 110 111 if (state > max_state) 112 return -EINVAL; 113 114 arg_list.count = 1; 115 arg_list.pointer = &arg; 116 arg.type = ACPI_TYPE_INTEGER; 117 arg.integer.value = state; 118 119 status = 120 acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, 121 &temp); 122 123 pr_info("Bandwidth value was %ld: status is %d\n", state, status); 124 if (ACPI_FAILURE(status)) 125 return -EFAULT; 126 127 return 0; 128} 129 130static const struct thermal_cooling_device_ops memory_cooling_ops = { 131 .get_max_state = memory_get_max_bandwidth, 132 .get_cur_state = memory_get_cur_bandwidth, 133 .set_cur_state = memory_set_cur_bandwidth, 134}; 135 136/* 137 * Memory Device Management 138 */ 139static int intel_menlow_memory_add(struct acpi_device *device) 140{ 141 int result = -ENODEV; 142 struct thermal_cooling_device *cdev; 143 144 if (!device) 145 return -EINVAL; 146 147 if (!acpi_has_method(device->handle, MEMORY_GET_BANDWIDTH)) 148 goto end; 149 150 if (!acpi_has_method(device->handle, MEMORY_SET_BANDWIDTH)) 151 goto end; 152 153 cdev = thermal_cooling_device_register("Memory controller", device, 154 &memory_cooling_ops); 155 if (IS_ERR(cdev)) { 156 result = PTR_ERR(cdev); 157 goto end; 158 } 159 160 device->driver_data = cdev; 161 result = sysfs_create_link(&device->dev.kobj, 162 &cdev->device.kobj, "thermal_cooling"); 163 if (result) 164 goto unregister; 165 166 result = sysfs_create_link(&cdev->device.kobj, 167 &device->dev.kobj, "device"); 168 if (result) { 169 sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 170 goto unregister; 171 } 172 173 end: 174 return result; 175 176 unregister: 177 thermal_cooling_device_unregister(cdev); 178 return result; 179 180} 181 182static int intel_menlow_memory_remove(struct acpi_device *device) 183{ 184 struct thermal_cooling_device *cdev; 185 186 if (!device) 187 return -EINVAL; 188 189 cdev = acpi_driver_data(device); 190 if (!cdev) 191 return -EINVAL; 192 193 sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 194 sysfs_remove_link(&cdev->device.kobj, "device"); 195 thermal_cooling_device_unregister(cdev); 196 197 return 0; 198} 199 200static const struct acpi_device_id intel_menlow_memory_ids[] = { 201 {"INT0002", 0}, 202 {"", 0}, 203}; 204 205static struct acpi_driver intel_menlow_memory_driver = { 206 .name = "intel_menlow_thermal_control", 207 .ids = intel_menlow_memory_ids, 208 .ops = { 209 .add = intel_menlow_memory_add, 210 .remove = intel_menlow_memory_remove, 211 }, 212}; 213 214/* 215 * Sensor control on menlow platform 216 */ 217 218#define THERMAL_AUX0 0 219#define THERMAL_AUX1 1 220#define GET_AUX0 "GAX0" 221#define GET_AUX1 "GAX1" 222#define SET_AUX0 "SAX0" 223#define SET_AUX1 "SAX1" 224 225struct intel_menlow_attribute { 226 struct device_attribute attr; 227 struct device *device; 228 acpi_handle handle; 229 struct list_head node; 230}; 231 232static LIST_HEAD(intel_menlow_attr_list); 233static DEFINE_MUTEX(intel_menlow_attr_lock); 234 235/* 236 * sensor_get_auxtrip - get the current auxtrip value from sensor 237 * @name: Thermalzone name 238 * @auxtype : AUX0/AUX1 239 * @buf: syfs buffer 240 */ 241static int sensor_get_auxtrip(acpi_handle handle, int index, 242 unsigned long long *value) 243{ 244 acpi_status status; 245 246 if ((index != 0 && index != 1) || !value) 247 return -EINVAL; 248 249 status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, 250 NULL, value); 251 if (ACPI_FAILURE(status)) 252 return -EIO; 253 254 return 0; 255} 256 257/* 258 * sensor_set_auxtrip - set the new auxtrip value to sensor 259 * @name: Thermalzone name 260 * @auxtype : AUX0/AUX1 261 * @buf: syfs buffer 262 */ 263static int sensor_set_auxtrip(acpi_handle handle, int index, int value) 264{ 265 acpi_status status; 266 union acpi_object arg = { 267 ACPI_TYPE_INTEGER 268 }; 269 struct acpi_object_list args = { 270 1, &arg 271 }; 272 unsigned long long temp; 273 274 if (index != 0 && index != 1) 275 return -EINVAL; 276 277 status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, 278 NULL, &temp); 279 if (ACPI_FAILURE(status)) 280 return -EIO; 281 if ((index && value < temp) || (!index && value > temp)) 282 return -EINVAL; 283 284 arg.integer.value = value; 285 status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, 286 &args, &temp); 287 if (ACPI_FAILURE(status)) 288 return -EIO; 289 290 /* do we need to check the return value of SAX0/SAX1 ? */ 291 292 return 0; 293} 294 295#define to_intel_menlow_attr(_attr) \ 296 container_of(_attr, struct intel_menlow_attribute, attr) 297 298static ssize_t aux_show(struct device *dev, struct device_attribute *dev_attr, 299 char *buf, int idx) 300{ 301 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); 302 unsigned long long value; 303 int result; 304 305 result = sensor_get_auxtrip(attr->handle, idx, &value); 306 if (result) 307 return result; 308 309 return sprintf(buf, "%lu", deci_kelvin_to_celsius(value)); 310} 311 312static ssize_t aux0_show(struct device *dev, 313 struct device_attribute *dev_attr, char *buf) 314{ 315 return aux_show(dev, dev_attr, buf, 0); 316} 317 318static ssize_t aux1_show(struct device *dev, 319 struct device_attribute *dev_attr, char *buf) 320{ 321 return aux_show(dev, dev_attr, buf, 1); 322} 323 324static ssize_t aux_store(struct device *dev, struct device_attribute *dev_attr, 325 const char *buf, size_t count, int idx) 326{ 327 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); 328 int value; 329 int result; 330 331 /*Sanity check; should be a positive integer */ 332 if (!sscanf(buf, "%d", &value)) 333 return -EINVAL; 334 335 if (value < 0) 336 return -EINVAL; 337 338 result = sensor_set_auxtrip(attr->handle, idx, 339 celsius_to_deci_kelvin(value)); 340 return result ? result : count; 341} 342 343static ssize_t aux0_store(struct device *dev, 344 struct device_attribute *dev_attr, 345 const char *buf, size_t count) 346{ 347 return aux_store(dev, dev_attr, buf, count, 0); 348} 349 350static ssize_t aux1_store(struct device *dev, 351 struct device_attribute *dev_attr, 352 const char *buf, size_t count) 353{ 354 return aux_store(dev, dev_attr, buf, count, 1); 355} 356 357/* BIOS can enable/disable the thermal user application in dabney platform */ 358#define BIOS_ENABLED "\\_TZ.GSTS" 359static ssize_t bios_enabled_show(struct device *dev, 360 struct device_attribute *attr, char *buf) 361{ 362 acpi_status status; 363 unsigned long long bios_enabled; 364 365 status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); 366 if (ACPI_FAILURE(status)) 367 return -ENODEV; 368 369 return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); 370} 371 372static int intel_menlow_add_one_attribute(char *name, umode_t mode, void *show, 373 void *store, struct device *dev, 374 acpi_handle handle) 375{ 376 struct intel_menlow_attribute *attr; 377 int result; 378 379 attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); 380 if (!attr) 381 return -ENOMEM; 382 383 sysfs_attr_init(&attr->attr.attr); /* That is consistent naming :D */ 384 attr->attr.attr.name = name; 385 attr->attr.attr.mode = mode; 386 attr->attr.show = show; 387 attr->attr.store = store; 388 attr->device = dev; 389 attr->handle = handle; 390 391 result = device_create_file(dev, &attr->attr); 392 if (result) { 393 kfree(attr); 394 return result; 395 } 396 397 mutex_lock(&intel_menlow_attr_lock); 398 list_add_tail(&attr->node, &intel_menlow_attr_list); 399 mutex_unlock(&intel_menlow_attr_lock); 400 401 return 0; 402} 403 404static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, 405 void *context, void **rv) 406{ 407 acpi_status status; 408 acpi_handle dummy; 409 struct thermal_zone_device *thermal; 410 int result; 411 412 result = acpi_bus_get_private_data(handle, (void **)&thermal); 413 if (result) 414 return 0; 415 416 /* _TZ must have the AUX0/1 methods */ 417 status = acpi_get_handle(handle, GET_AUX0, &dummy); 418 if (ACPI_FAILURE(status)) 419 return (status == AE_NOT_FOUND) ? AE_OK : status; 420 421 status = acpi_get_handle(handle, SET_AUX0, &dummy); 422 if (ACPI_FAILURE(status)) 423 return (status == AE_NOT_FOUND) ? AE_OK : status; 424 425 result = intel_menlow_add_one_attribute("aux0", 0644, 426 aux0_show, aux0_store, 427 &thermal->device, handle); 428 if (result) 429 return AE_ERROR; 430 431 status = acpi_get_handle(handle, GET_AUX1, &dummy); 432 if (ACPI_FAILURE(status)) 433 goto aux1_not_found; 434 435 status = acpi_get_handle(handle, SET_AUX1, &dummy); 436 if (ACPI_FAILURE(status)) 437 goto aux1_not_found; 438 439 result = intel_menlow_add_one_attribute("aux1", 0644, 440 aux1_show, aux1_store, 441 &thermal->device, handle); 442 if (result) { 443 intel_menlow_unregister_sensor(); 444 return AE_ERROR; 445 } 446 447 /* 448 * create the "dabney_enabled" attribute which means the user app 449 * should be loaded or not 450 */ 451 452 result = intel_menlow_add_one_attribute("bios_enabled", 0444, 453 bios_enabled_show, NULL, 454 &thermal->device, handle); 455 if (result) { 456 intel_menlow_unregister_sensor(); 457 return AE_ERROR; 458 } 459 460 return AE_OK; 461 462 aux1_not_found: 463 if (status == AE_NOT_FOUND) 464 return AE_OK; 465 466 intel_menlow_unregister_sensor(); 467 return status; 468} 469 470static void intel_menlow_unregister_sensor(void) 471{ 472 struct intel_menlow_attribute *pos, *next; 473 474 mutex_lock(&intel_menlow_attr_lock); 475 list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { 476 list_del(&pos->node); 477 device_remove_file(pos->device, &pos->attr); 478 kfree(pos); 479 } 480 mutex_unlock(&intel_menlow_attr_lock); 481 482 return; 483} 484 485static int __init intel_menlow_module_init(void) 486{ 487 int result = -ENODEV; 488 acpi_status status; 489 unsigned long long enable; 490 491 if (acpi_disabled) 492 return result; 493 494 /* Looking for the \_TZ.GSTS method */ 495 status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); 496 if (ACPI_FAILURE(status) || !enable) 497 return -ENODEV; 498 499 /* Looking for ACPI device MEM0 with hardware id INT0002 */ 500 result = acpi_bus_register_driver(&intel_menlow_memory_driver); 501 if (result) 502 return result; 503 504 /* Looking for sensors in each ACPI thermal zone */ 505 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, 506 ACPI_UINT32_MAX, 507 intel_menlow_register_sensor, NULL, NULL, NULL); 508 if (ACPI_FAILURE(status)) { 509 acpi_bus_unregister_driver(&intel_menlow_memory_driver); 510 return -ENODEV; 511 } 512 513 return 0; 514} 515 516static void __exit intel_menlow_module_exit(void) 517{ 518 acpi_bus_unregister_driver(&intel_menlow_memory_driver); 519 intel_menlow_unregister_sensor(); 520} 521 522module_init(intel_menlow_module_init); 523module_exit(intel_menlow_module_exit);