Release 4.12 drivers/acpi/thermal.c
  
  
  
/*
 *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  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.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This driver fully implements the ACPI thermal policy as described in the
 *  ACPI 2.0 Specification.
 *
 *  TBD: 1. Implement passive cooling hysteresis.
 *       2. Enhance passive cooling (CPU) states/limit interface to support
 *          concepts of 'multiple limiters', upper/lower limits, etc.
 *
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/reboot.h>
#include <linux/device.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
#include <linux/workqueue.h>
#include <linux/uaccess.h>
#define PREFIX "ACPI: "
#define ACPI_THERMAL_CLASS		"thermal_zone"
#define ACPI_THERMAL_DEVICE_NAME	"Thermal Zone"
#define ACPI_THERMAL_NOTIFY_TEMPERATURE	0x80
#define ACPI_THERMAL_NOTIFY_THRESHOLDS	0x81
#define ACPI_THERMAL_NOTIFY_DEVICES	0x82
#define ACPI_THERMAL_NOTIFY_CRITICAL	0xF0
#define ACPI_THERMAL_NOTIFY_HOT		0xF1
#define ACPI_THERMAL_MODE_ACTIVE	0x00
#define ACPI_THERMAL_MAX_ACTIVE	10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
#define _COMPONENT		ACPI_THERMAL_COMPONENT
ACPI_MODULE_NAME("thermal");
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
MODULE_LICENSE("GPL");
static int act;
module_param(act, int, 0644);
MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
static int crt;
module_param(crt, int, 0644);
MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
static int tzp;
module_param(tzp, int, 0444);
MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
static int nocrt;
module_param(nocrt, int, 0);
MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
static int off;
module_param(off, int, 0);
MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
static int psv;
module_param(psv, int, 0644);
MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
static struct workqueue_struct *acpi_thermal_pm_queue;
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id  thermal_device_ids[] = {
	{ACPI_THERMAL_HID, 0},
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
#ifdef CONFIG_PM_SLEEP
static int acpi_thermal_suspend(struct device *dev);
static int acpi_thermal_resume(struct device *dev);
#else
#define acpi_thermal_suspend NULL
#define acpi_thermal_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
static struct acpi_driver acpi_thermal_driver = {
	.name = "thermal",
	.class = ACPI_THERMAL_CLASS,
	.ids = thermal_device_ids,
	.ops = {
		.add = acpi_thermal_add,
		.remove = acpi_thermal_remove,
		.notify = acpi_thermal_notify,
                },
	.drv.pm = &acpi_thermal_pm,
};
struct acpi_thermal_state {
	
u8 critical:1;
	
u8 hot:1;
	
u8 passive:1;
	
u8 active:1;
	
u8 reserved:4;
	
int active_index;
};
struct acpi_thermal_state_flags {
	
u8 valid:1;
	
u8 enabled:1;
	
u8 reserved:6;
};
struct acpi_thermal_critical {
	
struct acpi_thermal_state_flags flags;
	
unsigned long temperature;
};
struct acpi_thermal_hot {
	
struct acpi_thermal_state_flags flags;
	
unsigned long temperature;
};
struct acpi_thermal_passive {
	
struct acpi_thermal_state_flags flags;
	
unsigned long temperature;
	
unsigned long tc1;
	
unsigned long tc2;
	
unsigned long tsp;
	
struct acpi_handle_list devices;
};
struct acpi_thermal_active {
	
struct acpi_thermal_state_flags flags;
	
unsigned long temperature;
	
struct acpi_handle_list devices;
};
struct acpi_thermal_trips {
	
struct acpi_thermal_critical critical;
	
struct acpi_thermal_hot hot;
	
struct acpi_thermal_passive passive;
	
struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
};
struct acpi_thermal_flags {
	
u8 cooling_mode:1;	/* _SCP */
	
u8 devices:1;		/* _TZD */
	
u8 reserved:6;
};
struct acpi_thermal {
	
struct acpi_device * device;
	
acpi_bus_id name;
	
unsigned long temperature;
	
unsigned long last_temperature;
	
unsigned long polling_frequency;
	
volatile u8 zombie;
	
struct acpi_thermal_flags flags;
	
struct acpi_thermal_state state;
	
struct acpi_thermal_trips trips;
	
struct acpi_handle_list devices;
	
struct thermal_zone_device *thermal_zone;
	
int tz_enabled;
	
int kelvin_offset;
	
struct work_struct thermal_check_work;
};
/* --------------------------------------------------------------------------
                             Thermal Zone Management
   -------------------------------------------------------------------------- */
static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
{
	acpi_status status = AE_OK;
	unsigned long long tmp;
	if (!tz)
		return -EINVAL;
	tz->last_temperature = tz->temperature;
	status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
	if (ACPI_FAILURE(status))
		return -ENODEV;
	tz->temperature = tmp;
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
			  tz->temperature));
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 69 | 77.53% | 1 | 25.00% | 
| Matthew Wilcox | 12 | 13.48% | 1 | 25.00% | 
| Patrick Mochel | 8 | 8.99% | 2 | 50.00% | 
| Total | 89 | 100.00% | 4 | 100.00% | 
static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
{
	acpi_status status = AE_OK;
	unsigned long long tmp;
	if (!tz)
		return -EINVAL;
	status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
	if (ACPI_FAILURE(status))
		return -ENODEV;
	tz->polling_frequency = tmp;
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
			  tz->polling_frequency));
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 61 | 75.31% | 1 | 25.00% | 
| Matthew Wilcox | 12 | 14.81% | 1 | 25.00% | 
| Patrick Mochel | 8 | 9.88% | 2 | 50.00% | 
| Total | 81 | 100.00% | 4 | 100.00% | 
static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
{
	if (!tz)
		return -EINVAL;
	if (!acpi_has_method(tz->device->handle, "_SCP")) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
		return -ENODEV;
	} else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
							   "_SCP", mode))) {
		return -ENODEV;
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 52 | 65.00% | 1 | 25.00% | 
| Jiang Liu | 18 | 22.50% | 1 | 25.00% | 
| Patrick Mochel | 10 | 12.50% | 2 | 50.00% | 
| Total | 80 | 100.00% | 4 | 100.00% | 
#define ACPI_TRIPS_CRITICAL	0x01
#define ACPI_TRIPS_HOT		0x02
#define ACPI_TRIPS_PASSIVE	0x04
#define ACPI_TRIPS_ACTIVE	0x08
#define ACPI_TRIPS_DEVICES	0x10
#define ACPI_TRIPS_REFRESH_THRESHOLDS	(ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
#define ACPI_TRIPS_REFRESH_DEVICES	ACPI_TRIPS_DEVICES
#define ACPI_TRIPS_INIT      (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
                              ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE |  \
                              ACPI_TRIPS_DEVICES)
