From ee073604dba4787b30a754a63af16d13f3d9b846 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 2 Mar 2015 13:12:58 -0800 Subject: Thermal: Intel SoC: DTS thermal IOSF core This is becoming a common feature for Intel SoCs to expose the additional digital temperature sensors (DTSs) using side band interface (IOSF). This change remove common IOSF DTS handler function from the existing driver intel_soc_dts_thermal.c and creates a stand alone module, which can be selected from the SoC specific drivers. In this way there is less code duplication. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 10 + drivers/thermal/Makefile | 1 + drivers/thermal/intel_soc_dts_iosf.c | 483 +++++++++++++++++++++++++++++++++++ drivers/thermal/intel_soc_dts_iosf.h | 62 +++++ 4 files changed, 556 insertions(+) create mode 100644 drivers/thermal/intel_soc_dts_iosf.c create mode 100644 drivers/thermal/intel_soc_dts_iosf.h diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index af40db0df58e..effc46d6b070 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -249,6 +249,16 @@ config X86_PKG_TEMP_THERMAL two trip points which can be set by user to get notifications via thermal notification methods. +config INTEL_SOC_DTS_IOSF_CORE + tristate + depends on X86 + select IOSF_MBI + help + This is becoming a common feature for Intel SoCs to expose the additional + digital temperature sensors (DTSs) using side band interface (IOSF). This + implements the common set of helper functions to register, get temperature + and get/set thresholds on DTSs. + config INTEL_SOC_DTS_THERMAL tristate "Intel SoCs DTS thermal driver" depends on X86 && IOSF_MBI diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index fa0dc486790f..166d603ebf7e 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o +obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ diff --git a/drivers/thermal/intel_soc_dts_iosf.c b/drivers/thermal/intel_soc_dts_iosf.c new file mode 100644 index 000000000000..d89787612c5d --- /dev/null +++ b/drivers/thermal/intel_soc_dts_iosf.c @@ -0,0 +1,483 @@ +/* + * intel_soc_dts_iosf.c + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include "intel_soc_dts_iosf.h" + +#define SOC_DTS_OFFSET_ENABLE 0xB0 +#define SOC_DTS_OFFSET_TEMP 0xB1 + +#define SOC_DTS_OFFSET_PTPS 0xB2 +#define SOC_DTS_OFFSET_PTTS 0xB3 +#define SOC_DTS_OFFSET_PTTSS 0xB4 +#define SOC_DTS_OFFSET_PTMC 0x80 +#define SOC_DTS_TE_AUX0 0xB5 +#define SOC_DTS_TE_AUX1 0xB6 + +#define SOC_DTS_AUX0_ENABLE_BIT BIT(0) +#define SOC_DTS_AUX1_ENABLE_BIT BIT(1) +#define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) +#define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) +#define SOC_DTS_TE_SCI_ENABLE BIT(9) +#define SOC_DTS_TE_SMI_ENABLE BIT(10) +#define SOC_DTS_TE_MSI_ENABLE BIT(11) +#define SOC_DTS_TE_APICA_ENABLE BIT(14) +#define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) + +/* DTS encoding for TJ MAX temperature */ +#define SOC_DTS_TJMAX_ENCODING 0x7F + +/* Only 2 out of 4 is allowed for OSPM */ +#define SOC_MAX_DTS_TRIPS 2 + +/* Mask for two trips in status bits */ +#define SOC_DTS_TRIP_MASK 0x03 + +/* DTS0 and DTS 1 */ +#define SOC_MAX_DTS_SENSORS 2 + +static int get_tj_max(u32 *tj_max) +{ + u32 eax, edx; + u32 val; + int err; + + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + if (err) + goto err_ret; + else { + val = (eax >> 16) & 0xff; + if (val) + *tj_max = val * 1000; + else { + err = -EINVAL; + goto err_ret; + } + } + + return 0; +err_ret: + *tj_max = 0; + + return err; +} + +static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, + unsigned long *temp) +{ + int status; + u32 out; + struct intel_soc_dts_sensor_entry *dts; + struct intel_soc_dts_sensors *sensors; + + dts = tzd->devdata; + sensors = dts->sensors; + mutex_lock(&sensors->dts_update_lock); + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_PTPS, &out); + mutex_unlock(&sensors->dts_update_lock); + if (status) + return status; + + out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING; + if (!out) + *temp = 0; + else + *temp = sensors->tj_max - out * 1000; + + return 0; +} + +static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, + int thres_index, unsigned long temp, + enum thermal_trip_type trip_type) +{ + int status; + u32 temp_out; + u32 out; + u32 store_ptps; + u32 store_ptmc; + u32 store_te_out; + u32 te_out; + u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE; + struct intel_soc_dts_sensors *sensors = dts->sensors; + + if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI) + int_enable_bit |= SOC_DTS_TE_MSI_ENABLE; + + temp_out = (sensors->tj_max - temp) / 1000; + + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_PTPS, &store_ptps); + if (status) + return status; + + out = (store_ptps & ~(0xFF << (thres_index * 8))); + out |= (temp_out & 0xFF) << (thres_index * 8); + status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTPS, out); + if (status) + return status; + + pr_debug("update_trip_temp PTPS = %x\n", out); + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_PTMC, &out); + if (status) + goto err_restore_ptps; + + store_ptmc = out; + + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_TE_AUX0 + thres_index, + &te_out); + if (status) + goto err_restore_ptmc; + + store_te_out = te_out; + /* Enable for CPU module 0 and module 1 */ + out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | + SOC_DTS_CPU_MODULE1_ENABLE_BIT); + if (temp) { + if (thres_index) + out |= SOC_DTS_AUX1_ENABLE_BIT; + else + out |= SOC_DTS_AUX0_ENABLE_BIT; + te_out |= int_enable_bit; + } else { + if (thres_index) + out &= ~SOC_DTS_AUX1_ENABLE_BIT; + else + out &= ~SOC_DTS_AUX0_ENABLE_BIT; + te_out &= ~int_enable_bit; + } + status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTMC, out); + if (status) + goto err_restore_te_out; + + status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_TE_AUX0 + thres_index, + te_out); + if (status) + goto err_restore_te_out; + + dts->trip_types[thres_index] = trip_type; + + return 0; +err_restore_te_out: + iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTMC, store_te_out); +err_restore_ptmc: + iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTMC, store_ptmc); +err_restore_ptps: + iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTPS, store_ptps); + /* Nothing we can do if restore fails */ + + return status; +} + +static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, + unsigned long temp) +{ + struct intel_soc_dts_sensor_entry *dts = tzd->devdata; + struct intel_soc_dts_sensors *sensors = dts->sensors; + int status; + + if (temp > sensors->tj_max) + return -EINVAL; + + mutex_lock(&sensors->dts_update_lock); + status = update_trip_temp(tzd->devdata, trip, temp, + dts->trip_types[trip]); + mutex_unlock(&sensors->dts_update_lock); + + return status; +} + +static int sys_get_trip_type(struct thermal_zone_device *tzd, + int trip, enum thermal_trip_type *type) +{ + struct intel_soc_dts_sensor_entry *dts; + + dts = tzd->devdata; + + *type = dts->trip_types[trip]; + + return 0; +} + +static int sys_get_curr_temp(struct thermal_zone_device *tzd, + unsigned long *temp) +{ + int status; + u32 out; + struct intel_soc_dts_sensor_entry *dts; + struct intel_soc_dts_sensors *sensors; + + dts = tzd->devdata; + sensors = dts->sensors; + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_TEMP, &out); + if (status) + return status; + + out = (out & dts->temp_mask) >> dts->temp_shift; + out -= SOC_DTS_TJMAX_ENCODING; + *temp = sensors->tj_max - out * 1000; + + return 0; +} + +static struct thermal_zone_device_ops tzone_ops = { + .get_temp = sys_get_curr_temp, + .get_trip_temp = sys_get_trip_temp, + .get_trip_type = sys_get_trip_type, + .set_trip_temp = sys_set_trip_temp, +}; + +static int soc_dts_enable(int id) +{ + u32 out; + int ret; + + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_ENABLE, &out); + if (ret) + return ret; + + if (!(out & BIT(id))) { + out |= BIT(id); + ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_ENABLE, out); + if (ret) + return ret; + } + + return ret; +} + +static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts) +{ + if (dts) { + iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_ENABLE, dts->store_status); + thermal_zone_device_unregister(dts->tzone); + } +} + +static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, + bool notification_support, int trip_cnt, + int read_only_trip_cnt) +{ + char name[10]; + int trip_count = 0; + int trip_mask = 0; + u32 store_ptps; + int ret; + int i; + + /* Store status to restor on exit */ + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_ENABLE, + &dts->store_status); + if (ret) + goto err_ret; + + dts->id = id; + dts->temp_mask = 0x00FF << (id * 8); + dts->temp_shift = id * 8; + if (notification_support) { + trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt); + trip_mask = BIT(trip_count - read_only_trip_cnt) - 1; + } + + /* Check if the writable trip we provide is not used by BIOS */ + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_PTPS, &store_ptps); + if (ret) + trip_mask = 0; + else { + for (i = 0; i < trip_count; ++i) { + if (trip_mask & BIT(i)) + if (store_ptps & (0xff << (i * 8))) + trip_mask &= ~BIT(i); + } + } + dts->trip_mask = trip_mask; + dts->trip_count = trip_count; + snprintf(name, sizeof(name), "soc_dts%d", id); + dts->tzone = thermal_zone_device_register(name, + trip_count, + trip_mask, + dts, &tzone_ops, + NULL, 0, 0); + if (IS_ERR(dts->tzone)) { + ret = PTR_ERR(dts->tzone); + goto err_ret; + } + + ret = soc_dts_enable(id); + if (ret) + goto err_enable; + + return 0; +err_enable: + thermal_zone_device_unregister(dts->tzone); +err_ret: + return ret; +} + +int intel_soc_dts_iosf_add_read_only_critical_trip( + struct intel_soc_dts_sensors *sensors, int critical_offset) +{ + int i, j; + int ret; + + for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { + for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { + if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { + ret = update_trip_temp(&sensors->soc_dts[i], j, + sensors->tj_max - critical_offset, + THERMAL_TRIP_CRITICAL); + if (ret) + return ret; + + return 0; + } + } + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip); + +void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) +{ + u32 sticky_out; + int status; + u32 ptmc_out; + unsigned long flags; + + spin_lock_irqsave(&sensors->intr_notify_lock, flags); + + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_PTMC, &ptmc_out); + ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; + status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTMC, ptmc_out); + + status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + SOC_DTS_OFFSET_PTTSS, &sticky_out); + pr_debug("status %d PTTSS %x\n", status, sticky_out); + if (sticky_out & SOC_DTS_TRIP_MASK) { + int i; + /* reset sticky bit */ + status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + SOC_DTS_OFFSET_PTTSS, sticky_out); + spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); + + for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { + pr_debug("TZD update for zone %d\n", i); + thermal_zone_device_update(sensors->soc_dts[i].tzone); + } + } else + spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); +} +EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler); + +struct intel_soc_dts_sensors *intel_soc_dts_iosf_init( + enum intel_soc_dts_interrupt_type intr_type, int trip_count, + int read_only_trip_count) +{ + struct intel_soc_dts_sensors *sensors; + bool notification; + u32 tj_max; + int ret; + int i; + + if (!iosf_mbi_available()) + return ERR_PTR(-ENODEV); + + if (!trip_count || read_only_trip_count > trip_count) + return ERR_PTR(-EINVAL); + + if (get_tj_max(&tj_max)) + return ERR_PTR(-EINVAL); + + sensors = kzalloc(sizeof(*sensors), GFP_KERNEL); + if (!sensors) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&sensors->intr_notify_lock); + mutex_init(&sensors->dts_update_lock); + sensors->intr_type = intr_type; + sensors->tj_max = tj_max; + if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE) + notification = false; + else + notification = true; + for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { + sensors->soc_dts[i].sensors = sensors; + ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], + notification, trip_count, + read_only_trip_count); + if (ret) + goto err_free; + } + + for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { + ret = update_trip_temp(&sensors->soc_dts[i], 0, 0, + THERMAL_TRIP_PASSIVE); + if (ret) + goto err_remove_zone; + + ret = update_trip_temp(&sensors->soc_dts[i], 1, 0, + THERMAL_TRIP_PASSIVE); + if (ret) + goto err_remove_zone; + } + + return sensors; +err_remove_zone: + for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) + remove_dts_thermal_zone(&sensors->soc_dts[i]); + +err_free: + kfree(sensors); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init); + +void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) +{ + int i; + + for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { + update_trip_temp(&sensors->soc_dts[i], 0, 0, 0); + update_trip_temp(&sensors->soc_dts[i], 1, 0, 0); + remove_dts_thermal_zone(&sensors->soc_dts[i]); + } + kfree(sensors); +} +EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel_soc_dts_iosf.h b/drivers/thermal/intel_soc_dts_iosf.h new file mode 100644 index 000000000000..625e37bf93dc --- /dev/null +++ b/drivers/thermal/intel_soc_dts_iosf.h @@ -0,0 +1,62 @@ +/* + * intel_soc_dts_iosf.h + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + */ + +#ifndef _INTEL_SOC_DTS_IOSF_CORE_H +#define _INTEL_SOC_DTS_IOSF_CORE_H + +#include + +/* DTS0 and DTS 1 */ +#define SOC_MAX_DTS_SENSORS 2 + +enum intel_soc_dts_interrupt_type { + INTEL_SOC_DTS_INTERRUPT_NONE, + INTEL_SOC_DTS_INTERRUPT_APIC, + INTEL_SOC_DTS_INTERRUPT_MSI, + INTEL_SOC_DTS_INTERRUPT_SCI, + INTEL_SOC_DTS_INTERRUPT_SMI, +}; + +struct intel_soc_dts_sensors; + +struct intel_soc_dts_sensor_entry { + int id; + u32 temp_mask; + u32 temp_shift; + u32 store_status; + u32 trip_mask; + u32 trip_count; + enum thermal_trip_type trip_types[2]; + struct thermal_zone_device *tzone; + struct intel_soc_dts_sensors *sensors; +}; + +struct intel_soc_dts_sensors { + u32 tj_max; + spinlock_t intr_notify_lock; + struct mutex dts_update_lock; + enum intel_soc_dts_interrupt_type intr_type; + struct intel_soc_dts_sensor_entry soc_dts[SOC_MAX_DTS_SENSORS]; +}; + +struct intel_soc_dts_sensors *intel_soc_dts_iosf_init( + enum intel_soc_dts_interrupt_type intr_type, int trip_count, + int read_only_trip_count); +void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors); +void intel_soc_dts_iosf_interrupt_handler( + struct intel_soc_dts_sensors *sensors); +int intel_soc_dts_iosf_add_read_only_critical_trip( + struct intel_soc_dts_sensors *sensors, int critical_offset); +#endif -- cgit v1.2.3 From 3a2419f865a65b2a4cb27f8640376ecb862be0e8 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 2 Mar 2015 13:12:59 -0800 Subject: Thermal: Intel SoC: DTS thermal use common APIs There is no change in functionality but using the common IOSF core APIs. This driver is now just responsible for enumeration and call relevant API to create thermal zone and register critical trip. Also cpuid 0x4c is now handled in the int340x processor thermal driver with the same functionality. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 3 +- drivers/thermal/intel_soc_dts_thermal.c | 430 ++------------------------------ 2 files changed, 23 insertions(+), 410 deletions(-) diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index effc46d6b070..210e1707f31d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -261,7 +261,8 @@ config INTEL_SOC_DTS_IOSF_CORE config INTEL_SOC_DTS_THERMAL tristate "Intel SoCs DTS thermal driver" - depends on X86 && IOSF_MBI + depends on X86 + select INTEL_SOC_DTS_IOSF_CORE help Enable this to register Intel SoCs (e.g. Bay Trail) platform digital temperature sensor (DTS). These SoCs have two additional DTSs in diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index 9013505e43b7..4ebb31a35a64 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c @@ -16,431 +16,54 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include -#include #include -#include - -#define SOC_DTS_OFFSET_ENABLE 0xB0 -#define SOC_DTS_OFFSET_TEMP 0xB1 - -#define SOC_DTS_OFFSET_PTPS 0xB2 -#define SOC_DTS_OFFSET_PTTS 0xB3 -#define SOC_DTS_OFFSET_PTTSS 0xB4 -#define SOC_DTS_OFFSET_PTMC 0x80 -#define SOC_DTS_TE_AUX0 0xB5 -#define SOC_DTS_TE_AUX1 0xB6 - -#define SOC_DTS_AUX0_ENABLE_BIT BIT(0) -#define SOC_DTS_AUX1_ENABLE_BIT BIT(1) -#define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) -#define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) -#define SOC_DTS_TE_SCI_ENABLE BIT(9) -#define SOC_DTS_TE_SMI_ENABLE BIT(10) -#define SOC_DTS_TE_MSI_ENABLE BIT(11) -#define SOC_DTS_TE_APICA_ENABLE BIT(14) -#define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) - -/* DTS encoding for TJ MAX temperature */ -#define SOC_DTS_TJMAX_ENCODING 0x7F - -/* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */ -#define BYT_SOC_DTS_APIC_IRQ 86 - -/* Only 2 out of 4 is allowed for OSPM */ -#define SOC_MAX_DTS_TRIPS 2 - -/* Mask for two trips in status bits */ -#define SOC_DTS_TRIP_MASK 0x03 - -/* DTS0 and DTS 1 */ -#define SOC_MAX_DTS_SENSORS 2 +#include "intel_soc_dts_iosf.h" #define CRITICAL_OFFSET_FROM_TJ_MAX 5000 -struct soc_sensor_entry { - int id; - u32 tj_max; - u32 temp_mask; - u32 temp_shift; - u32 store_status; - struct thermal_zone_device *tzone; -}; - -static struct soc_sensor_entry *soc_dts[SOC_MAX_DTS_SENSORS]; - static int crit_offset = CRITICAL_OFFSET_FROM_TJ_MAX; module_param(crit_offset, int, 0644); MODULE_PARM_DESC(crit_offset, "Critical Temperature offset from tj max in millidegree Celsius."); -static DEFINE_MUTEX(aux_update_mutex); -static spinlock_t intr_notify_lock; -static int soc_dts_thres_irq; - -static int get_tj_max(u32 *tj_max) -{ - u32 eax, edx; - u32 val; - int err; - - err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); - if (err) - goto err_ret; - else { - val = (eax >> 16) & 0xff; - if (val) - *tj_max = val * 1000; - else { - err = -EINVAL; - goto err_ret; - } - } - - return 0; -err_ret: - *tj_max = 0; - - return err; -} - -static int sys_get_trip_temp(struct thermal_zone_device *tzd, - int trip, unsigned long *temp) -{ - int status; - u32 out; - struct soc_sensor_entry *aux_entry; - - aux_entry = tzd->devdata; - - if (!trip) { - /* Just return the critical temp */ - *temp = aux_entry->tj_max - crit_offset; - return 0; - } - - mutex_lock(&aux_update_mutex); - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_PTPS, &out); - mutex_unlock(&aux_update_mutex); - if (status) - return status; - - out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING; - - if (!out) - *temp = 0; - else - *temp = aux_entry->tj_max - out * 1000; - - return 0; -} - -static int update_trip_temp(struct soc_sensor_entry *aux_entry, - int thres_index, unsigned long temp) -{ - int status; - u32 temp_out; - u32 out; - u32 store_ptps; - u32 store_ptmc; - u32 store_te_out; - u32 te_out; - - u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE | - SOC_DTS_TE_MSI_ENABLE; - - temp_out = (aux_entry->tj_max - temp) / 1000; - - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_PTPS, &store_ptps); - if (status) - return status; - - out = (store_ptps & ~(0xFF << (thres_index * 8))); - out |= (temp_out & 0xFF) << (thres_index * 8); - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTPS, out); - if (status) - return status; - pr_debug("update_trip_temp PTPS = %x\n", out); - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_PTMC, &out); - if (status) - goto err_restore_ptps; - - store_ptmc = out; - - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_TE_AUX0 + thres_index, - &te_out); - if (status) - goto err_restore_ptmc; - - store_te_out = te_out; - - /* Enable for CPU module 0 and module 1 */ - out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | - SOC_DTS_CPU_MODULE1_ENABLE_BIT); - if (temp) { - if (thres_index) - out |= SOC_DTS_AUX1_ENABLE_BIT; - else - out |= SOC_DTS_AUX0_ENABLE_BIT; - te_out |= int_enable_bit; - } else { - if (thres_index) - out &= ~SOC_DTS_AUX1_ENABLE_BIT; - else - out &= ~SOC_DTS_AUX0_ENABLE_BIT; - te_out &= ~int_enable_bit; - } - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTMC, out); - if (status) - goto err_restore_te_out; - - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_TE_AUX0 + thres_index, - te_out); - if (status) - goto err_restore_te_out; - - return 0; - -err_restore_te_out: - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTMC, store_te_out); -err_restore_ptmc: - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTMC, store_ptmc); -err_restore_ptps: - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTPS, store_ptps); - /* Nothing we can do if restore fails */ - - return status; -} - -static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, - unsigned long temp) -{ - struct soc_sensor_entry *aux_entry = tzd->devdata; - int status; - - if (temp > (aux_entry->tj_max - crit_offset)) - return -EINVAL; - - mutex_lock(&aux_update_mutex); - status = update_trip_temp(tzd->devdata, trip, temp); - mutex_unlock(&aux_update_mutex); - - return status; -} - -static int sys_get_trip_type(struct thermal_zone_device *thermal, - int trip, enum thermal_trip_type *type) -{ - if (trip) - *type = THERMAL_TRIP_PASSIVE; - else - *type = THERMAL_TRIP_CRITICAL; - - return 0; -} - -static int sys_get_curr_temp(struct thermal_zone_device *tzd, - unsigned long *temp) -{ - int status; - u32 out; - struct soc_sensor_entry *aux_entry; - - aux_entry = tzd->devdata; - - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_TEMP, &out); - if (status) - return status; - - out = (out & aux_entry->temp_mask) >> aux_entry->temp_shift; - out -= SOC_DTS_TJMAX_ENCODING; - *temp = aux_entry->tj_max - out * 1000; - - return 0; -} - -static struct thermal_zone_device_ops tzone_ops = { - .get_temp = sys_get_curr_temp, - .get_trip_temp = sys_get_trip_temp, - .get_trip_type = sys_get_trip_type, - .set_trip_temp = sys_set_trip_temp, -}; - -static void free_soc_dts(struct soc_sensor_entry *aux_entry) -{ - if (aux_entry) { - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_ENABLE, aux_entry->store_status); - thermal_zone_device_unregister(aux_entry->tzone); - kfree(aux_entry); - } -} - -static int soc_dts_enable(int id) -{ - u32 out; - int ret; - - ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_ENABLE, &out); - if (ret) - return ret; - - if (!(out & BIT(id))) { - out |= BIT(id); - ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_ENABLE, out); - if (ret) - return ret; - } - - return ret; -} - -static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max, - bool notification_support) -{ - struct soc_sensor_entry *aux_entry; - char name[10]; - int trip_count = 0; - int trip_mask = 0; - int err; - - aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); - if (!aux_entry) { - err = -ENOMEM; - return ERR_PTR(-ENOMEM); - } - - /* Store status to restor on exit */ - err = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_ENABLE, - &aux_entry->store_status); - if (err) - goto err_ret; - - aux_entry->id = id; - aux_entry->tj_max = tj_max; - aux_entry->temp_mask = 0x00FF << (id * 8); - aux_entry->temp_shift = id * 8; - if (notification_support) { - trip_count = SOC_MAX_DTS_TRIPS; - trip_mask = 0x02; - } - snprintf(name, sizeof(name), "soc_dts%d", id); - aux_entry->tzone = thermal_zone_device_register(name, - trip_count, - trip_mask, - aux_entry, &tzone_ops, - NULL, 0, 0); - if (IS_ERR(aux_entry->tzone)) { - err = PTR_ERR(aux_entry->tzone); - goto err_ret; - } - - err = soc_dts_enable(id); - if (err) - goto err_aux_status; - - return aux_entry; - -err_aux_status: - thermal_zone_device_unregister(aux_entry->tzone); -err_ret: - kfree(aux_entry); - return ERR_PTR(err); -} - -static void proc_thermal_interrupt(void) -{ - u32 sticky_out; - int status; - u32 ptmc_out; - unsigned long flags; - - spin_lock_irqsave(&intr_notify_lock, flags); - - /* Clear APIC interrupt */ - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_PTMC, &ptmc_out); - - ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTMC, ptmc_out); - - /* Read status here */ - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_PTTSS, &sticky_out); - pr_debug("status %d PTTSS %x\n", status, sticky_out); - if (sticky_out & SOC_DTS_TRIP_MASK) { - int i; - /* reset sticky bit */ - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - SOC_DTS_OFFSET_PTTSS, sticky_out); - spin_unlock_irqrestore(&intr_notify_lock, flags); - - for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { - pr_debug("TZD update for zone %d\n", i); - thermal_zone_device_update(soc_dts[i]->tzone); - } - } else - spin_unlock_irqrestore(&intr_notify_lock, flags); +/* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */ +#define BYT_SOC_DTS_APIC_IRQ 86 -} +static int soc_dts_thres_irq; +static struct intel_soc_dts_sensors *soc_dts; static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) { - proc_thermal_interrupt(); pr_debug("proc_thermal_interrupt\n"); + intel_soc_dts_iosf_interrupt_handler(soc_dts); return IRQ_HANDLED; } static const struct x86_cpu_id soc_thermal_ids[] = { { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, - { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x4c, 0, 0}, {} }; MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); static int __init intel_soc_thermal_init(void) { - u32 tj_max; int err = 0; - int i; const struct x86_cpu_id *match_cpu; match_cpu = x86_match_cpu(soc_thermal_ids); if (!match_cpu) return -ENODEV; - if (get_tj_max(&tj_max)) - return -EINVAL; - - soc_dts_thres_irq = (int)match_cpu->driver_data; - - for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { - soc_dts[i] = alloc_soc_dts(i, tj_max, - soc_dts_thres_irq ? true : false); - if (IS_ERR(soc_dts[i])) { - err = PTR_ERR(soc_dts[i]); - goto err_free; - } + /* Create a zone with 2 trips with marked as read only */ + soc_dts = intel_soc_dts_iosf_init(INTEL_SOC_DTS_INTERRUPT_APIC, 2, 1); + if (IS_ERR(soc_dts)) { + err = PTR_ERR(soc_dts); + return err; } - spin_lock_init(&intr_notify_lock); + soc_dts_thres_irq = (int)match_cpu->driver_data; if (soc_dts_thres_irq) { err = request_threaded_irq(soc_dts_thres_irq, NULL, @@ -449,42 +72,31 @@ static int __init intel_soc_thermal_init(void) "soc_dts", soc_dts); if (err) { pr_err("request_threaded_irq ret %d\n", err); - goto err_free; + goto error_irq; } } - for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { - err = update_trip_temp(soc_dts[i], 0, tj_max - crit_offset); - if (err) - goto err_trip_temp; - } + err = intel_soc_dts_iosf_add_read_only_critical_trip(soc_dts, + crit_offset); + if (err) + goto error_trips; return 0; -err_trip_temp: - i = SOC_MAX_DTS_SENSORS; +error_trips: if (soc_dts_thres_irq) free_irq(soc_dts_thres_irq, soc_dts); -err_free: - while (--i >= 0) - free_soc_dts(soc_dts[i]); +error_irq: + intel_soc_dts_iosf_exit(soc_dts); return err; } static void __exit intel_soc_thermal_exit(void) { - int i; - - for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) - update_trip_temp(soc_dts[i], 0, 0); - if (soc_dts_thres_irq) free_irq(soc_dts_thres_irq, soc_dts); - - for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) - free_soc_dts(soc_dts[i]); - + intel_soc_dts_iosf_exit(soc_dts); } module_init(intel_soc_thermal_init) -- cgit v1.2.3 From 4d0dd6c1576b6e42524b330dbc4188f050febf7a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 2 Mar 2015 13:13:00 -0800 Subject: Thermal/int340x/processor_thermal: Enable auxiliary DTS for Braswell Support two auxiliary DTS present on Braswell platform using side band IOSF interface. This supports two read write trips, which can be used to get notification on trip violation. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 1 + .../int340x_thermal/processor_thermal_device.c | 55 +++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 210e1707f31d..56922373806e 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -278,6 +278,7 @@ config INT340X_THERMAL select THERMAL_GOV_USER_SPACE select ACPI_THERMAL_REL select ACPI_FAN + select INTEL_SOC_DTS_IOSF_CORE help Newer laptops and tablets that use ACPI may have thermal sensors and other devices with thermal control capabilities outside the core diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 5e8d8e91ea6d..e9f1b729fe9c 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include "int340x_thermal_zone.h" +#include "../intel_soc_dts_iosf.h" /* Broadwell-U/HSB thermal reporting device */ #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 @@ -42,6 +44,7 @@ struct proc_thermal_device { struct acpi_device *adev; struct power_config power_limits[2]; struct int34x_thermal_zone *int340x_zone; + struct intel_soc_dts_sensors *soc_dts; }; enum proc_thermal_emum_mode_type { @@ -308,6 +311,18 @@ static int int3401_remove(struct platform_device *pdev) return 0; } +static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) +{ + struct proc_thermal_device *proc_priv; + struct pci_dev *pdev = devid; + + proc_priv = pci_get_drvdata(pdev); + + intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts); + + return IRQ_HANDLED; +} + static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *unused) { @@ -334,12 +349,50 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, proc_priv); proc_thermal_emum_mode = PROC_THERMAL_PCI; + if (pdev->device == PCI_DEVICE_ID_PROC_BSW_THERMAL) { + /* + * Enumerate additional DTS sensors available via IOSF. + * But we are not treating as a failure condition, if + * there are no aux DTSs enabled or fails. This driver + * already exposes sensors, which can be accessed via + * ACPI/MSR. So we don't want to fail for auxiliary DTSs. + */ + proc_priv->soc_dts = intel_soc_dts_iosf_init( + INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0); + + if (proc_priv->soc_dts && pdev->irq) { + ret = pci_enable_msi(pdev); + if (!ret) { + ret = request_threaded_irq(pdev->irq, NULL, + proc_thermal_pci_msi_irq, + IRQF_ONESHOT, "proc_thermal", + pdev); + if (ret) { + intel_soc_dts_iosf_exit( + proc_priv->soc_dts); + pci_disable_msi(pdev); + proc_priv->soc_dts = NULL; + } + } + } else + dev_err(&pdev->dev, "No auxiliary DTSs enabled\n"); + } + return 0; } static void proc_thermal_pci_remove(struct pci_dev *pdev) { - proc_thermal_remove(pci_get_drvdata(pdev)); + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); + + if (proc_priv->soc_dts) { + intel_soc_dts_iosf_exit(proc_priv->soc_dts); + if (pdev->irq) { + free_irq(pdev->irq, pdev); + pci_disable_msi(pdev); + } + } + proc_thermal_remove(proc_priv); pci_disable_device(pdev); } -- cgit v1.2.3 From 8c1876939663191b5044807230fa295f35462215 Mon Sep 17 00:00:00 2001 From: "Ong, Boon Leong" Date: Wed, 15 Apr 2015 10:08:15 +0800 Subject: thermal: intel Quark SoC X1000 DTS thermal driver In Intel Quark SoC X1000, there is one on-die digital temperature sensor(DTS). The DTS offers both hot & critical trip points. However, in current distribution of UEFI BIOS for Quark platform, only critical trip point is configured to be 105 degree Celsius (based on Quark SW ver1.0.1 and hot trip point is not used due to lack of IRQ. There is no active cooling device for Quark SoC, so Quark SoC thermal management logic expects Linux distro to orderly power-off when temperature of the DTS exceeds the configured critical trip point. Kernel param "polling_delay" in milliseconds is used to control the frequency the DTS temperature is read by thermal framework. It defaults to 2-second. To change it, use kernel boot param "intel_quark_dts_thermal.polling_delay=X". User interacts with Quark SoC DTS thermal driver through sysfs via: /sys/class/thermal/thermal_zone0/ For example: - to read DTS temperature $ cat temp - to read critical trip point $ cat trip_point_0_temp - to read trip point type $ cat trip_point_0_type - to emulate temperature raise to test orderly shutdown by Linux distro $ echo 105 > emul_temp Tested-by: Bryan O'Donoghue Signed-off-by: Ong Boon Leong Reviewed-by: Bryan O'Donoghue Reviewed-by: Kweh, Hock Leong Signed-off-by: Zhang Rui --- drivers/thermal/Kconfig | 10 + drivers/thermal/Makefile | 1 + drivers/thermal/intel_quark_dts_thermal.c | 473 ++++++++++++++++++++++++++++++ 3 files changed, 484 insertions(+) create mode 100644 drivers/thermal/intel_quark_dts_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 56922373806e..dbbb437f7d13 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -272,6 +272,16 @@ config INTEL_SOC_DTS_THERMAL notification methods.The other trip is a critical trip point, which was set by the driver based on the TJ MAX temperature. +config INTEL_QUARK_DTS_THERMAL + tristate "Intel Quark DTS thermal driver" + depends on X86_INTEL_QUARK + help + Enable this to register Intel Quark SoC (e.g. X1000) platform digital + temperature sensor (DTS). For X1000 SoC, it has one on-die DTS. + The DTS will be registered as a thermal zone. There are two trip points: + hot & critical. The critical trip point default value is set by + underlying BIOS/Firmware. + config INT340X_THERMAL tristate "ACPI INT340X thermal drivers" depends on X86 && ACPI diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 166d603ebf7e..873ca1564e50 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o +obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ obj-$(CONFIG_ST_THERMAL) += st/ diff --git a/drivers/thermal/intel_quark_dts_thermal.c b/drivers/thermal/intel_quark_dts_thermal.c new file mode 100644 index 000000000000..4434ec812cb7 --- /dev/null +++ b/drivers/thermal/intel_quark_dts_thermal.c @@ -0,0 +1,473 @@ +/* + * intel_quark_dts_thermal.c + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * Contact Information: + * Ong Boon Leong + * Intel Malaysia, Penang + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Quark DTS thermal driver is implemented by referencing + * intel_soc_dts_thermal.c. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define X86_FAMILY_QUARK 0x5 +#define X86_MODEL_QUARK_X1000 0x9 + +/* DTS reset is programmed via QRK_MBI_UNIT_SOC */ +#define QRK_DTS_REG_OFFSET_RESET 0x34 +#define QRK_DTS_RESET_BIT BIT(0) + +/* DTS enable is programmed via QRK_MBI_UNIT_RMU */ +#define QRK_DTS_REG_OFFSET_ENABLE 0xB0 +#define QRK_DTS_ENABLE_BIT BIT(15) + +/* Temperature Register is read via QRK_MBI_UNIT_RMU */ +#define QRK_DTS_REG_OFFSET_TEMP 0xB1 +#define QRK_DTS_MASK_TEMP 0xFF +#define QRK_DTS_OFFSET_TEMP 0 +#define QRK_DTS_OFFSET_REL_TEMP 16 +#define QRK_DTS_TEMP_BASE 50 + +/* Programmable Trip Point Register is configured via QRK_MBI_UNIT_RMU */ +#define QRK_DTS_REG_OFFSET_PTPS 0xB2 +#define QRK_DTS_MASK_TP_THRES 0xFF +#define QRK_DTS_SHIFT_TP 8 +#define QRK_DTS_ID_TP_CRITICAL 0 +#define QRK_DTS_SAFE_TP_THRES 105 + +/* Thermal Sensor Register Lock */ +#define QRK_DTS_REG_OFFSET_LOCK 0x71 +#define QRK_DTS_LOCK_BIT BIT(5) + +/* Quark DTS has 2 trip points: hot & catastrophic */ +#define QRK_MAX_DTS_TRIPS 2 +/* If DTS not locked, all trip points are configurable */ +#define QRK_DTS_WR_MASK_SET 0x3 +/* If DTS locked, all trip points are not configurable */ +#define QRK_DTS_WR_MASK_CLR 0 + +#define DEFAULT_POLL_DELAY 2000 + +struct soc_sensor_entry { + bool locked; + u32 store_ptps; + u32 store_dts_enable; + enum thermal_device_mode mode; + struct thermal_zone_device *tzone; +}; + +static struct soc_sensor_entry *soc_dts; + +static int polling_delay = DEFAULT_POLL_DELAY; +module_param(polling_delay, int, 0644); +MODULE_PARM_DESC(polling_delay, + "Polling interval for checking trip points (in milliseconds)"); + +static DEFINE_MUTEX(dts_update_mutex); + +static int soc_dts_enable(struct thermal_zone_device *tzd) +{ + u32 out; + struct soc_sensor_entry *aux_entry = tzd->devdata; + int ret; + + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_ENABLE, &out); + if (ret) + return ret; + + if (out & QRK_DTS_ENABLE_BIT) { + aux_entry->mode = THERMAL_DEVICE_ENABLED; + return 0; + } + + if (!aux_entry->locked) { + out |= QRK_DTS_ENABLE_BIT; + ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, + QRK_DTS_REG_OFFSET_ENABLE, out); + if (ret) + return ret; + + aux_entry->mode = THERMAL_DEVICE_ENABLED; + } else { + aux_entry->mode = THERMAL_DEVICE_DISABLED; + pr_info("DTS is locked. Cannot enable DTS\n"); + ret = -EPERM; + } + + return ret; +} + +static int soc_dts_disable(struct thermal_zone_device *tzd) +{ + u32 out; + struct soc_sensor_entry *aux_entry = tzd->devdata; + int ret; + + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_ENABLE, &out); + if (ret) + return ret; + + if (!(out & QRK_DTS_ENABLE_BIT)) { + aux_entry->mode = THERMAL_DEVICE_DISABLED; + return 0; + } + + if (!aux_entry->locked) { + out &= ~QRK_DTS_ENABLE_BIT; + ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, + QRK_DTS_REG_OFFSET_ENABLE, out); + + if (ret) + return ret; + + aux_entry->mode = THERMAL_DEVICE_DISABLED; + } else { + aux_entry->mode = THERMAL_DEVICE_ENABLED; + pr_info("DTS is locked. Cannot disable DTS\n"); + ret = -EPERM; + } + + return ret; +} + +static int _get_trip_temp(int trip, unsigned long *temp) +{ + int status; + u32 out; + + mutex_lock(&dts_update_mutex); + status = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_PTPS, &out); + mutex_unlock(&dts_update_mutex); + + if (status) + return status; + + /* + * Thermal Sensor Programmable Trip Point Register has 8-bit + * fields for critical (catastrophic) and hot set trip point + * thresholds. The threshold value is always offset by its + * temperature base (50 degree Celsius). + */ + *temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES; + *temp -= QRK_DTS_TEMP_BASE; + + return 0; +} + +static inline int sys_get_trip_temp(struct thermal_zone_device *tzd, + int trip, unsigned long *temp) +{ + return _get_trip_temp(trip, temp); +} + +static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, + unsigned long *temp) +{ + return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp); +} + +static int update_trip_temp(struct soc_sensor_entry *aux_entry, + int trip, unsigned long temp) +{ + u32 out; + u32 temp_out; + u32 store_ptps; + int ret; + + mutex_lock(&dts_update_mutex); + if (aux_entry->locked) { + ret = -EPERM; + goto failed; + } + + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_PTPS, &store_ptps); + if (ret) + goto failed; + + /* + * Protection against unsafe trip point thresdhold value. + * As Quark X1000 data-sheet does not provide any recommendation + * regarding the safe trip point threshold value to use, we choose + * the safe value according to the threshold value set by UEFI BIOS. + */ + if (temp > QRK_DTS_SAFE_TP_THRES) + temp = QRK_DTS_SAFE_TP_THRES; + + /* + * Thermal Sensor Programmable Trip Point Register has 8-bit + * fields for critical (catastrophic) and hot set trip point + * thresholds. The threshold value is always offset by its + * temperature base (50 degree Celsius). + */ + temp_out = temp + QRK_DTS_TEMP_BASE; + out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES << + (trip * QRK_DTS_SHIFT_TP))); + out |= (temp_out & QRK_DTS_MASK_TP_THRES) << + (trip * QRK_DTS_SHIFT_TP); + + ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, + QRK_DTS_REG_OFFSET_PTPS, out); + +failed: + mutex_unlock(&dts_update_mutex); + return ret; +} + +static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, + unsigned long temp) +{ + return update_trip_temp(tzd->devdata, trip, temp); +} + +static int sys_get_trip_type(struct thermal_zone_device *thermal, + int trip, enum thermal_trip_type *type) +{ + if (trip) + *type = THERMAL_TRIP_HOT; + else + *type = THERMAL_TRIP_CRITICAL; + + return 0; +} + +static int sys_get_curr_temp(struct thermal_zone_device *tzd, + unsigned long *temp) +{ + u32 out; + int ret; + + mutex_lock(&dts_update_mutex); + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_TEMP, &out); + mutex_unlock(&dts_update_mutex); + + if (ret) + return ret; + + /* + * Thermal Sensor Temperature Register has 8-bit field + * for temperature value (offset by temperature base + * 50 degree Celsius). + */ + out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP; + *temp = out - QRK_DTS_TEMP_BASE; + + return 0; +} + +static int sys_get_mode(struct thermal_zone_device *tzd, + enum thermal_device_mode *mode) +{ + struct soc_sensor_entry *aux_entry = tzd->devdata; + *mode = aux_entry->mode; + return 0; +} + +static int sys_set_mode(struct thermal_zone_device *tzd, + enum thermal_device_mode mode) +{ + int ret; + + mutex_lock(&dts_update_mutex); + if (mode == THERMAL_DEVICE_ENABLED) + ret = soc_dts_enable(tzd); + else + ret = soc_dts_disable(tzd); + mutex_unlock(&dts_update_mutex); + + return ret; +} + +static struct thermal_zone_device_ops tzone_ops = { + .get_temp = sys_get_curr_temp, + .get_trip_temp = sys_get_trip_temp, + .get_trip_type = sys_get_trip_type, + .set_trip_temp = sys_set_trip_temp, + .get_crit_temp = sys_get_crit_temp, + .get_mode = sys_get_mode, + .set_mode = sys_set_mode, +}; + +static void free_soc_dts(struct soc_sensor_entry *aux_entry) +{ + if (aux_entry) { + if (!aux_entry->locked) { + mutex_lock(&dts_update_mutex); + iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, + QRK_DTS_REG_OFFSET_ENABLE, + aux_entry->store_dts_enable); + + iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, + QRK_DTS_REG_OFFSET_PTPS, + aux_entry->store_ptps); + mutex_unlock(&dts_update_mutex); + } + thermal_zone_device_unregister(aux_entry->tzone); + kfree(aux_entry); + } +} + +static struct soc_sensor_entry *alloc_soc_dts(void) +{ + struct soc_sensor_entry *aux_entry; + int err; + u32 out; + int wr_mask; + + aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); + if (!aux_entry) { + err = -ENOMEM; + return ERR_PTR(-ENOMEM); + } + + /* Check if DTS register is locked */ + err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_LOCK, + &out); + if (err) + goto err_ret; + + if (out & QRK_DTS_LOCK_BIT) { + aux_entry->locked = true; + wr_mask = QRK_DTS_WR_MASK_CLR; + } else { + aux_entry->locked = false; + wr_mask = QRK_DTS_WR_MASK_SET; + } + + /* Store DTS default state if DTS registers are not locked */ + if (!aux_entry->locked) { + /* Store DTS default enable for restore on exit */ + err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_ENABLE, + &aux_entry->store_dts_enable); + if (err) + goto err_ret; + + /* Store DTS default PTPS register for restore on exit */ + err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, + QRK_DTS_REG_OFFSET_PTPS, + &aux_entry->store_ptps); + if (err) + goto err_ret; + } + + aux_entry->tzone = thermal_zone_device_register("quark_dts", + QRK_MAX_DTS_TRIPS, + wr_mask, + aux_entry, &tzone_ops, NULL, 0, polling_delay); + if (IS_ERR(aux_entry->tzone)) { + err = PTR_ERR(aux_entry->tzone); + goto err_ret; + } + + mutex_lock(&dts_update_mutex); + err = soc_dts_enable(aux_entry->tzone); + mutex_unlock(&dts_update_mutex); + if (err) + goto err_aux_status; + + return aux_entry; + +err_aux_status: + thermal_zone_device_unregister(aux_entry->tzone); +err_ret: + kfree(aux_entry); + return ERR_PTR(err); +} + +static const struct x86_cpu_id qrk_thermal_ids[] __initconst = { + { X86_VENDOR_INTEL, X86_FAMILY_QUARK, X86_MODEL_QUARK_X1000 }, + {} +}; +MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); + +static int __init intel_quark_thermal_init(void) +{ + int err = 0; + + if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available()) + return -ENODEV; + + soc_dts = alloc_soc_dts(); + if (IS_ERR(soc_dts)) { + err = PTR_ERR(soc_dts); + goto err_free; + } + + return 0; + +err_free: + free_soc_dts(soc_dts); + return err; +} + +static void __exit intel_quark_thermal_exit(void) +{ + free_soc_dts(soc_dts); +} + +module_init(intel_quark_thermal_init) +module_exit(intel_quark_thermal_exit) + +MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver"); +MODULE_AUTHOR("Ong Boon Leong "); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From bd7081ae2bbd063fa4a29a01cb7004d8516e54e3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 29 Apr 2015 09:10:16 +0800 Subject: Thermal: Intel SoC: fix simple_return.cocci warnings drivers/thermal/intel_soc_dts_iosf.c:358:4-7: WARNING: end returns can be simpified Simplify a trivial if-return sequence. Possibly combine with a preceding function call. Generated by: scripts/coccinelle/misc/simple_return.cocci CC: Srinivas Pandruvada Signed-off-by: Fengguang Wu Signed-off-by: Zhang Rui --- drivers/thermal/intel_soc_dts_iosf.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/thermal/intel_soc_dts_iosf.c b/drivers/thermal/intel_soc_dts_iosf.c index d89787612c5d..42e4b6ac3875 100644 --- a/drivers/thermal/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel_soc_dts_iosf.c @@ -350,18 +350,13 @@ int intel_soc_dts_iosf_add_read_only_critical_trip( struct intel_soc_dts_sensors *sensors, int critical_offset) { int i, j; - int ret; for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { - ret = update_trip_temp(&sensors->soc_dts[i], j, + return update_trip_temp(&sensors->soc_dts[i], j, sensors->tj_max - critical_offset, THERMAL_TRIP_CRITICAL); - if (ret) - return ret; - - return 0; } } } -- cgit v1.2.3 From 383b4d60f6e376cd062964ed93affd08d9a730c0 Mon Sep 17 00:00:00 2001 From: Brian Bian Date: Mon, 20 Apr 2015 11:25:37 -0700 Subject: int340x_thermal/processor_thermal_device: add support to Skylake processors Add PCI ID of Skylake thermal reporting device. Signed-off-by: Brian Bian Signed-off-by: Zhang Rui --- drivers/thermal/int340x_thermal/processor_thermal_device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index e9f1b729fe9c..3df3dc34b124 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -27,6 +27,9 @@ #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 #define PCI_DEVICE_ID_PROC_HSB_THERMAL 0x0A03 +/* Skylake thermal reporting device */ +#define PCI_DEVICE_ID_PROC_SKL_THERMAL 0x1903 + /* Braswell thermal reporting device */ #define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC @@ -399,6 +402,7 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev) static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)}, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)}, { 0, }, }; -- cgit v1.2.3 From 6a6bcf08e5d1834447655a762dfaf552b675cc54 Mon Sep 17 00:00:00 2001 From: Dasaratharaman Chandramouli Date: Fri, 17 Apr 2015 15:31:06 -0700 Subject: intel powerclamp: support Knights Landing This patch enables intel_powerclamp driver to run on the next-generation Intel(R) Xeon Phi Microarchitecture code named "Knights Landing" Signed-off-by: Dasaratharaman Chandramouli Acked-by: Jacob Pan Signed-off-by: Zhang Rui --- drivers/thermal/intel_powerclamp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 12623bc02f46..e34ccd5b1ba0 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -690,6 +690,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = { { X86_VENDOR_INTEL, 6, 0x4c}, { X86_VENDOR_INTEL, 6, 0x4d}, { X86_VENDOR_INTEL, 6, 0x56}, + { X86_VENDOR_INTEL, 6, 0x57}, {} }; MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); -- cgit v1.2.3 From 6cd9e9f629f11b9412d4e9aa294c029dbb36b3cf Mon Sep 17 00:00:00 2001 From: Kapileshwar Singh Date: Wed, 18 Feb 2015 16:04:21 +0000 Subject: thermal: of: fix cooling device weights in device tree Currently you can specify the weight of the cooling device in the device tree but that information is not populated to the thermal_bind_params where the fair share governor expects it to be. The of thermal zone device doesn't have a thermal_bind_params structure and arguably it's better to pass the weight inside the thermal_instance as it is specific to the bind of a cooling device to a thermal zone parameter. Core thermal code is fixed to populate the weight in the instance from the thermal_bind_params, so platform code that was passing the weight inside the thermal_bind_params continue to work seamlessly. While we are at it, create a default value for the weight parameter for those thermal zones that currently don't define it and remove the hardcoded default in of-thermal. Cc: Zhang Rui Cc: "Rafael J. Wysocki" Cc: Len Brown Cc: Peter Feuerer Cc: Darren Hart Cc: Eduardo Valentin Cc: Kukjin Kim Cc: Durgadoss R Signed-off-by: Kapileshwar Singh Signed-off-by: Eduardo Valentin --- Documentation/thermal/sysfs-api.txt | 4 +++- drivers/acpi/thermal.c | 9 ++++++--- drivers/platform/x86/acerhdf.c | 3 ++- drivers/thermal/db8500_thermal.c | 2 +- drivers/thermal/fair_share.c | 2 +- drivers/thermal/imx_thermal.c | 3 ++- drivers/thermal/of-thermal.c | 5 +++-- drivers/thermal/thermal_core.c | 22 ++++++++++++++++------ drivers/thermal/thermal_core.h | 1 + drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 3 ++- include/linux/thermal.h | 6 +++++- 11 files changed, 42 insertions(+), 18 deletions(-) diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index 87519cb379ee..7ec632ed9769 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt @@ -95,7 +95,7 @@ temperature) and throttle appropriate devices. 1.3 interface for binding a thermal zone device with a thermal cooling device 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev, - unsigned long upper, unsigned long lower); + unsigned long upper, unsigned long lower, unsigned int weight); This interface function bind a thermal cooling device to the certain trip point of a thermal zone device. @@ -110,6 +110,8 @@ temperature) and throttle appropriate devices. lower:the Minimum cooling state can be used for this trip point. THERMAL_NO_LIMIT means no lower limit, and the cooling device can be in cooling state 0. + weight: the influence of this cooling device in this thermal + zone. See 1.4.1 below for more information. 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index d24fa1964eb8..6d4e44ea74ac 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -800,7 +800,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, result = thermal_zone_bind_cooling_device (thermal, trip, cdev, - THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); + THERMAL_NO_LIMIT, THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); else result = thermal_zone_unbind_cooling_device @@ -824,7 +825,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, if (bind) result = thermal_zone_bind_cooling_device (thermal, trip, cdev, - THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); + THERMAL_NO_LIMIT, THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); else result = thermal_zone_unbind_cooling_device (thermal, trip, cdev); @@ -841,7 +843,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, result = thermal_zone_bind_cooling_device (thermal, THERMAL_TRIPS_NONE, cdev, THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT); + THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); else result = thermal_zone_unbind_cooling_device (thermal, THERMAL_TRIPS_NONE, diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index 594c918b553d..1ef02daddb60 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -372,7 +372,8 @@ static int acerhdf_bind(struct thermal_zone_device *thermal, return 0; if (thermal_zone_bind_cooling_device(thermal, 0, cdev, - THERMAL_NO_LIMIT, THERMAL_NO_LIMIT)) { + THERMAL_NO_LIMIT, THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT)) { pr_err("error binding cooling dev\n"); return -EINVAL; } diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c index 20adfbe27df1..2fb273c4baa9 100644 --- a/drivers/thermal/db8500_thermal.c +++ b/drivers/thermal/db8500_thermal.c @@ -76,7 +76,7 @@ static int db8500_cdev_bind(struct thermal_zone_device *thermal, upper = lower = i > max_state ? max_state : i; ret = thermal_zone_bind_cooling_device(thermal, i, cdev, - upper, lower); + upper, lower, THERMAL_WEIGHT_DEFAULT); dev_info(&cdev->device, "%s bind to %d: %d-%s\n", cdev->type, i, ret, ret ? "fail" : "succeed"); diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c index 6e0a3fbfae86..c3b25187b467 100644 --- a/drivers/thermal/fair_share.c +++ b/drivers/thermal/fair_share.c @@ -109,7 +109,7 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip) continue; instance->target = get_target_state(tz, cdev, - tzp->tbp[i].weight, cur_trip_level); + instance->weight, cur_trip_level); instance->cdev->updated = false; thermal_cdev_update(cdev); diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 2ccbc0788353..fde4c2876d14 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -306,7 +306,8 @@ static int imx_bind(struct thermal_zone_device *tz, ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev, THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT); + THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); if (ret) { dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n", diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 668fb1bdea9e..c606b85ea9f4 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -227,7 +227,8 @@ static int of_thermal_bind(struct thermal_zone_device *thermal, ret = thermal_zone_bind_cooling_device(thermal, tbp->trip_id, cdev, tbp->max, - tbp->min); + tbp->min, + tbp->usage); if (ret) return ret; } @@ -581,7 +582,7 @@ static int thermal_of_populate_bind_params(struct device_node *np, u32 prop; /* Default weight. Usage is optional */ - __tbp->usage = 0; + __tbp->usage = THERMAL_WEIGHT_DEFAULT; ret = of_property_read_u32(np, "contribution", &prop); if (ret == 0) __tbp->usage = prop; diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 4108db7e10c1..a6cb9b78b629 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -218,7 +218,8 @@ static void print_bind_err_msg(struct thermal_zone_device *tz, static void __bind(struct thermal_zone_device *tz, int mask, struct thermal_cooling_device *cdev, - unsigned long *limits) + unsigned long *limits, + unsigned int weight) { int i, ret; @@ -233,7 +234,8 @@ static void __bind(struct thermal_zone_device *tz, int mask, upper = limits[i * 2 + 1]; } ret = thermal_zone_bind_cooling_device(tz, i, cdev, - upper, lower); + upper, lower, + weight); if (ret) print_bind_err_msg(tz, cdev, ret); } @@ -280,7 +282,8 @@ static void bind_cdev(struct thermal_cooling_device *cdev) continue; tzp->tbp[i].cdev = cdev; __bind(pos, tzp->tbp[i].trip_mask, cdev, - tzp->tbp[i].binding_limits); + tzp->tbp[i].binding_limits, + tzp->tbp[i].weight); } } @@ -319,7 +322,8 @@ static void bind_tz(struct thermal_zone_device *tz) continue; tzp->tbp[i].cdev = pos; __bind(tz, tzp->tbp[i].trip_mask, pos, - tzp->tbp[i].binding_limits); + tzp->tbp[i].binding_limits, + tzp->tbp[i].weight); } } exit: @@ -713,7 +717,8 @@ passive_store(struct device *dev, struct device_attribute *attr, thermal_zone_bind_cooling_device(tz, THERMAL_TRIPS_NONE, cdev, THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT); + THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); } mutex_unlock(&thermal_list_lock); if (!tz->passive_delay) @@ -931,6 +936,9 @@ static const struct attribute_group *cooling_device_attr_groups[] = { * @