cregit-Linux how code gets into the kernel

Release 4.7 drivers/platform/x86/intel_menlow.c

/*
 *  intel_menlow.c - Intel menlow Driver for thermal management extension
 *
 *  Copyright (C) 2008 Intel Corp
 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This driver creates the sys I/F for programming the sensors.
 *  It also implements the driver for intel menlow memory controller (hardware
 *  id is INT0002) which makes use of the platform specific ACPI methods
 *  to get/set bandwidth.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/thermal.h>
#include <linux/acpi.h>

MODULE_AUTHOR("Thomas Sujith");
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Intel Menlow platform specific driver");
MODULE_LICENSE("GPL");

/*
 * Memory controller device control
 */


#define MEMORY_GET_BANDWIDTH "GTHS"

#define MEMORY_SET_BANDWIDTH "STHS"

#define MEMORY_ARG_CUR_BANDWIDTH 1

#define MEMORY_ARG_MAX_BANDWIDTH 0

static void intel_menlow_unregister_sensor(void);

/*
 * GTHS returning 'n' would mean that [0,n-1] states are supported
 * In that case max_cstate would be n-1
 * GTHS returning '0' would mean that no bandwidth control states are supported
 */

static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev, unsigned long *max_state) { struct acpi_device *device = cdev->devdata; acpi_handle handle = device->handle; unsigned long long value; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, &arg_list, &value); if (ACPI_FAILURE(status)) return -EFAULT; if (!value) return -EINVAL; *max_state = value - 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith11190.98%125.00%
rui zhangrui zhang97.38%125.00%
matthew garrettmatthew garrett10.82%125.00%
matthew wilcoxmatthew wilcox10.82%125.00%
Total122100.00%4100.00%


static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, unsigned long *value) { struct acpi_device *device = cdev->devdata; acpi_handle handle = device->handle; unsigned long long result; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, &arg_list, &result); if (ACPI_FAILURE(status)) return -EFAULT; *value = result; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith9989.19%133.33%
matthew garrettmatthew garrett119.91%133.33%
matthew wilcoxmatthew wilcox10.90%133.33%
Total111100.00%3100.00%


static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, unsigned long state) { struct acpi_device *device = cdev->devdata; acpi_handle handle = device->handle; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status; unsigned long long temp; unsigned long max_state; if (memory_get_max_bandwidth(cdev, &max_state)) return -EFAULT; if (state > max_state) return -EINVAL; arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; arg.integer.value = state; status = acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, &temp); pr_info("Bandwidth value was %ld: status is %d\n", state, status); if (ACPI_FAILURE(status)) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith13395.00%125.00%
matthew wilcoxmatthew wilcox32.14%125.00%
matthew garrettmatthew garrett32.14%125.00%
joe perchesjoe perches10.71%125.00%
Total140100.00%4100.00%

static struct thermal_cooling_device_ops memory_cooling_ops = { .get_max_state = memory_get_max_bandwidth, .get_cur_state = memory_get_cur_bandwidth, .set_cur_state = memory_set_cur_bandwidth, }; /* * Memory Device Management */
static int intel_menlow_memory_add(struct acpi_device *device) { int result = -ENODEV; struct thermal_cooling_device *cdev; if (!device) return -EINVAL; if (!acpi_has_method(device->handle, MEMORY_GET_BANDWIDTH)) goto end; if (!acpi_has_method(device->handle, MEMORY_SET_BANDWIDTH)) goto end; cdev = thermal_cooling_device_register("Memory controller", device, &memory_cooling_ops); if (IS_ERR(cdev)) { result = PTR_ERR(cdev); goto end; } device->driver_data = cdev; result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, "thermal_cooling"); if (result) goto unregister; result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, "device"); if (result) { sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); goto unregister; } end: return result; unregister: thermal_cooling_device_unregister(cdev); return result; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith17394.54%250.00%
rui zhangrui zhang84.37%125.00%
pavel machekpavel machek21.09%125.00%
Total183100.00%4100.00%


