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

Configure Feed

Select the types of activity you want to include in your feed.

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