/*
 * This exception is thrown out in two cases:
 * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
 *   when re-evaluating the AML code.
 * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
 *   We need to re-bind the cooling devices of a thermal zone when this occurs.
 */
#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str)	\
do {    \
        if (flags != ACPI_TRIPS_INIT)   \
                ACPI_EXCEPTION((AE_INFO, AE_ERROR,      \
                "ACPI thermal trip point %s changed\n"  \
                "Please send acpidump to linux-acpi@vger.kernel.org", str)); \
} while (0)
static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
{
	acpi_status status = AE_OK;
	unsigned long long tmp;
	struct acpi_handle_list devices;
	int valid = 0;
	int i;
	/* Critical Shutdown */
	if (flag & ACPI_TRIPS_CRITICAL) {
		status = acpi_evaluate_integer(tz->device->handle,
				"_CRT", NULL, &tmp);
		tz->trips.critical.temperature = tmp;
		/*
                 * Treat freezing temperatures as invalid as well; some
                 * BIOSes return really low values and cause reboots at startup.
                 * Below zero (Celsius) values clearly aren't right for sure..
                 * ... so lets discard those as invalid.
                 */
		if (ACPI_FAILURE(status)) {
			tz->trips.critical.flags.valid = 0;
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "No critical threshold\n"));
		} else if (tmp <= 2732) {
			pr_warn(FW_BUG "Invalid critical threshold (%llu)\n",
				tmp);
			tz->trips.critical.flags.valid = 0;
		} else {
			tz->trips.critical.flags.valid = 1;
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "Found critical threshold [%lu]\n",
					  tz->trips.critical.temperature));
		}
		if (tz->trips.critical.flags.valid == 1) {
			if (crt == -1) {
				tz->trips.critical.flags.valid = 0;
			} else if (crt > 0) {
				unsigned long crt_k = CELSIUS_TO_DECI_KELVIN(crt);
				/*
                                 * Allow override critical threshold
                                 */
				if (crt_k > tz->trips.critical.temperature)
					pr_warn(PREFIX "Critical threshold %d C\n",
						crt);
				tz->trips.critical.temperature = crt_k;
			}
		}
	}
	/* Critical Sleep (optional) */
	if (flag & ACPI_TRIPS_HOT) {
		status = acpi_evaluate_integer(tz->device->handle,
				"_HOT", NULL, &tmp);
		if (ACPI_FAILURE(status)) {
			tz->trips.hot.flags.valid = 0;
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					"No hot threshold\n"));
		} else {
			tz->trips.hot.temperature = tmp;
			tz->trips.hot.flags.valid = 1;
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					"Found hot threshold [%lu]\n",
					tz->trips.hot.temperature));
		}
	}
	/* Passive (optional) */
	if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
		(flag == ACPI_TRIPS_INIT)) {
		valid = tz->trips.passive.flags.valid;
		if (psv == -1) {
			status = AE_SUPPORT;
		} else if (psv > 0) {
			tmp = CELSIUS_TO_DECI_KELVIN(psv);
			status = AE_OK;
		} else {
			status = acpi_evaluate_integer(tz->device->handle,
				"_PSV", NULL, &tmp);
		}
		if (ACPI_FAILURE(status))
			tz->trips.passive.flags.valid = 0;
		else {
			tz->trips.passive.temperature = tmp;
			tz->trips.passive.flags.valid = 1;
			if (flag == ACPI_TRIPS_INIT) {
				status = acpi_evaluate_integer(
						tz->device->handle, "_TC1",
						NULL, &tmp);
				if (ACPI_FAILURE(status))
					tz->trips.passive.flags.valid = 0;
				else
					tz->trips.passive.tc1 = tmp;
				status = acpi_evaluate_integer(
						tz->device->handle, "_TC2",
						NULL, &tmp);
				if (ACPI_FAILURE(status))
					tz->trips.passive.flags.valid = 0;
				else
					tz->trips.passive.tc2 = tmp;
				status = acpi_evaluate_integer(
						tz->device->handle, "_TSP",
						NULL, &tmp);
				if (ACPI_FAILURE(status))
					tz->trips.passive.flags.valid = 0;
				else
					tz->trips.passive.tsp = tmp;
			}
		}
	}
	if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
		memset(&devices, 0, sizeof(struct acpi_handle_list));
		status = acpi_evaluate_reference(tz->device->handle, "_PSL",
							NULL, &devices);
		if (ACPI_FAILURE(status)) {
			pr_warn(PREFIX "Invalid passive threshold\n");
			tz->trips.passive.flags.valid = 0;
		}
		else
			tz->trips.passive.flags.valid = 1;
		if (memcmp(&tz->trips.passive.devices, &devices,
				sizeof(struct acpi_handle_list))) {
			memcpy(&tz->trips.passive.devices, &devices,
				sizeof(struct acpi_handle_list));
			ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
		}
	}
	if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
		if (valid != tz->trips.passive.flags.valid)
				ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
	}
	/* Active (optional) */
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
		char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
		valid = tz->trips.active[i].flags.valid;
		if (act == -1)
			break; /* disable all active trip points */
		if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
			tz->trips.active[i].flags.valid)) {
			status = acpi_evaluate_integer(tz->device->handle,
							name, NULL, &tmp);
			if (ACPI_FAILURE(status)) {
				tz->trips.active[i].flags.valid = 0;
				if (i == 0)
					break;
				if (act <= 0)
					break;
				if (i == 1)
					tz->trips.active[0].temperature =
						CELSIUS_TO_DECI_KELVIN(act);
				else
					/*
                                         * Don't allow override higher than
                                         * the next higher trip point
                                         */
					tz->trips.active[i - 1].temperature =
						(tz->trips.active[i - 2].temperature <
						CELSIUS_TO_DECI_KELVIN(act) ?
						tz->trips.active[i - 2].temperature :
						CELSIUS_TO_DECI_KELVIN(act));
				break;
			} else {
				tz->trips.active[i].temperature = tmp;
				tz->trips.active[i].flags.valid = 1;
			}
		}
		name[2] = 'L';
		if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
			memset(&devices, 0, sizeof(struct acpi_handle_list));
			status = acpi_evaluate_reference(tz->device->handle,
						name, NULL, &devices);
			if (ACPI_FAILURE(status)) {
				pr_warn(PREFIX "Invalid active%d threshold\n",
					i);
				tz->trips.active[i].flags.valid = 0;
			}
			else
				tz->trips.active[i].flags.valid = 1;
			if (memcmp(&tz->trips.active[i].devices, &devices,
					sizeof(struct acpi_handle_list))) {
				memcpy(&tz->trips.active[i].devices, &devices,
					sizeof(struct acpi_handle_list));
				ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
			}
		}
		if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
			if (valid != tz->trips.active[i].flags.valid)
				ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
		if (!tz->trips.active[i].flags.valid)
			break;
	}
	if ((flag & ACPI_TRIPS_DEVICES)
	    && acpi_has_method(tz->device->handle, "_TZD")) {
		memset(&devices, 0, sizeof(devices));
		status = acpi_evaluate_reference(tz->device->handle, "_TZD",
						NULL, &devices);
		if (ACPI_SUCCESS(status)
		    && memcmp(&tz->devices, &devices, sizeof(devices))) {
			tz->devices = devices;
			ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
		}
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 548 | 39.26% | 1 | 5.88% | 
| Rui Zhang | 434 | 31.09% | 3 | 17.65% | 
| Len Brown | 229 | 16.40% | 3 | 17.65% | 
| Matthew Wilcox | 85 | 6.09% | 1 | 5.88% | 
| Thomas Renninger | 26 | 1.86% | 1 | 5.88% | 
| Patrick Mochel | 22 | 1.58% | 2 | 11.76% | 
| Lan Tianyu | 21 | 1.50% | 1 | 5.88% | 
| Andy Shevchenko | 16 | 1.15% | 1 | 5.88% | 
| Arjan van de Ven | 8 | 0.57% | 1 | 5.88% | 
| Rasmus Villemoes | 5 | 0.36% | 1 | 5.88% | 
| Adam Buchbinder | 1 | 0.07% | 1 | 5.88% | 
| Zhihui Zhang | 1 | 0.07% | 1 | 5.88% | 
| Total | 1396 | 100.00% | 17 | 100.00% | 
static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
{
	int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
	if (ret)
		return ret;
	valid = tz->trips.critical.flags.valid |
		tz->trips.hot.flags.valid |
		tz->trips.passive.flags.valid;
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
		valid |= tz->trips.active[i].flags.valid;
	if (!valid) {
		pr_warn(FW_BUG "No valid trip found\n");
		return -ENODEV;
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Thomas Renninger | 91 | 81.25% | 1 | 20.00% | 
| Andy Grover | 14 | 12.50% | 1 | 20.00% | 
| Andy Shevchenko | 3 | 2.68% | 1 | 20.00% | 
| Rui Zhang | 3 | 2.68% | 1 | 20.00% | 
| Patrick Mochel | 1 | 0.89% | 1 | 20.00% | 
| Total | 112 | 100.00% | 5 | 100.00% | 
static void acpi_thermal_check(void *data)
{
	struct acpi_thermal *tz = data;
	if (!tz->tz_enabled)
		return;
	thermal_zone_device_update(tz->thermal_zone,
				   THERMAL_EVENT_UNSPECIFIED);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Matthew Garrett | 18 | 52.94% | 1 | 25.00% | 
| Srinivas Pandruvada | 10 | 29.41% | 2 | 50.00% | 
| Andy Grover | 6 | 17.65% | 1 | 25.00% | 
| Total | 34 | 100.00% | 4 | 100.00% | 
/* sys I/F for generic thermal sysfs support */
static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
{
	struct acpi_thermal *tz = thermal->devdata;
	int result;
	if (!tz)
		return -EINVAL;
	result = acpi_thermal_get_temperature(tz);
	if (result)
		return result;
	*temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(tz->temperature,
							tz->kelvin_offset);
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Matthew Garrett | 32 | 47.76% | 1 | 11.11% | 
| Andy Grover | 13 | 19.40% | 1 | 11.11% | 
| Rui Zhang | 11 | 16.42% | 2 | 22.22% | 
| Jean Delvare | 4 | 5.97% | 1 | 11.11% | 
| Patrick Mochel | 4 | 5.97% | 1 | 11.11% | 
| Aaron Lu | 1 | 1.49% | 1 | 11.11% | 
| Sascha Hauer | 1 | 1.49% | 1 | 11.11% | 
| Kay Sievers | 1 | 1.49% | 1 | 11.11% | 
| Total | 67 | 100.00% | 9 | 100.00% | 
static int thermal_get_mode(struct thermal_zone_device *thermal,
				enum thermal_device_mode *mode)
{
	struct acpi_thermal *tz = thermal->devdata;
	if (!tz)
		return -EINVAL;
	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
		THERMAL_DEVICE_DISABLED;
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 23 | 47.92% | 1 | 20.00% | 
| Matthew Garrett | 12 | 25.00% | 2 | 40.00% | 
| Aristeu Sergio Rozanski Filho | 7 | 14.58% | 1 | 20.00% | 
| Andy Grover | 6 | 12.50% | 1 | 20.00% | 
| Total | 48 | 100.00% | 5 | 100.00% | 
static int thermal_set_mode(struct thermal_zone_device *thermal,
				enum thermal_device_mode mode)
{
	struct acpi_thermal *tz = thermal->devdata;
	int enable;
	if (!tz)
		return -EINVAL;
	/*
         * enable/disable thermal management from ACPI thermal driver
         */
	if (mode == THERMAL_DEVICE_ENABLED)
		enable = 1;
	else if (mode == THERMAL_DEVICE_DISABLED) {
		enable = 0;
		pr_warn("thermal zone will be disabled\n");
	} else
		return -EINVAL;
	if (enable != tz->tz_enabled) {
		tz->tz_enabled = enable;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			"%s kernel ACPI thermal control\n",
			tz->tz_enabled ? "Enable" : "Disable"));
		acpi_thermal_check(tz);
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 73 | 65.77% | 2 | 33.33% | 
| Andy Grover | 18 | 16.22% | 1 | 16.67% | 
| Matthew Garrett | 9 | 8.11% | 1 | 16.67% | 
| Srinivas Pandruvada | 7 | 6.31% | 1 | 16.67% | 
| Aristeu Sergio Rozanski Filho | 4 | 3.60% | 1 | 16.67% | 
| Total | 111 | 100.00% | 6 | 100.00% | 
static int thermal_get_trip_type(struct thermal_zone_device *thermal,
				 int trip, enum thermal_trip_type *type)
{
	struct acpi_thermal *tz = thermal->devdata;
	int i;
	if (!tz || trip < 0)
		return -EINVAL;
	if (tz->trips.critical.flags.valid) {
		if (!trip) {
			*type = THERMAL_TRIP_CRITICAL;
			return 0;
		}
		trip--;
	}
	if (tz->trips.hot.flags.valid) {
		if (!trip) {
			*type = THERMAL_TRIP_HOT;
			return 0;
		}
		trip--;
	}
	if (tz->trips.passive.flags.valid) {
		if (!trip) {
			*type = THERMAL_TRIP_PASSIVE;
			return 0;
		}
		trip--;
	}
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
		tz->trips.active[i].flags.valid; i++) {
		if (!trip) {
			*type = THERMAL_TRIP_ACTIVE;
			return 0;
		}
		trip--;
	}
	return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 155 | 81.58% | 1 | 50.00% | 
| Matthew Garrett | 35 | 18.42% | 1 | 50.00% | 
| Total | 190 | 100.00% | 2 | 100.00% | 
static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
				 int trip, int *temp)
{
	struct acpi_thermal *tz = thermal->devdata;
	int i;
	if (!tz || trip < 0)
		return -EINVAL;
	if (tz->trips.critical.flags.valid) {
		if (!trip) {
			*temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
				tz->trips.critical.temperature,
				tz->kelvin_offset);
			return 0;
		}
		trip--;
	}
	if (tz->trips.hot.flags.valid) {
		if (!trip) {
			*temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
				tz->trips.hot.temperature,
				tz->kelvin_offset);
			return 0;
		}
		trip--;
	}
	if (tz->trips.passive.flags.valid) {
		if (!trip) {
			*temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
				tz->trips.passive.temperature,
				tz->kelvin_offset);
			return 0;
		}
		trip--;
	}
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
		tz->trips.active[i].flags.valid; i++) {
		if (!trip) {
			*temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
				tz->trips.active[i].temperature,
				tz->kelvin_offset);
			return 0;
		}
		trip--;
	}
	return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 190 | 77.87% | 1 | 20.00% | 
| Matthew Garrett | 33 | 13.52% | 1 | 20.00% | 
| Jean Delvare | 16 | 6.56% | 1 | 20.00% | 
| Aaron Lu | 4 | 1.64% | 1 | 20.00% | 
| Sascha Hauer | 1 | 0.41% | 1 | 20.00% | 
| Total | 244 | 100.00% | 5 | 100.00% | 
static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
				int *temperature)
{
	struct acpi_thermal *tz = thermal->devdata;
	if (tz->trips.critical.flags.valid) {
		*temperature = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
				tz->trips.critical.temperature,
				tz->kelvin_offset);
		return 0;
	} else
		return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 41 | 64.06% | 1 | 20.00% | 