static int intel_menlow_memory_remove(struct acpi_device *device) { struct thermal_cooling_device *cdev = acpi_driver_data(device); if (!device || !cdev) return -EINVAL; sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); sysfs_remove_link(&cdev->device.kobj, "device"); thermal_cooling_device_unregister(cdev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith65100.00%1100.00%
Total65100.00%1100.00%

static const struct acpi_device_id intel_menlow_memory_ids[] = { {"INT0002", 0}, {"", 0}, }; static struct acpi_driver intel_menlow_memory_driver = { .name = "intel_menlow_thermal_control", .ids = intel_menlow_memory_ids, .ops = { .add = intel_menlow_memory_add, .remove = intel_menlow_memory_remove, }, }; /* * Sensor control on menlow platform */ #define THERMAL_AUX0 0 #define THERMAL_AUX1 1 #define GET_AUX0 "GAX0" #define GET_AUX1 "GAX1" #define SET_AUX0 "SAX0" #define SET_AUX1 "SAX1" struct intel_menlow_attribute { struct device_attribute attr; struct device *device; acpi_handle handle; struct list_head node; }; static LIST_HEAD(intel_menlow_attr_list); static DEFINE_MUTEX(intel_menlow_attr_lock); /* * sensor_get_auxtrip - get the current auxtrip value from sensor * @name: Thermalzone name * @auxtype : AUX0/AUX1 * @buf: syfs buffer */
static int sensor_get_auxtrip(acpi_handle handle, int index, unsigned long long *value) { acpi_status status; if ((index != 0 && index != 1) || !value) return -EINVAL; status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, NULL, value); if (ACPI_FAILURE(status)) return -EIO; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith6895.77%150.00%
matthew wilcoxmatthew wilcox34.23%150.00%
Total71100.00%2100.00%

/* * sensor_set_auxtrip - set the new auxtrip value to sensor * @name: Thermalzone name * @auxtype : AUX0/AUX1 * @buf: syfs buffer */
static int sensor_set_auxtrip(acpi_handle handle, int index, int value) { acpi_status status; union acpi_object arg = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg }; unsigned long long temp; if (index != 0 && index != 1) return -EINVAL; status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, NULL, &temp); if (ACPI_FAILURE(status)) return -EIO; if ((index && value < temp) || (!index && value > temp)) return -EINVAL; arg.integer.value = value; status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, &args, &temp); if (ACPI_FAILURE(status)) return -EIO; /* do we need to check the return value of SAX0/SAX1 ? */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith14798.00%150.00%
matthew wilcoxmatthew wilcox32.00%150.00%
Total150100.00%2100.00%

#define to_intel_menlow_attr(_attr) \ container_of(_attr, struct intel_menlow_attribute, attr)
static ssize_t aux_show(struct device *dev, struct device_attribute *dev_attr, char *buf, int idx) { struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); unsigned long long value; int result; result = sensor_get_auxtrip(attr->handle, idx, &value); return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value)); }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith6387.50%125.00%
rasmus villemoesrasmus villemoes68.33%250.00%
matthew wilcoxmatthew wilcox34.17%125.00%
Total72100.00%4100.00%


static ssize_t aux0_show(struct device *dev, struct device_attribute *dev_attr, char *buf) { return aux_show(dev, dev_attr, buf, 0); }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith2371.88%150.00%
rasmus villemoesrasmus villemoes928.12%150.00%
Total32100.00%2100.00%


static ssize_t aux1_show(struct device *dev, struct device_attribute *dev_attr, char *buf) { return aux_show(dev, dev_attr, buf, 1); }

Contributors

PersonTokensPropCommitsCommitProp
rasmus villemoesrasmus villemoes2578.12%150.00%
thomas sujiththomas sujith721.88%150.00%
Total32100.00%2100.00%


static ssize_t aux_store(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count, int idx) { struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); int value; int result; /*Sanity check; should be a positive integer */ if (!sscanf(buf, "%d", &value)) return -EINVAL; if (value < 0) return -EINVAL; result = sensor_set_auxtrip(attr->handle, idx, CELSIUS_TO_DECI_KELVIN(value)); return result ? result : count; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith8893.62%133.33%
rasmus villemoesrasmus villemoes66.38%266.67%
Total94100.00%3100.00%


static ssize_t aux0_store(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) { return aux_store(dev, dev_attr, buf, count, 0); }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith2976.32%150.00%
rasmus villemoesrasmus villemoes923.68%150.00%
Total38100.00%2100.00%


static ssize_t aux1_store(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) { return aux_store(dev, dev_attr, buf, count, 1); }

Contributors

PersonTokensPropCommitsCommitProp
rasmus villemoesrasmus villemoes3181.58%150.00%
thomas sujiththomas sujith718.42%150.00%
Total38100.00%2100.00%

/* BIOS can enable/disable the thermal user application in dabney platform */ #define BIOS_ENABLED "\\_TZ.GSTS"
static ssize_t bios_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { acpi_status status; unsigned long long bios_enabled; status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); if (ACPI_FAILURE(status)) return -ENODEV; return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith6698.51%150.00%
matthew wilcoxmatthew wilcox11.49%150.00%
Total67100.00%2100.00%


