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