| Matthew Garrett | 17 | 26.56% | 1 | 20.00% | 
| Jean Delvare | 4 | 6.25% | 1 | 20.00% | 
| Sascha Hauer | 1 | 1.56% | 1 | 20.00% | 
| Aaron Lu | 1 | 1.56% | 1 | 20.00% | 
| Total | 64 | 100.00% | 5 | 100.00% | 
static int thermal_get_trend(struct thermal_zone_device *thermal,
				int trip, enum thermal_trend *trend)
{
	struct acpi_thermal *tz = thermal->devdata;
	enum thermal_trip_type type;
	int i;
	if (thermal_get_trip_type(thermal, trip, &type))
		return -EINVAL;
	if (type == THERMAL_TRIP_ACTIVE) {
		int trip_temp;
		int temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
					tz->temperature, tz->kelvin_offset);
		if (thermal_get_trip_temp(thermal, trip, &trip_temp))
			return -EINVAL;
		if (temp > trip_temp) {
			*trend = THERMAL_TREND_RAISING;
			return 0;
		} else {
			/* Fall back on default trend */
			return -EINVAL;
		}
	}
	/*
         * tz->temperature has already been updated by generic thermal layer,
         * before this callback being invoked
         */
	i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
		+ (tz->trips.passive.tc2
		* (tz->temperature - tz->trips.passive.temperature));
	if (i > 0)
		*trend = THERMAL_TREND_RAISING;
	else if (i < 0)
		*trend = THERMAL_TREND_DROPPING;
	else
		*trend = THERMAL_TREND_STABLE;
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 192 | 98.46% | 3 | 60.00% | 
| Sascha Hauer | 2 | 1.03% | 1 | 20.00% | 
| Aaron Lu | 1 | 0.51% | 1 | 20.00% | 
| Total | 195 | 100.00% | 5 | 100.00% | 
static int thermal_notify(struct thermal_zone_device *thermal, int trip,
			   enum thermal_trip_type trip_type)
{
	u8 type = 0;
	struct acpi_thermal *tz = thermal->devdata;
	if (trip_type == THERMAL_TRIP_CRITICAL)
		type = ACPI_THERMAL_NOTIFY_CRITICAL;
	else if (trip_type == THERMAL_TRIP_HOT)
		type = ACPI_THERMAL_NOTIFY_HOT;
	else
		return 0;
	acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
					dev_name(&tz->device->dev), type, 1);
	if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
		return 1;
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Matthew Garrett | 84 | 87.50% | 1 | 33.33% | 
| Rui Zhang | 8 | 8.33% | 1 | 33.33% | 
| Stephen Rothwell | 4 | 4.17% | 1 | 33.33% | 
| Total | 96 | 100.00% | 3 | 100.00% | 
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
					struct thermal_cooling_device *cdev,
					bool bind)
{
	struct acpi_device *device = cdev->devdata;
	struct acpi_thermal *tz = thermal->devdata;
	struct acpi_device *dev;
	acpi_status status;
	acpi_handle handle;
	int i;
	int j;
	int trip = -1;
	int result = 0;
	if (tz->trips.critical.flags.valid)
		trip++;
	if (tz->trips.hot.flags.valid)
		trip++;
	if (tz->trips.passive.flags.valid) {
		trip++;
		for (i = 0; i < tz->trips.passive.devices.count;
		    i++) {
			handle = tz->trips.passive.devices.handles[i];
			status = acpi_bus_get_device(handle, &dev);
			if (ACPI_FAILURE(status) || dev != device)
				continue;
			if (bind)
				result =
					thermal_zone_bind_cooling_device
					(thermal, trip, cdev,
					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
					 THERMAL_WEIGHT_DEFAULT);
			else
				result =
					thermal_zone_unbind_cooling_device
					(thermal, trip, cdev);
			if (result)
				goto failed;
		}
	}
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
		if (!tz->trips.active[i].flags.valid)
			break;
		trip++;
		for (j = 0;
		    j < tz->trips.active[i].devices.count;
		    j++) {
			handle = tz->trips.active[i].devices.handles[j];
			status = acpi_bus_get_device(handle, &dev);
			if (ACPI_FAILURE(status) || dev != device)
				continue;
			if (bind)
				result = thermal_zone_bind_cooling_device
					(thermal, trip, cdev,
					 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
					 THERMAL_WEIGHT_DEFAULT);
			else
				result = thermal_zone_unbind_cooling_device
					(thermal, trip, cdev);
			if (result)
				goto failed;
		}
	}
	for (i = 0; i < tz->devices.count; i++) {
		handle = tz->devices.handles[i];
		status = acpi_bus_get_device(handle, &dev);
		if (ACPI_SUCCESS(status) && (dev == device)) {
			if (bind)
				result = thermal_zone_bind_cooling_device
						(thermal, THERMAL_TRIPS_NONE,
						 cdev, THERMAL_NO_LIMIT,
						 THERMAL_NO_LIMIT,
						 THERMAL_WEIGHT_DEFAULT);
			else
				result = thermal_zone_unbind_cooling_device
						(thermal, THERMAL_TRIPS_NONE,
						 cdev);
			if (result)
				goto failed;
		}
	}