static int intel_menlow_add_one_attribute(char *name, umode_t mode, void *show, void *store, struct device *dev, acpi_handle handle) { struct intel_menlow_attribute *attr; int result; attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); if (!attr) return -ENOMEM; sysfs_attr_init(&attr->attr.attr); /* That is consistent naming :D */ attr->attr.attr.name = name; attr->attr.attr.mode = mode; attr->attr.show = show; attr->attr.store = store; attr->device = dev; attr->handle = handle; result = device_create_file(dev, &attr->attr); if (result) { kfree(attr); return result; } mutex_lock(&intel_menlow_attr_lock); list_add_tail(&attr->node, &intel_menlow_attr_list); mutex_unlock(&intel_menlow_attr_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith15188.82%125.00%
wolfram sangwolfram sang116.47%125.00%
axel linaxel lin74.12%125.00%
al viroal viro10.59%125.00%
Total170100.00%4100.00%


static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; acpi_handle dummy; struct thermal_zone_device *thermal; int result; result = acpi_bus_get_private_data(handle, (void **)&thermal); if (result) return 0; /* _TZ must have the AUX0/1 methods */ status = acpi_get_handle(handle, GET_AUX0, &dummy); if (ACPI_FAILURE(status)) return (status == AE_NOT_FOUND) ? AE_OK : status; status = acpi_get_handle(handle, SET_AUX0, &dummy); if (ACPI_FAILURE(status)) return (status == AE_NOT_FOUND) ? AE_OK : status; result = intel_menlow_add_one_attribute("aux0", 0644, aux0_show, aux0_store, &thermal->device, handle); if (result) return AE_ERROR; status = acpi_get_handle(handle, GET_AUX1, &dummy); if (ACPI_FAILURE(status)) goto aux1_not_found; status = acpi_get_handle(handle, SET_AUX1, &dummy); if (ACPI_FAILURE(status)) goto aux1_not_found; result = intel_menlow_add_one_attribute("aux1", 0644, aux1_show, aux1_store, &thermal->device, handle); if (result) { intel_menlow_unregister_sensor(); return AE_ERROR; } /* * create the "dabney_enabled" attribute which means the user app * should be loaded or not */ result = intel_menlow_add_one_attribute("bios_enabled", 0444, bios_enabled_show, NULL, &thermal->device, handle); if (result) { intel_menlow_unregister_sensor(); return AE_ERROR; } return AE_OK; aux1_not_found: if (status == AE_NOT_FOUND) return AE_OK; intel_menlow_unregister_sensor(); return status; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith23385.04%133.33%
axel linaxel lin4114.96%266.67%
Total274100.00%3100.00%


static void intel_menlow_unregister_sensor(void) { struct intel_menlow_attribute *pos, *next; mutex_lock(&intel_menlow_attr_lock); list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { list_del(&pos->node); device_remove_file(pos->device, &pos->attr); kfree(pos); } mutex_unlock(&intel_menlow_attr_lock); return; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith66100.00%1100.00%
Total66100.00%1100.00%


static int __init intel_menlow_module_init(void) { int result = -ENODEV; acpi_status status; unsigned long long enable; if (acpi_disabled) return result; /* Looking for the \_TZ.GSTS method */ status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); if (ACPI_FAILURE(status) || !enable) return -ENODEV; /* Looking for ACPI device MEM0 with hardware id INT0002 */ result = acpi_bus_register_driver(&intel_menlow_memory_driver); if (result) return result; /* Looking for sensors in each ACPI thermal zone */ status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, intel_menlow_register_sensor, NULL, NULL, NULL); if (ACPI_FAILURE(status)) { acpi_bus_unregister_driver(&intel_menlow_memory_driver); return -ENODEV; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith10690.60%125.00%
axel linaxel lin86.84%125.00%
lin minglin ming21.71%125.00%
matthew wilcoxmatthew wilcox10.85%125.00%
Total117100.00%4100.00%


static void __exit intel_menlow_module_exit(void) { acpi_bus_unregister_driver(&intel_menlow_memory_driver); intel_menlow_unregister_sensor(); }

Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith18100.00%1100.00%
Total18100.00%1100.00%

module_init(intel_menlow_module_init); module_exit(intel_menlow_module_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
thomas sujiththomas sujith187389.23%315.79%
rasmus villemoesrasmus villemoes864.10%210.53%
axel linaxel lin633.00%210.53%
rui zhangrui zhang170.81%210.53%
matthew wilcoxmatthew wilcox160.76%15.26%
matthew garrettmatthew garrett150.71%15.26%
wolfram sangwolfram sang110.52%15.26%
joe perchesjoe perches80.38%15.26%
tejun heotejun heo30.14%15.26%
lin minglin ming20.10%15.26%
pavel machekpavel machek20.10%15.26%
al viroal viro10.05%15.26%
lv zhenglv zheng10.05%15.26%
tobias klausertobias klauser10.05%15.26%
Total2099100.00%19100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}