failed:
	return result;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 445 | 98.23% | 3 | 60.00% | 
| Kapileshwar Singh | 6 | 1.32% | 1 | 20.00% | 
| Lan Tianyu | 2 | 0.44% | 1 | 20.00% | 
| Total | 453 | 100.00% | 5 | 100.00% | 
static int
acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
					struct thermal_cooling_device *cdev)
{
	return acpi_thermal_cooling_device_cb(thermal, cdev, true);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 26 | 100.00% | 2 | 100.00% | 
| Total | 26 | 100.00% | 2 | 100.00% | 
static int
acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
					struct thermal_cooling_device *cdev)
{
	return acpi_thermal_cooling_device_cb(thermal, cdev, false);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 26 | 100.00% | 2 | 100.00% | 
| Total | 26 | 100.00% | 2 | 100.00% | 
static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
	.bind = acpi_thermal_bind_cooling_device,
	.unbind	= acpi_thermal_unbind_cooling_device,
	.get_temp = thermal_get_temp,
	.get_mode = thermal_get_mode,
	.set_mode = thermal_set_mode,
	.get_trip_type = thermal_get_trip_type,
	.get_trip_temp = thermal_get_trip_temp,
	.get_crit_temp = thermal_get_crit_temp,
	.get_trend = thermal_get_trend,
	.notify = thermal_notify,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
{
	int trips = 0;
	int result;
	acpi_status status;
	int i;
	if (tz->trips.critical.flags.valid)
		trips++;
	if (tz->trips.hot.flags.valid)
		trips++;
	if (tz->trips.passive.flags.valid)
		trips++;
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
			tz->trips.active[i].flags.valid; i++, trips++);
	if (tz->trips.passive.flags.valid)
		tz->thermal_zone =
			thermal_zone_device_register("acpitz", trips, 0, tz,
						&acpi_thermal_zone_ops, NULL,
						     tz->trips.passive.tsp*100,
						     tz->polling_frequency*100);
	else
		tz->thermal_zone =
			thermal_zone_device_register("acpitz", trips, 0, tz,
						&acpi_thermal_zone_ops, NULL,
						0, tz->polling_frequency*100);
	if (IS_ERR(tz->thermal_zone))
		return -ENODEV;
	result = sysfs_create_link(&tz->device->dev.kobj,
				   &tz->thermal_zone->device.kobj, "thermal_zone");
	if (result)
		return result;
	result = sysfs_create_link(&tz->thermal_zone->device.kobj,
				   &tz->device->dev.kobj, "device");
	if (result)
		return result;
	status =  acpi_bus_attach_private_data(tz->device->handle,
					       tz->thermal_zone);
	if (ACPI_FAILURE(status))
		return -ENODEV;
	tz->tz_enabled = 1;
	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
		 tz->thermal_zone->id);
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 196 | 63.84% | 3 | 27.27% | 
| Matthew Garrett | 53 | 17.26% | 2 | 18.18% | 
| Andy Grover | 32 | 10.42% | 1 | 9.09% | 
| Greg Kroah-Hartman | 14 | 4.56% | 1 | 9.09% | 
| Durgadoss R | 8 | 2.61% | 2 | 18.18% | 
| Krzysztof Helt | 3 | 0.98% | 1 | 9.09% | 
| Lan Tianyu | 1 | 0.33% | 1 | 9.09% | 
| Total | 307 | 100.00% | 11 | 100.00% | 
static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
{
	sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
	sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
	thermal_zone_device_unregister(tz->thermal_zone);
	tz->thermal_zone = NULL;
	acpi_bus_detach_private_data(tz->device->handle);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 44 | 72.13% | 2 | 40.00% | 
| Andy Grover | 11 | 18.03% | 1 | 20.00% | 
| Alexey Y. Starikovskiy | 5 | 8.20% | 1 | 20.00% | 
| Lan Tianyu | 1 | 1.64% | 1 | 20.00% | 
| Total | 61 | 100.00% | 5 | 100.00% | 
/* --------------------------------------------------------------------------
                                 Driver Interface
   -------------------------------------------------------------------------- */
static void acpi_thermal_notify(struct acpi_device *device, u32 event)
{
	struct acpi_thermal *tz = acpi_driver_data(device);
	if (!tz)
		return;
	switch (event) {
	case ACPI_THERMAL_NOTIFY_TEMPERATURE:
		acpi_thermal_check(tz);
		break;
	case ACPI_THERMAL_NOTIFY_THRESHOLDS:
		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
		acpi_thermal_check(tz);
		acpi_bus_generate_netlink_event(device->pnp.device_class,
						  dev_name(&device->dev), event, 0);
		break;
	case ACPI_THERMAL_NOTIFY_DEVICES:
		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
		acpi_thermal_check(tz);
		acpi_bus_generate_netlink_event(device->pnp.device_class,
						  dev_name(&device->dev), event, 0);
		break;
	default:
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Unsupported event [0x%x]\n", event));
		break;
	}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 87 | 65.91% | 1 | 12.50% | 
| Rui Zhang | 32 | 24.24% | 3 | 37.50% | 
| Kay Sievers | 8 | 6.06% | 1 | 12.50% | 
| Björn Helgaas | 3 | 2.27% | 1 | 12.50% | 
| Patrick Mochel | 1 | 0.76% | 1 | 12.50% | 
| Aristeu Sergio Rozanski Filho | 1 | 0.76% | 1 | 12.50% | 
| Total | 132 | 100.00% | 8 | 100.00% | 
/*
 * On some platforms, the AML code has dependency about
 * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx.
 * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after
 *    /_CRT/_HOT/_PSV/_ACx, or else system will be power off.
 * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0
 *    if _TMP has never been evaluated.
 *
 * As this dependency is totally transparent to OS, evaluate
 * all of them once, in the order of _CRT/_HOT/_PSV/_ACx,
 * _TMP, before they are actually used.
 */
static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
{
	acpi_handle handle = tz->device->handle;
	unsigned long long value;
	int i;
	acpi_evaluate_integer(handle, "_CRT", NULL, &value);
	acpi_evaluate_integer(handle, "_HOT", NULL, &value);
	acpi_evaluate_integer(handle, "_PSV", NULL, &value);
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
		char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
		acpi_status status;
		status = acpi_evaluate_integer(handle, name, NULL, &value);
		if (status == AE_NOT_FOUND)
			break;
	}
	acpi_evaluate_integer(handle, "_TMP", NULL, &value);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 137 | 100.00% | 1 | 100.00% | 
| Total | 137 | 100.00% | 1 | 100.00% | 
static int acpi_thermal_get_info(struct acpi_thermal *tz)
{
	int result = 0;
	if (!tz)
		return -EINVAL;
	acpi_thermal_aml_dependency_fix(tz);
	/* Get trip points [_CRT, _PSV, etc.] (required) */
	result = acpi_thermal_get_trip_points(tz);
	if (result)
		return result;
	/* Get temperature [_TMP] (required) */
	result = acpi_thermal_get_temperature(tz);
	if (result)
		return result;
	/* Set the cooling mode [_SCP] to active cooling (default) */
	result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
	if (!result)
		tz->flags.cooling_mode = 1;
	/* Get default polling frequency [_TZP] (optional) */
	if (tzp)
		tz->polling_frequency = tzp;
	else
		acpi_thermal_get_polling_frequency(tz);
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 75 | 72.82% | 2 | 33.33% | 
| Len Brown | 11 | 10.68% | 1 | 16.67% | 
| Patrick Mochel | 8 | 7.77% | 1 | 16.67% | 
| Rui Zhang | 5 | 4.85% | 1 | 16.67% | 
| Matthew Garrett | 4 | 3.88% | 1 | 16.67% | 
| Total | 103 | 100.00% | 6 | 100.00% | 
/*
 * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI
 * handles temperature values with a single decimal place. As a consequence,
 * some implementations use an offset of 273.1 and others use an offset of
 * 273.2. Try to find out which one is being used, to present the most
 * accurate and visually appealing number.
 *
 * The heuristic below should work for all ACPI thermal zones which have a
 * critical trip point with a value being a multiple of 0.5 degree Celsius.
 */
static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
{
	if (tz->trips.critical.flags.valid &&
	    (tz->trips.critical.temperature % 5) == 1)
		tz->kelvin_offset = 2731;
	else
		tz->kelvin_offset = 2732;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Jean Delvare | 50 | 100.00% | 1 | 100.00% | 
| Total | 50 | 100.00% | 1 | 100.00% | 
static void acpi_thermal_check_fn(struct work_struct *work)
{
	struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
					       thermal_check_work);
	acpi_thermal_check(tz);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Aaron Lu | 31 | 100.00% | 1 | 100.00% | 
| Total | 31 | 100.00% | 1 | 100.00% | 
static int acpi_thermal_add(struct acpi_device *device)
{
	int result = 0;
	struct acpi_thermal *tz = NULL;
	if (!device)
		return -EINVAL;
	tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
	if (!tz)
		return -ENOMEM;
	tz->device = device;
	strcpy(tz->name, device->pnp.bus_id);
	strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
	device->driver_data = tz;
	result = acpi_thermal_get_info(tz);
	if (result)
		goto free_memory;
	acpi_thermal_guess_offset(tz);
	result = acpi_thermal_register_thermal_zone(tz);
	if (result)
		goto free_memory;
	INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
	pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
		acpi_device_bid(device), DECI_KELVIN_TO_CELSIUS(tz->temperature));
	goto end;
free_memory:
	kfree(tz);
end:
	return result;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 111 | 61.67% | 2 | 16.67% | 
| Rui Zhang | 21 | 11.67% | 1 | 8.33% | 
| Andy Shevchenko | 16 | 8.89% | 1 | 8.33% | 
| Patrick Mochel | 10 | 5.56% | 2 | 16.67% | 
| Aaron Lu | 10 | 5.56% | 1 | 8.33% | 
| Jean Delvare | 5 | 2.78% | 1 | 8.33% | 
| Andrew Morton | 3 | 1.67% | 1 | 8.33% | 
| Pavel Machek | 2 | 1.11% | 1 | 8.33% | 
| Burman Yan | 1 | 0.56% | 1 | 8.33% | 
| Rasmus Villemoes | 1 | 0.56% | 1 | 8.33% | 
| Total | 180 | 100.00% | 12 | 100.00% | 
static int acpi_thermal_remove(struct acpi_device *device)
{
	struct acpi_thermal *tz = NULL;
	if (!device || !acpi_driver_data(device))
		return -EINVAL;
	flush_workqueue(acpi_thermal_pm_queue);
	tz = acpi_driver_data(device);
	acpi_thermal_unregister_thermal_zone(tz);
	kfree(tz);
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 39 | 67.24% | 1 | 20.00% | 
| Aaron Lu | 5 | 8.62% | 1 | 20.00% | 
| Rui Zhang | 5 | 8.62% | 1 | 20.00% | 
| Len Brown | 5 | 8.62% | 1 | 20.00% | 
| Patrick Mochel | 4 | 6.90% | 1 | 20.00% | 
| Total | 58 | 100.00% | 5 | 100.00% | 
#ifdef CONFIG_PM_SLEEP
static int acpi_thermal_suspend(struct device *dev)
{
	/* Make sure the previously queued thermal check work has been done */
	flush_workqueue(acpi_thermal_pm_queue);
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Aaron Lu | 20 | 100.00% | 1 | 100.00% | 
| Total | 20 | 100.00% | 1 | 100.00% | 
static int acpi_thermal_resume(struct device *dev)
{
	struct acpi_thermal *tz;
	int i, j, power_state, result;
	if (!dev)
		return -EINVAL;
	tz = acpi_driver_data(to_acpi_device(dev));
	if (!tz)
		return -EINVAL;
	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
		if (!(&tz->trips.active[i]))
			break;
		if (!tz->trips.active[i].flags.valid)
			break;
		tz->trips.active[i].flags.enabled = 1;
		for (j = 0; j < tz->trips.active[i].devices.count; j++) {
			result = acpi_bus_update_power(
					tz->trips.active[i].devices.handles[j],
					&power_state);
			if (result || (power_state != ACPI_STATE_D0)) {
				tz->trips.active[i].flags.enabled = 0;
				break;
			}
		}
		tz->state.active |= tz->trips.active[i].flags.enabled;
	}
	queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
	return AE_OK;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Konstantin Karasyov | 201 | 88.94% | 3 | 42.86% | 
| Rafael J. Wysocki | 17 | 7.52% | 2 | 28.57% | 
| Aaron Lu | 6 | 2.65% | 1 | 14.29% | 
| Patrick Mochel | 2 | 0.88% | 1 | 14.29% | 
| Total | 226 | 100.00% | 7 | 100.00% | 
#endif
static int thermal_act(const struct dmi_system_id *d) {
	if (act == 0) {
		pr_notice(PREFIX "%s detected: "
			  "disabling all active thermal trip points\n", d->ident);
		act = -1;
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Len Brown | 35 | 89.74% | 1 | 33.33% | 
| Andy Shevchenko | 3 | 7.69% | 1 | 33.33% | 
| Jeff Garzik | 1 | 2.56% | 1 | 33.33% | 
| Total | 39 | 100.00% | 3 | 100.00% | 
static int thermal_nocrt(const struct dmi_system_id *d) {
	pr_notice(PREFIX "%s detected: "
		  "disabling all critical thermal trip point actions.\n", d->ident);
	nocrt = 1;
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Len Brown | 26 | 86.67% | 1 | 33.33% | 
| Andy Shevchenko | 3 | 10.00% | 1 | 33.33% | 
| Jeff Garzik | 1 | 3.33% | 1 | 33.33% | 
| Total | 30 | 100.00% | 3 | 100.00% | 
static int thermal_tzp(const struct dmi_system_id *d) {
	if (tzp == 0) {
		pr_notice(PREFIX "%s detected: "
			  "enabling thermal zone polling\n", d->ident);
		tzp = 300;	/* 300 dS = 30 Seconds */
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Len Brown | 35 | 89.74% | 1 | 33.33% | 
| Andy Shevchenko | 3 | 7.69% | 1 | 33.33% | 
| Jeff Garzik | 1 | 2.56% | 1 | 33.33% | 
| Total | 39 | 100.00% | 3 | 100.00% | 
static int thermal_psv(const struct dmi_system_id *d) {
	if (psv == 0) {
		pr_notice(PREFIX "%s detected: "
			  "disabling all passive thermal trip points\n", d->ident);
		psv = -1;
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Len Brown | 35 | 89.74% | 1 | 33.33% | 
| Andy Shevchenko | 3 | 7.69% | 1 | 33.33% | 
| Jeff Garzik | 1 | 2.56% | 1 | 33.33% | 
| Total | 39 | 100.00% | 3 | 100.00% | 
static struct dmi_system_id thermal_dmi_table[] __initdata = {
	/*
         * Award BIOS on this AOpen makes thermal control almost worthless.
         * http://bugzilla.kernel.org/show_bug.cgi?id=8842
         */
	{
	 .callback = thermal_act,
	 .ident = "AOpen i915GMm-HFS",
	 .matches = {
		DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
		DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
                },
        },
	{
	 .callback = thermal_psv,
	 .ident = "AOpen i915GMm-HFS",
	 .matches = {
		DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
		DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
                },
        },
	{
	 .callback = thermal_tzp,
	 .ident = "AOpen i915GMm-HFS",
	 .matches = {
		DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
		DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
                },
        },
	{
	 .callback = thermal_nocrt,
	 .ident = "Gigabyte GA-7ZX",
	 .matches = {
		DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
		DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
                },
        },
	{}
};
static int __init acpi_thermal_init(void)
{
	int result = 0;
	dmi_check_system(thermal_dmi_table);
	if (off) {
		pr_notice(PREFIX "thermal control disabled\n");
		return -ENODEV;
	}
	acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
						WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
	if (!acpi_thermal_pm_queue)
		return -ENODEV;
	result = acpi_bus_register_driver(&acpi_thermal_driver);
	if (result < 0) {
		destroy_workqueue(acpi_thermal_pm_queue);
		return -ENODEV;
	}
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 31 | 36.47% | 2 | 25.00% | 
| Aaron Lu | 22 | 25.88% | 1 | 12.50% | 
| Len Brown | 18 | 21.18% | 2 | 25.00% | 
| Bhaktipriya Shridhar | 7 | 8.24% | 1 | 12.50% | 
| Patrick Mochel | 4 | 4.71% | 1 | 12.50% | 
| Andy Shevchenko | 3 | 3.53% | 1 | 12.50% | 
| Total | 85 | 100.00% | 8 | 100.00% | 
static void __exit acpi_thermal_exit(void)
{
	acpi_bus_unregister_driver(&acpi_thermal_driver);
	destroy_workqueue(acpi_thermal_pm_queue);
	return;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Grover | 15 | 71.43% | 1 | 33.33% | 
| Aaron Lu | 5 | 23.81% | 1 | 33.33% | 
| Patrick Mochel | 1 | 4.76% | 1 | 33.33% | 
| Total | 21 | 100.00% | 3 | 100.00% | 
module_init(acpi_thermal_init);
module_exit(acpi_thermal_exit);
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rui Zhang | 2176 | 37.84% | 18 | 18.37% | 
| Andy Grover | 1518 | 26.40% | 5 | 5.10% | 
| Len Brown | 652 | 11.34% | 17 | 17.35% | 
| Matthew Garrett | 303 | 5.27% | 4 | 4.08% | 
| Konstantin Karasyov | 203 | 3.53% | 3 | 3.06% | 
| Thomas Renninger | 146 | 2.54% | 3 | 3.06% | 
| Aaron Lu | 134 | 2.33% | 3 | 3.06% | 
| Patrick Mochel | 120 | 2.09% | 4 | 4.08% | 
| Matthew Wilcox | 109 | 1.90% | 1 | 1.02% | 
| Jean Delvare | 83 | 1.44% | 1 | 1.02% | 
| Rafael J. Wysocki | 54 | 0.94% | 3 | 3.06% | 
| Andy Shevchenko | 50 | 0.87% | 1 | 1.02% | 
| Lan Tianyu | 25 | 0.43% | 3 | 3.06% | 
| Jiang Liu | 18 | 0.31% | 1 | 1.02% | 
| Björn Helgaas | 18 | 0.31% | 1 | 1.02% | 
| Srinivas Pandruvada | 17 | 0.30% | 3 | 3.06% | 
| Aristeu Sergio Rozanski Filho | 15 | 0.26% | 1 | 1.02% | 
| Greg Kroah-Hartman | 14 | 0.24% | 1 | 1.02% | 
| Kay Sievers | 9 | 0.16% | 1 | 1.02% | 
| Durgadoss R | 8 | 0.14% | 2 | 2.04% | 
| Arjan van de Ven | 8 | 0.14% | 1 | 1.02% | 
| Bhaktipriya Shridhar | 7 | 0.12% | 1 | 1.02% | 
| Stephen Rothwell | 7 | 0.12% | 1 | 1.02% | 
| Rasmus Villemoes | 6 | 0.10% | 1 | 1.02% | 
| Shuah Khan | 6 | 0.10% | 1 | 1.02% | 
| Kapileshwar Singh | 6 | 0.10% | 1 | 1.02% | 
| Sascha Hauer | 5 | 0.09% | 1 | 1.02% | 
| Alexey Y. Starikovskiy | 5 | 0.09% | 1 | 1.02% | 
| Jeff Garzik | 4 | 0.07% | 1 | 1.02% | 
| Krzysztof Helt | 3 | 0.05% | 1 | 1.02% | 
| Tejun Heo | 3 | 0.05% | 1 | 1.02% | 
| Rusty Russell | 3 | 0.05% | 1 | 1.02% | 
| Andrew Morton | 3 | 0.05% | 1 | 1.02% | 
| Jeremy Fitzhardinge | 3 | 0.05% | 1 | 1.02% | 
| Pavel Machek | 2 | 0.03% | 1 | 1.02% | 
| Burman Yan | 1 | 0.02% | 1 | 1.02% | 
| Adam Buchbinder | 1 | 0.02% | 1 | 1.02% | 
| Lv Zheng | 1 | 0.02% | 1 | 1.02% | 
| Jarkko Nikula | 1 | 0.02% | 1 | 1.02% | 
| Zhihui Zhang | 1 | 0.02% | 1 | 1.02% | 
| Linus Torvalds | 1 | 0.02% | 1 | 1.02% | 
| Colin Ian King | 1 | 0.02% | 1 | 1.02% | 
| Total | 5750 | 100.00% | 98 | 100.00% | 
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.