From a3c1f066e1c514ac819f5dae288cc8a59c384158 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:15 +0800 Subject: thermal/intel: Introduce Intel TCC library There are several different drivers that accesses the Intel TCC (thermal control circuitry) MSRs, and each of them has its own implementation for the same functionalities, e.g. getting the current temperature, getting the tj_max, and getting/setting the tj_max offset. Introduce a library to unify the code for Intel CPU TCC MSR access. At the same time, ensure the temperature is got based on the updated tjmax value because tjmax can be changed at runtime for cases like the Intel SST-PP (Intel Speed Select Technology - Performance Profile) level change. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/Kconfig | 4 ++ drivers/thermal/intel/Makefile | 1 + drivers/thermal/intel/intel_tcc.c | 139 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 drivers/thermal/intel/intel_tcc.c (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index f0c845679250..6b938c040d6e 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -12,6 +12,10 @@ config X86_THERMAL_VECTOR def_bool y depends on X86 && CPU_SUP_INTEL && X86_LOCAL_APIC +config INTEL_TCC + bool + depends on X86 + config X86_PKG_TEMP_THERMAL tristate "X86 package temperature thermal driver" depends on X86_THERMAL_VECTOR diff --git a/drivers/thermal/intel/Makefile b/drivers/thermal/intel/Makefile index 9a8d8054f316..5d8833c82ab6 100644 --- a/drivers/thermal/intel/Makefile +++ b/drivers/thermal/intel/Makefile @@ -2,6 +2,7 @@ # # Makefile for various Intel thermal drivers. +obj-$(CONFIG_INTEL_TCC) += intel_tcc.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 diff --git a/drivers/thermal/intel/intel_tcc.c b/drivers/thermal/intel/intel_tcc.c new file mode 100644 index 000000000000..2e5c741c41ca --- /dev/null +++ b/drivers/thermal/intel/intel_tcc.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access + * Copyright (c) 2022, Intel Corporation. + */ + +#include +#include +#include + +/** + * intel_tcc_get_tjmax() - returns the default TCC activation Temperature + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * + * Get the TjMax value, which is the default thermal throttling or TCC + * activation temperature in degrees C. + * + * Return: Tjmax value in degrees C on success, negative error code otherwise. + */ +int intel_tcc_get_tjmax(int cpu) +{ + u32 low, high; + int val, err; + + if (cpu < 0) + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high); + if (err) + return err; + + val = (low >> 16) & 0xff; + + return val ? val : -ENODATA; +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC); + +/** + * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * + * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC + * activation temperature equals "Tjmax" - "TCC Offset", in degrees C. + * + * Return: Tcc offset value in degrees C on success, negative error code otherwise. + */ +int intel_tcc_get_offset(int cpu) +{ + u32 low, high; + int err; + + if (cpu < 0) + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high); + if (err) + return err; + + return (low >> 24) & 0x3f; +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC); + +/** + * intel_tcc_set_offset() - set the TCC offset value to Tjmax + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @offset: TCC offset value in degree C + * + * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC + * activation temperature equals "Tjmax" - "TCC Offset", in degree C. + * + * Return: On success returns 0, negative error code otherwise. + */ + +int intel_tcc_set_offset(int cpu, int offset) +{ + u32 low, high; + int err; + + if (offset < 0 || offset > 0x3f) + return -EINVAL; + + if (cpu < 0) + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high); + if (err) + return err; + + /* MSR Locked */ + if (low & BIT(31)) + return -EPERM; + + low &= ~(0x3f << 24); + low |= offset << 24; + + if (cpu < 0) + return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high); + else + return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high); +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC); + +/** + * intel_tcc_get_temp() - returns the current temperature + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor. + * + * Get the current temperature returned by the CPU core/package level + * thermal sensor, in degrees C. + * + * Return: Temperature in degrees C on success, negative error code otherwise. + */ +int intel_tcc_get_temp(int cpu, bool pkg) +{ + u32 low, high; + u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS; + int tjmax, temp, err; + + tjmax = intel_tcc_get_tjmax(cpu); + if (tjmax < 0) + return tjmax; + + if (cpu < 0) + err = rdmsr_safe(msr, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, msr, &low, &high); + if (err) + return err; + + /* Temperature is beyond the valid thermal sensor range */ + if (!(low & BIT(31))) + return -ENODATA; + + temp = tjmax - ((low >> 16) & 0x7f); + + /* Do not allow negative CPU temperature */ + return temp >= 0 ? temp : -ENODATA; +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC); -- cgit v1.2.3 From d91a4714e54e4ad4d6fe795339aae329f53b2217 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:16 +0800 Subject: thermal/int340x/processor_thermal: Use Intel TCC library Cleanup the code by using Intel TCC library for TCC (Thermal Control Circuitry) MSR access. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/Kconfig | 1 + .../int340x_thermal/processor_thermal_device.c | 119 ++++----------------- 2 files changed, 22 insertions(+), 98 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig index 5d046de96a5d..0f511917e0e1 100644 --- a/drivers/thermal/intel/int340x_thermal/Kconfig +++ b/drivers/thermal/intel/int340x_thermal/Kconfig @@ -10,6 +10,7 @@ config INT340X_THERMAL select ACPI_THERMAL_REL select ACPI_FAN select INTEL_SOC_DTS_IOSF_CORE + select INTEL_TCC select PROC_THERMAL_MMIO_RAPL if POWERCAP help Newer laptops and tablets that use ACPI may have thermal sensors and diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index a8d98f1bd6c6..a2ea22f2bffd 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -4,6 +4,7 @@ * Copyright (c) 2014, Intel Corporation. */ #include +#include #include #include #include @@ -68,54 +69,17 @@ static const struct attribute_group power_limit_attribute_group = { .name = "power_limits" }; -static int tcc_get_offset(void) -{ - u64 val; - int err; - - err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); - if (err) - return err; - - return (val >> 24) & 0x3f; -} - static ssize_t tcc_offset_degree_celsius_show(struct device *dev, struct device_attribute *attr, char *buf) { - int tcc; - - tcc = tcc_get_offset(); - if (tcc < 0) - return tcc; + int offset; - return sprintf(buf, "%d\n", tcc); -} - -static int tcc_offset_update(unsigned int tcc) -{ - u64 val; - int err; - - if (tcc > 63) - return -EINVAL; - - err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); - if (err) - return err; - - if (val & BIT(31)) - return -EPERM; - - val &= ~GENMASK_ULL(29, 24); - val |= (tcc & 0x3f) << 24; - - err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); - if (err) - return err; + offset = intel_tcc_get_offset(-1); + if (offset < 0) + return offset; - return 0; + return sprintf(buf, "%d\n", offset); } static ssize_t tcc_offset_degree_celsius_store(struct device *dev, @@ -136,7 +100,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev, if (kstrtouint(buf, 0, &tcc)) return -EINVAL; - err = tcc_offset_update(tcc); + err = intel_tcc_set_offset(-1, tcc); if (err) return err; @@ -145,66 +109,25 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev, static DEVICE_ATTR_RW(tcc_offset_degree_celsius); -static int stored_tjmax; /* since it is fixed, we can have local storage */ - -static int get_tjmax(void) -{ - u32 eax, edx; - u32 val; - int err; - - err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); - if (err) - return err; - - val = (eax >> 16) & 0xff; - if (val) - return val; - - return -EINVAL; -} - -static int read_temp_msr(int *temp) +static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, + int *temp) { int cpu; - u32 eax, edx; - int err; - unsigned long curr_temp_off = 0; + int curr_temp; *temp = 0; for_each_online_cpu(cpu) { - err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, - &edx); - if (err) - goto err_ret; - else { - if (eax & 0x80000000) { - curr_temp_off = (eax >> 16) & 0x7f; - if (!*temp || curr_temp_off < *temp) - *temp = curr_temp_off; - } else { - err = -EINVAL; - goto err_ret; - } - } + curr_temp = intel_tcc_get_temp(cpu, false); + if (curr_temp < 0) + return curr_temp; + if (!*temp || curr_temp > *temp) + *temp = curr_temp; } - return 0; -err_ret: - return err; -} - -static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, - int *temp) -{ - int ret; - - ret = read_temp_msr(temp); - if (!ret) - *temp = (stored_tjmax - *temp) * 1000; + *temp *= 1000; - return ret; + return 0; } static struct thermal_zone_device_ops proc_thermal_local_ops = { @@ -302,8 +225,7 @@ int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv) status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); if (ACPI_FAILURE(status)) { /* there is no _TMP method, add local method */ - stored_tjmax = get_tjmax(); - if (stored_tjmax > 0) + if (intel_tcc_get_tjmax(-1) > 0) ops = &proc_thermal_local_ops; } @@ -356,7 +278,7 @@ static int tcc_offset_save = -1; int proc_thermal_suspend(struct device *dev) { - tcc_offset_save = tcc_get_offset(); + tcc_offset_save = intel_tcc_get_offset(-1); if (tcc_offset_save < 0) dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save); @@ -373,7 +295,7 @@ int proc_thermal_resume(struct device *dev) /* Do not update if saving failed */ if (tcc_offset_save >= 0) - tcc_offset_update(tcc_offset_save); + intel_tcc_set_offset(-1, tcc_offset_save); return 0; } @@ -460,6 +382,7 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device * } EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove); +MODULE_IMPORT_NS(INTEL_TCC); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 955fb8719efbb8e914dc03f192e9a0bded3bae77 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:17 +0800 Subject: thermal/intel/intel_soc_dts_iosf: Use Intel TCC library Cleanup the code by using Intel TCC library for TCC (Thermal Control Circuitry) MSR access. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/Kconfig | 1 + drivers/thermal/intel/intel_soc_dts_iosf.c | 33 +++++------------------------- 2 files changed, 6 insertions(+), 28 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index 6b938c040d6e..329c0ee934c4 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -32,6 +32,7 @@ config INTEL_SOC_DTS_IOSF_CORE tristate depends on X86 && PCI select IOSF_MBI + select INTEL_TCC help This is becoming a common feature for Intel SoCs to expose the additional digital temperature sensors (DTSs) using side band interface (IOSF). This diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c index 342b0bb5a56d..2138693d8afd 100644 --- a/drivers/thermal/intel/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel/intel_soc_dts_iosf.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -45,32 +46,6 @@ /* 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, int *temp) { @@ -415,8 +390,9 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init( if (!trip_count || read_only_trip_count > trip_count) return ERR_PTR(-EINVAL); - if (get_tj_max(&tj_max)) - return ERR_PTR(-EINVAL); + tj_max = intel_tcc_get_tjmax(-1); + if (tj_max < 0) + return ERR_PTR(tj_max); sensors = kzalloc(sizeof(*sensors), GFP_KERNEL); if (!sensors) @@ -475,4 +451,5 @@ void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) } EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); +MODULE_IMPORT_NS(INTEL_TCC); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 4e3ecc2898fe0b42177cd7bb4d38088b4829ef45 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:18 +0800 Subject: thermal/intel/intel_tcc_cooling: Use Intel TCC library Cleanup the code by using Intel TCC library for TCC (Thermal Control Circuitry) MSR access. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/Kconfig | 1 + drivers/thermal/intel/intel_tcc_cooling.c | 37 +++++++------------------------ 2 files changed, 9 insertions(+), 29 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index 329c0ee934c4..dafdb3dd3fc7 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -88,6 +88,7 @@ config INTEL_PCH_THERMAL config INTEL_TCC_COOLING tristate "Intel TCC offset cooling Driver" depends on X86 + select INTEL_TCC help Enable this to support system cooling by adjusting the effective TCC activation temperature via the TCC Offset register, which is widely diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c index a89e7e1890e4..e95f799454fe 100644 --- a/drivers/thermal/intel/intel_tcc_cooling.c +++ b/drivers/thermal/intel/intel_tcc_cooling.c @@ -7,12 +7,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include -#define TCC_SHIFT 24 -#define TCC_MASK (0x3fULL<<24) #define TCC_PROGRAMMABLE BIT(30) #define TCC_LOCKED BIT(31) @@ -21,47 +20,26 @@ static struct thermal_cooling_device *tcc_cdev; static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { - *state = TCC_MASK >> TCC_SHIFT; - return 0; -} - -static int tcc_offset_update(int tcc) -{ - u64 val; - int err; - - err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); - if (err) - return err; - - val &= ~TCC_MASK; - val |= tcc << TCC_SHIFT; - - err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); - if (err) - return err; - + *state = 0x3f; return 0; } static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { - u64 val; - int err; + int offset = intel_tcc_get_offset(-1); - err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); - if (err) - return err; + if (offset < 0) + return offset; - *state = (val & TCC_MASK) >> TCC_SHIFT; + *state = offset; return 0; } static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { - return tcc_offset_update(state); + return intel_tcc_set_offset(-1, (int)state); } static const struct thermal_cooling_device_ops tcc_cooling_ops = { @@ -140,6 +118,7 @@ static void __exit tcc_cooling_exit(void) module_exit(tcc_cooling_exit) +MODULE_IMPORT_NS(INTEL_TCC); MODULE_DESCRIPTION("TCC offset cooling device Driver"); MODULE_AUTHOR("Zhang Rui "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 983eb370cb871bd843a8a7da01da6c4b38871309 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:19 +0800 Subject: thermal/x86_pkg_temp_thermal: Use Intel TCC library Cleanup the code by using Intel TCC library for TCC (Thermal Control Circuitry) MSR access. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/Kconfig | 1 + drivers/thermal/intel/x86_pkg_temp_thermal.c | 44 ++++++++-------------------- 2 files changed, 14 insertions(+), 31 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index dafdb3dd3fc7..fd41c810629b 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -21,6 +21,7 @@ config X86_PKG_TEMP_THERMAL depends on X86_THERMAL_VECTOR select THERMAL_GOV_USER_SPACE select THERMAL_WRITABLE_TRIPS + select INTEL_TCC default m help Enable this to register CPU digital sensor for package temperature as diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 84c3a116ed04..1cb054c5a02f 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -104,38 +105,18 @@ static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu) return NULL; } -/* -* tj-max is interesting because threshold is set relative to this -* temperature. -*/ -static int get_tj_max(int cpu, u32 *tj_max) -{ - u32 eax, edx, val; - int err; - - err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); - if (err) - return err; - - val = (eax >> 16) & 0xff; - *tj_max = val * 1000; - - return val ? 0 : -EINVAL; -} - static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) { struct zone_device *zonedev = tzd->devdata; - u32 eax, edx; + int val; - rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_STATUS, - &eax, &edx); - if (eax & 0x80000000) { - *temp = zonedev->tj_max - ((eax >> 16) & 0x7f) * 1000; - pr_debug("sys_get_curr_temp %d\n", *temp); - return 0; - } - return -EINVAL; + val = intel_tcc_get_temp(zonedev->cpu, true); + if (val < 0) + return val; + + *temp = val * 1000; + pr_debug("sys_get_curr_temp %d\n", *temp); + return 0; } static int sys_get_trip_temp(struct thermal_zone_device *tzd, @@ -340,9 +321,9 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS); - err = get_tj_max(cpu, &tj_max); - if (err) - return err; + tj_max = intel_tcc_get_tjmax(cpu); + if (tj_max < 0) + return tj_max; zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL); if (!zonedev) @@ -531,6 +512,7 @@ static void __exit pkg_temp_thermal_exit(void) } module_exit(pkg_temp_thermal_exit) +MODULE_IMPORT_NS(INTEL_TCC); MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 58374a3970a04ef3bf2df3a3d3d2345be998068f Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:20 +0800 Subject: thermal/x86_pkg_temp_thermal: Add support for handling dynamic tjmax Tjmax value retrieved from MSR_IA32_TEMPERATURE_TARGET can be changed at runtime when the Intel SST-PP (Intel Speed Select Technology - Performance Profile) level is changed. Enhance the code to use updated tjmax when programming the thermal interrupt thresholds. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/x86_pkg_temp_thermal.c | 30 ++++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 1cb054c5a02f..9e08d8c8f5fb 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -49,7 +49,6 @@ MODULE_PARM_DESC(notify_delay_ms, struct zone_device { int cpu; bool work_scheduled; - u32 tj_max; u32 msr_pkg_therm_low; u32 msr_pkg_therm_high; struct delayed_work work; @@ -125,7 +124,7 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, struct zone_device *zonedev = tzd->devdata; unsigned long thres_reg_value; u32 mask, shift, eax, edx; - int ret; + int tj_max, ret; if (trip >= MAX_NUMBER_OF_TRIPS) return -EINVAL; @@ -138,6 +137,11 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, shift = THERM_SHIFT_THRESHOLD0; } + tj_max = intel_tcc_get_tjmax(zonedev->cpu); + if (tj_max < 0) + return tj_max; + tj_max *= 1000; + ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &eax, &edx); if (ret < 0) @@ -145,7 +149,7 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, thres_reg_value = (eax & mask) >> shift; if (thres_reg_value) - *temp = zonedev->tj_max - thres_reg_value * 1000; + *temp = tj_max - thres_reg_value * 1000; else *temp = THERMAL_TEMP_INVALID; pr_debug("sys_get_trip_temp %d\n", *temp); @@ -158,9 +162,14 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) { struct zone_device *zonedev = tzd->devdata; u32 l, h, mask, shift, intr; - int ret; + int tj_max, ret; - if (trip >= MAX_NUMBER_OF_TRIPS || temp >= zonedev->tj_max) + tj_max = intel_tcc_get_tjmax(zonedev->cpu); + if (tj_max < 0) + return tj_max; + tj_max *= 1000; + + if (trip >= MAX_NUMBER_OF_TRIPS || temp >= tj_max) return -EINVAL; ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, @@ -185,7 +194,7 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) if (!temp) { l &= ~intr; } else { - l |= (zonedev->tj_max - temp)/1000 << shift; + l |= (tj_max - temp)/1000 << shift; l |= intr; } @@ -307,7 +316,7 @@ static int pkg_thermal_notify(u64 msr_val) static int pkg_temp_thermal_device_add(unsigned int cpu) { int id = topology_logical_die_id(cpu); - u32 tj_max, eax, ebx, ecx, edx; + u32 eax, ebx, ecx, edx; struct zone_device *zonedev; int thres_count, err; @@ -321,9 +330,9 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS); - tj_max = intel_tcc_get_tjmax(cpu); - if (tj_max < 0) - return tj_max; + err = intel_tcc_get_tjmax(cpu); + if (err < 0) + return err; zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL); if (!zonedev) @@ -331,7 +340,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) INIT_DELAYED_WORK(&zonedev->work, pkg_temp_thermal_threshold_work_fn); zonedev->cpu = cpu; - zonedev->tj_max = tj_max; zonedev->tzone = thermal_zone_device_register("x86_pkg_temp", thres_count, (thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01, -- cgit v1.2.3 From e7fcfe67f9f410736b758969477b17ea285e8e6c Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 6 Jan 2023 08:59:51 +0800 Subject: thermal: intel: Fix unsigned comparison with less than zero The return value from the call to intel_tcc_get_tjmax() is int, which can be a negative error code. However, the return value is being assigned to an u32 variable 'tj_max', so making 'tj_max' an int. Eliminate the following warning: ./drivers/thermal/intel/intel_soc_dts_iosf.c:394:5-11: WARNING: Unsigned expression compared with zero: tj_max < 0 Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3637 Reported-by: Abaci Robot Signed-off-by: Yang Li Acked-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/intel_soc_dts_iosf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c index 2138693d8afd..8c26f7b2316b 100644 --- a/drivers/thermal/intel/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel/intel_soc_dts_iosf.c @@ -380,7 +380,7 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init( { struct intel_soc_dts_sensors *sensors; bool notification; - u32 tj_max; + int tj_max; int ret; int i; -- cgit v1.2.3 From a30e65792c473f0b758fcfe881264184423bdb52 Mon Sep 17 00:00:00 2001 From: Deming Wang Date: Tue, 17 Jan 2023 20:20:57 -0500 Subject: thermal: intel: menlow: Update function descriptions Update function parameter descriptions for sensor_get_auxtrip() and sensor_set_auxtrip(). [ rjw: New changelog, subject edits ] Signed-off-by: Deming Wang Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/intel_menlow.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/intel_menlow.c b/drivers/thermal/intel/intel_menlow.c index 3f885b08a490..5a6ad0552311 100644 --- a/drivers/thermal/intel/intel_menlow.c +++ b/drivers/thermal/intel/intel_menlow.c @@ -232,9 +232,9 @@ static DEFINE_MUTEX(intel_menlow_attr_lock); /* * sensor_get_auxtrip - get the current auxtrip value from sensor - * @name: Thermalzone name - * @auxtype : AUX0/AUX1 - * @buf: syfs buffer + * @handle: Object handle + * @index : GET_AUX1/GET_AUX0 + * @value : The address will be fill by the value */ static int sensor_get_auxtrip(acpi_handle handle, int index, unsigned long long *value) @@ -254,9 +254,9 @@ static int sensor_get_auxtrip(acpi_handle handle, int index, /* * sensor_set_auxtrip - set the new auxtrip value to sensor - * @name: Thermalzone name - * @auxtype : AUX0/AUX1 - * @buf: syfs buffer + * @handle: Object handle + * @index : GET_AUX1/GET_AUX0 + * @value : The value will be set */ static int sensor_set_auxtrip(acpi_handle handle, int index, int value) { -- cgit v1.2.3 From 763bd29fd3d1742153f6c6847ca3b3560e7ca957 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Tue, 17 Jan 2023 10:42:17 +0800 Subject: thermal: int340x_thermal: Use sysfs_emit_at() instead of scnprintf() Follow the advice of the Documentation/filesystems/sysfs.rst that show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. Signed-off-by: ye xingchen [ rjw: Subject rewrite ] Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index db8a6f63657d..c1fc4a78607c 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -130,10 +130,7 @@ static ssize_t available_uuids_show(struct device *dev, for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) { if (priv->uuid_bitmap & (1 << i)) - length += scnprintf(&buf[length], - PAGE_SIZE - length, - "%s\n", - int3400_thermal_uuids[i]); + length += sysfs_emit_at(buf, length, int3400_thermal_uuids[i]); } return length; @@ -151,10 +148,7 @@ static ssize_t current_uuid_show(struct device *dev, for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) { if (priv->os_uuid_mask & BIT(i)) - length += scnprintf(&buf[length], - PAGE_SIZE - length, - "%s\n", - int3400_thermal_uuids[i]); + length += sysfs_emit_at(buf, length, int3400_thermal_uuids[i]); } if (length) -- cgit v1.2.3 From 40dc1929089fc844ea06d9f8bdb6211ed4517c2e Mon Sep 17 00:00:00 2001 From: Tim Zimmermann Date: Sat, 7 Jan 2023 20:25:13 +0100 Subject: thermal: intel: intel_pch: Add support for Wellsburg PCH Add the PCI ID for the Wellsburg C610 series chipset PCH. The driver can read the temperature from the Wellsburg PCH with only the PCI ID added and no other modifications. Signed-off-by: Tim Zimmermann Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/intel_pch_thermal.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c index dabf11a687a1..9e27f430e034 100644 --- a/drivers/thermal/intel/intel_pch_thermal.c +++ b/drivers/thermal/intel/intel_pch_thermal.c @@ -29,6 +29,7 @@ #define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */ #define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */ #define PCH_THERMAL_DID_LWB 0xA1B1 /* Lewisburg PCH */ +#define PCH_THERMAL_DID_WBG 0x8D24 /* Wellsburg PCH */ /* Wildcat Point-LP PCH Thermal registers */ #define WPT_TEMP 0x0000 /* Temperature */ @@ -350,6 +351,7 @@ enum board_ids { board_cnl, board_cml, board_lwb, + board_wbg, }; static const struct board_info { @@ -380,6 +382,10 @@ static const struct board_info { .name = "pch_lewisburg", .ops = &pch_dev_ops_wpt, }, + [board_wbg] = { + .name = "pch_wellsburg", + .ops = &pch_dev_ops_wpt, + }, }; static int intel_pch_thermal_probe(struct pci_dev *pdev, @@ -495,6 +501,8 @@ static const struct pci_device_id intel_pch_thermal_id[] = { .driver_data = board_cml, }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_LWB), .driver_data = board_lwb, }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WBG), + .driver_data = board_wbg, }, { 0, }, }; MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id); -- cgit v1.2.3 From 7a0e39748861272e6f4b088d5a7e7ffa53c4d5eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 23 Jan 2023 19:38:31 +0100 Subject: thermal: ACPI: Add ACPI trip point routines Add library routines to populate a generic thermal trip point structure with data obtained by evaluating a specific object in the ACPI Namespace. Signed-off-by: Rafael J. Wysocki Co-developed-by: Daniel Lezcano Signed-off-by: Daniel Lezcano Tested-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 4 ++ drivers/thermal/Makefile | 1 + drivers/thermal/thermal_acpi.c | 150 +++++++++++++++++++++++++++++++++++++++++ include/linux/thermal.h | 8 +++ 4 files changed, 163 insertions(+) create mode 100644 drivers/thermal/thermal_acpi.c (limited to 'drivers/thermal') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index e052dae614eb..eaeb2b2ee6e9 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -76,6 +76,10 @@ config THERMAL_OF Say 'Y' here if you need to build thermal infrastructure based on device tree. +config THERMAL_ACPI + depends on ACPI + bool + config THERMAL_WRITABLE_TRIPS bool "Enable writable trip points" help diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 2506c6c8ca83..60f0dfa9aae2 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -13,6 +13,7 @@ thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o # interface to/from other layers providing sensors thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o +thermal_sys-$(CONFIG_THERMAL_ACPI) += thermal_acpi.o # governors thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += gov_fair_share.o diff --git a/drivers/thermal/thermal_acpi.c b/drivers/thermal/thermal_acpi.c new file mode 100644 index 000000000000..f65281ca3ed0 --- /dev/null +++ b/drivers/thermal/thermal_acpi.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 Linaro Limited + * Copyright 2023 Intel Corporation + * + * Library routines for populating a generic thermal trip point structure + * with data obtained by evaluating a specific object in the ACPI Namespace. + */ +#include +#include + +#include "thermal_core.h" + +/* + * Minimum temperature for full military grade is 218°K (-55°C) and + * max temperature is 448°K (175°C). We can consider those values as + * the boundaries for the [trips] temperature returned by the + * firmware. Any values out of these boundaries may be considered + * bogus and we can assume the firmware has no data to provide. + */ +#define TEMP_MIN_DECIK 2180 +#define TEMP_MAX_DECIK 4480 + +static int thermal_acpi_trip_init(struct acpi_device *adev, + enum thermal_trip_type type, int id, + struct thermal_trip *trip) +{ + unsigned long long temp; + acpi_status status; + char obj_name[5]; + + switch (type) { + case THERMAL_TRIP_ACTIVE: + if (id < 0 || id > 9) + return -EINVAL; + + obj_name[1] = 'A'; + obj_name[2] = 'C'; + obj_name[3] = '0' + id; + break; + case THERMAL_TRIP_PASSIVE: + obj_name[1] = 'P'; + obj_name[2] = 'S'; + obj_name[3] = 'V'; + break; + case THERMAL_TRIP_HOT: + obj_name[1] = 'H'; + obj_name[2] = 'O'; + obj_name[3] = 'T'; + break; + case THERMAL_TRIP_CRITICAL: + obj_name[1] = 'C'; + obj_name[2] = 'R'; + obj_name[3] = 'T'; + break; + } + + obj_name[0] = '_'; + obj_name[4] = '\0'; + + status = acpi_evaluate_integer(adev->handle, obj_name, NULL, &temp); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(adev->handle, "%s evaluation failed\n", obj_name); + return -ENODATA; + } + + if (temp < TEMP_MIN_DECIK || temp >= TEMP_MAX_DECIK) { + acpi_handle_debug(adev->handle, "%s result %llu out of range\n", + obj_name, temp); + return -ENODATA; + } + + trip->temperature = deci_kelvin_to_millicelsius(temp); + trip->hysteresis = 0; + trip->type = type; + + return 0; +} + +/** + * thermal_acpi_trip_active - Get the specified active trip point + * @adev: Thermal zone ACPI device object to get the description from. + * @id: Active cooling level (0 - 9). + * @trip: Trip point structure to be populated on success. + * + * Evaluate the _ACx object for the thermal zone represented by @adev to obtain + * the temperature of the active cooling trip point corresponding to the active + * cooling level given by @id and initialize @trip as an active trip point using + * that temperature value. + * + * Return 0 on success or a negative error value on failure. + */ +int thermal_acpi_trip_active(struct acpi_device *adev, int id, + struct thermal_trip *trip) +{ + return thermal_acpi_trip_init(adev, THERMAL_TRIP_ACTIVE, id, trip); +} +EXPORT_SYMBOL_GPL(thermal_acpi_trip_active); + +/** + * thermal_acpi_trip_passive - Get the passive trip point + * @adev: Thermal zone ACPI device object to get the description from. + * @trip: Trip point structure to be populated on success. + * + * Evaluate the _PSV object for the thermal zone represented by @adev to obtain + * the temperature of the passive cooling trip point and initialize @trip as a + * passive trip point using that temperature value. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_trip_passive(struct acpi_device *adev, struct thermal_trip *trip) +{ + return thermal_acpi_trip_init(adev, THERMAL_TRIP_PASSIVE, INT_MAX, trip); +} +EXPORT_SYMBOL_GPL(thermal_acpi_trip_passive); + +/** + * thermal_acpi_trip_hot - Get the near critical trip point + * @adev: the ACPI device to get the description from. + * @trip: a &struct thermal_trip to be filled if the function succeed. + * + * Evaluate the _HOT object for the thermal zone represented by @adev to obtain + * the temperature of the trip point at which the system is expected to be put + * into the S4 sleep state and initialize @trip as a hot trip point using that + * temperature value. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_trip_hot(struct acpi_device *adev, struct thermal_trip *trip) +{ + return thermal_acpi_trip_init(adev, THERMAL_TRIP_HOT, INT_MAX, trip); +} +EXPORT_SYMBOL_GPL(thermal_acpi_trip_hot); + +/** + * thermal_acpi_trip_critical - Get the critical trip point + * @adev: the ACPI device to get the description from. + * @trip: a &struct thermal_trip to be filled if the function succeed. + * + * Evaluate the _CRT object for the thermal zone represented by @adev to obtain + * the temperature of the critical cooling trip point and initialize @trip as a + * critical trip point using that temperature value. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_trip_critical(struct acpi_device *adev, struct thermal_trip *trip) +{ + return thermal_acpi_trip_init(adev, THERMAL_TRIP_CRITICAL, INT_MAX, trip); +} +EXPORT_SYMBOL_GPL(thermal_acpi_trip_critical); diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 30353e4b1424..23c2617156b5 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -346,6 +346,14 @@ int thermal_zone_get_num_trips(struct thermal_zone_device *tz); int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp); +#ifdef CONFIG_THERMAL_ACPI +int thermal_acpi_trip_active(struct acpi_device *adev, int id, + struct thermal_trip *trip); +int thermal_acpi_trip_passive(struct acpi_device *adev, struct thermal_trip *trip); +int thermal_acpi_trip_hot(struct acpi_device *adev, struct thermal_trip *trip); +int thermal_acpi_trip_critical(struct acpi_device *adev, struct thermal_trip *trip); +#endif + #ifdef CONFIG_THERMAL struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, void *, struct thermal_zone_device_ops *, -- cgit v1.2.3 From fee19c692160ae83f50e7b561076e4bd4cceb830 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 23 Jan 2023 19:40:33 +0100 Subject: thermal: intel: intel_pch: Use generic trip points The thermal framework gives the possibility to register the trip points along with the thermal zone. When that is done, no get_trip_* callbacks are needed and they can be removed. Convert the existing callbacks content logic into generic trip points initialization code and register them along with the thermal zone. In order to consolidate the code, use an ACPI trip library function to populate a generic trip point. Signed-off-by: Daniel Lezcano Reviewed-by: Zhang Rui [ rjw: Subject and changelog edits, rebase ] Signed-off-by: Rafael J. Wysocki Tested-by: Srinivas Pandruvada --- drivers/thermal/intel/Kconfig | 1 + drivers/thermal/intel/intel_pch_thermal.c | 88 +++++++------------------------ 2 files changed, 20 insertions(+), 69 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index fd41c810629b..e50fd260484a 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -81,6 +81,7 @@ config INTEL_BXT_PMIC_THERMAL config INTEL_PCH_THERMAL tristate "Intel PCH Thermal Reporting Driver" depends on X86 && PCI + select THERMAL_ACPI if ACPI help Enable this to support thermal reporting on certain intel PCHs. Thermal reporting device will provide temperature reading, diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c index 9e27f430e034..cc4e9d28496b 100644 --- a/drivers/thermal/intel/intel_pch_thermal.c +++ b/drivers/thermal/intel/intel_pch_thermal.c @@ -66,6 +66,8 @@ #define WPT_TEMP_OFFSET (PCH_TEMP_OFFSET * MILLIDEGREE_PER_DEGREE) #define GET_PCH_TEMP(x) (((x) / 2) + PCH_TEMP_OFFSET) +#define PCH_MAX_TRIPS 3 /* critical, hot, passive */ + /* Amount of time for each cooling delay, 100ms by default for now */ static unsigned int delay_timeout = 100; module_param(delay_timeout, int, 0644); @@ -83,12 +85,7 @@ struct pch_thermal_device { const struct pch_dev_ops *ops; struct pci_dev *pdev; struct thermal_zone_device *tzd; - int crt_trip_id; - unsigned long crt_temp; - int hot_trip_id; - unsigned long hot_temp; - int psv_trip_id; - unsigned long psv_temp; + struct thermal_trip trips[PCH_MAX_TRIPS]; bool bios_enabled; }; @@ -103,33 +100,22 @@ static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, int *nr_trips) { struct acpi_device *adev; - - ptd->psv_trip_id = -1; + int ret; adev = ACPI_COMPANION(&ptd->pdev->dev); - if (adev) { - unsigned long long r; - acpi_status status; - - status = acpi_evaluate_integer(adev->handle, "_PSV", NULL, - &r); - if (ACPI_SUCCESS(status)) { - unsigned long trip_temp; - - trip_temp = deci_kelvin_to_millicelsius(r); - if (trip_temp) { - ptd->psv_temp = trip_temp; - ptd->psv_trip_id = *nr_trips; - ++(*nr_trips); - } - } - } + if (!adev) + return; + + ret = thermal_acpi_trip_passive(adev, &ptd->trips[*nr_trips]); + if (ret) + return; + + ++(*nr_trips); } #else static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, int *nr_trips) { - ptd->psv_trip_id = -1; } #endif @@ -164,21 +150,19 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) } read_trips: - ptd->crt_trip_id = -1; trip_temp = readw(ptd->hw_base + WPT_CTT); trip_temp &= 0x1FF; if (trip_temp) { - ptd->crt_temp = GET_WPT_TEMP(trip_temp); - ptd->crt_trip_id = 0; + ptd->trips[*nr_trips].temperature = GET_WPT_TEMP(trip_temp); + ptd->trips[*nr_trips].type = THERMAL_TRIP_CRITICAL; ++(*nr_trips); } - ptd->hot_trip_id = -1; trip_temp = readw(ptd->hw_base + WPT_PHL); trip_temp &= 0x1FF; if (trip_temp) { - ptd->hot_temp = GET_WPT_TEMP(trip_temp); - ptd->hot_trip_id = *nr_trips; + ptd->trips[*nr_trips].temperature = GET_WPT_TEMP(trip_temp); + ptd->trips[*nr_trips].type = THERMAL_TRIP_HOT; ++(*nr_trips); } @@ -299,39 +283,6 @@ static int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp) return ptd->ops->get_temp(ptd, temp); } -static int pch_get_trip_type(struct thermal_zone_device *tzd, int trip, - enum thermal_trip_type *type) -{ - struct pch_thermal_device *ptd = tzd->devdata; - - if (ptd->crt_trip_id == trip) - *type = THERMAL_TRIP_CRITICAL; - else if (ptd->hot_trip_id == trip) - *type = THERMAL_TRIP_HOT; - else if (ptd->psv_trip_id == trip) - *type = THERMAL_TRIP_PASSIVE; - else - return -EINVAL; - - return 0; -} - -static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *temp) -{ - struct pch_thermal_device *ptd = tzd->devdata; - - if (ptd->crt_trip_id == trip) - *temp = ptd->crt_temp; - else if (ptd->hot_trip_id == trip) - *temp = ptd->hot_temp; - else if (ptd->psv_trip_id == trip) - *temp = ptd->psv_temp; - else - return -EINVAL; - - return 0; -} - static void pch_critical(struct thermal_zone_device *tzd) { dev_dbg(&tzd->device, "%s: critical temperature reached\n", tzd->type); @@ -339,8 +290,6 @@ static void pch_critical(struct thermal_zone_device *tzd) static struct thermal_zone_device_ops tzd_ops = { .get_temp = pch_thermal_get_temp, - .get_trip_type = pch_get_trip_type, - .get_trip_temp = pch_get_trip_temp, .critical = pch_critical, }; @@ -429,8 +378,9 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev, if (err) goto error_cleanup; - ptd->tzd = thermal_zone_device_register(bi->name, nr_trips, 0, ptd, - &tzd_ops, NULL, 0, 0); + ptd->tzd = thermal_zone_device_register_with_trips(bi->name, ptd->trips, + nr_trips, 0, ptd, + &tzd_ops, NULL, 0, 0); if (IS_ERR(ptd->tzd)) { dev_err(&pdev->dev, "Failed to register thermal zone %s\n", bi->name); -- cgit v1.2.3 From 5c36cf27846a364f830e5ea86b411e05f7c8bd2b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 23 Jan 2023 08:30:46 -0800 Subject: thermal: intel: int340x: Add production mode attribute It is possible that the system manufacturer locks down thermal tuning beyond what is usually done on the given platform. In that case user space calibration tools should not try to adjust the thermal configuration of the system. To allow user space to check if that is the case, add a new sysfs attribute "production_mode" that will be present when the ACPI DCFG method is present under the INT3400 device object in the ACPI Namespace. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki --- Documentation/driver-api/thermal/intel_dptf.rst | 3 ++ .../intel/int340x_thermal/int3400_thermal.c | 48 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'drivers/thermal') diff --git a/Documentation/driver-api/thermal/intel_dptf.rst b/Documentation/driver-api/thermal/intel_dptf.rst index 372bdb4d04c6..f5c193cccbda 100644 --- a/Documentation/driver-api/thermal/intel_dptf.rst +++ b/Documentation/driver-api/thermal/intel_dptf.rst @@ -84,6 +84,9 @@ DPTF ACPI Drivers interface https:/github.com/intel/thermal_daemon for decoding thermal table. +``production_mode`` (RO) + When different from zero, manufacturer locked thermal configuration + from further changes. ACPI Thermal Relationship table interface ------------------------------------------ diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index c1fc4a78607c..d0295123cc3e 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -60,6 +60,7 @@ struct int3400_thermal_priv { int odvp_count; int *odvp; u32 os_uuid_mask; + int production_mode; struct odvp_attr *odvp_attrs; }; @@ -309,6 +310,44 @@ end: return result; } +static ssize_t production_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct int3400_thermal_priv *priv = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", priv->production_mode); +} + +static DEVICE_ATTR_RO(production_mode); + +static int production_mode_init(struct int3400_thermal_priv *priv) +{ + unsigned long long mode; + acpi_status status; + int ret; + + priv->production_mode = -1; + + status = acpi_evaluate_integer(priv->adev->handle, "DCFG", NULL, &mode); + /* If the method is not present, this is not an error */ + if (ACPI_FAILURE(status)) + return 0; + + ret = sysfs_create_file(&priv->pdev->dev.kobj, &dev_attr_production_mode.attr); + if (ret) + return ret; + + priv->production_mode = mode; + + return 0; +} + +static void production_mode_exit(struct int3400_thermal_priv *priv) +{ + if (priv->production_mode >= 0) + sysfs_remove_file(&priv->pdev->dev.kobj, &dev_attr_production_mode.attr); +} + static ssize_t odvp_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -604,8 +643,15 @@ static int int3400_thermal_probe(struct platform_device *pdev) if (result) goto free_sysfs; + result = production_mode_init(priv); + if (result) + goto free_notify; + return 0; +free_notify: + acpi_remove_notify_handler(priv->adev->handle, ACPI_DEVICE_NOTIFY, + int3400_notify); free_sysfs: cleanup_odvp(priv); if (!ZERO_OR_NULL_PTR(priv->data_vault)) { @@ -632,6 +678,8 @@ static int int3400_thermal_remove(struct platform_device *pdev) { struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); + production_mode_exit(priv); + acpi_remove_notify_handler( priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify); -- cgit v1.2.3 From e90eb1df708c07240e323a4dbec8313736d1b500 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 18 Jan 2023 19:16:20 +0100 Subject: thermal: intel: processor_thermal_device_pci: Use generic trip point Make proc_thermal_pci_probe() register the TCPU_PCI thermal zone along with the trip point used by it and drop the zone callbacks related to this trip point that are not needed any more. Signed-off-by: Daniel Lezcano [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- .../int340x_thermal/processor_thermal_device_pci.c | 53 +++++++++------------- 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c index bf1b1cdfade4..40725cbc6eb0 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -144,34 +144,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) return 0; } -static int sys_get_trip_temp(struct thermal_zone_device *tzd, - int trip, int *temp) -{ - struct proc_thermal_pci *pci_info = tzd->devdata; - u32 _temp; - - proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &_temp); - if (!_temp) { - *temp = THERMAL_TEMP_INVALID; - } else { - int tjmax; - - proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax); - _temp = tjmax - _temp; - *temp = (unsigned long)_temp * 1000; - } - - return 0; -} - -static int sys_get_trip_type(struct thermal_zone_device *tzd, int trip, - enum thermal_trip_type *type) -{ - *type = THERMAL_TRIP_PASSIVE; - - return 0; -} - static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) { struct proc_thermal_pci *pci_info = tzd->devdata; @@ -200,10 +172,26 @@ static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp return 0; } +static int get_trip_temp(struct proc_thermal_pci *pci_info) +{ + int temp, tjmax; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &temp); + if (!temp) + return THERMAL_TEMP_INVALID; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax); + temp = (tjmax - temp) * 1000; + + return temp; +} + +static struct thermal_trip psv_trip = { + .type = THERMAL_TRIP_PASSIVE, +}; + 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, }; @@ -251,7 +239,10 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_ if (ret) goto err_ret_thermal; - pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info, + psv_trip.temperature = get_trip_temp(pci_info); + + pci_info->tzone = thermal_zone_device_register_with_trips("TCPU_PCI", &psv_trip, + 1, 1, pci_info, &tzone_ops, &tzone_params, 0, 0); if (IS_ERR(pci_info->tzone)) { -- cgit v1.2.3 From 97efecfdbf6fe4915e7f71603b634d5ad3f210b1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 26 Jan 2023 13:53:49 +0100 Subject: thermal: ACPI: Initialize trips if temperature is out of range In some cases it is still useful to register a trip point if the temperature returned by the corresponding ACPI thermal object (for example, _HOT) is invalid to start with, because the same ACPI thermal object may start to return a valid temperature after a system configuration change (for example, from an AC power source to battery an vice versa). For this reason, if the ACPI thermal object evaluated by thermal_acpi_trip_init() successfully returns a temperature value that is out of the range of values taken into account, initialize the trip point using THERMAL_TEMP_INVALID as the temperature value instead of returning an error to allow the user of the trip point to decide what to do with it. Also update pch_wpt_add_acpi_psv_trip() to reject trip points with invalid temperature values. Fixes: 7a0e39748861 ("thermal: ACPI: Add ACPI trip point routines") Reported-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/intel_pch_thermal.c | 2 +- drivers/thermal/thermal_acpi.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c index cc4e9d28496b..45a9ea86907e 100644 --- a/drivers/thermal/intel/intel_pch_thermal.c +++ b/drivers/thermal/intel/intel_pch_thermal.c @@ -107,7 +107,7 @@ static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, return; ret = thermal_acpi_trip_passive(adev, &ptd->trips[*nr_trips]); - if (ret) + if (ret || ptd->trips[*nr_trips].temperature <= 0) return; ++(*nr_trips); diff --git a/drivers/thermal/thermal_acpi.c b/drivers/thermal/thermal_acpi.c index f65281ca3ed0..671f774a7621 100644 --- a/drivers/thermal/thermal_acpi.c +++ b/drivers/thermal/thermal_acpi.c @@ -64,13 +64,14 @@ static int thermal_acpi_trip_init(struct acpi_device *adev, return -ENODATA; } - if (temp < TEMP_MIN_DECIK || temp >= TEMP_MAX_DECIK) { + if (temp >= TEMP_MIN_DECIK && temp <= TEMP_MAX_DECIK) { + trip->temperature = deci_kelvin_to_millicelsius(temp); + } else { acpi_handle_debug(adev->handle, "%s result %llu out of range\n", obj_name, temp); - return -ENODATA; + trip->temperature = THERMAL_TEMP_INVALID; } - trip->temperature = deci_kelvin_to_millicelsius(temp); trip->hysteresis = 0; trip->type = type; -- cgit v1.2.3 From b1bf9dbffc3049ca22ab36cb807b671655a936d0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 25 Jan 2023 15:52:25 +0100 Subject: thermal: intel: int340x: Rework updating trip points It is generally invalid to change the trip point indices after they have been exposed via sysfs. Moreover, the thermal objects in the ACPI namespace cannot go away and appear on the fly. In practice, the only thing that can happen when the INT3403_PERF_TRIP_POINT_CHANGED notification is sent by the platform firmware is a change of the return values of those thermal objects. For this reason, add a special function for updating the trip point temperatures after re-evaluating the respective ACPI thermal objects and change int3403_notify() to invoke it instead of int340x_thermal_read_trips() that would change the trip point indices on errors. Also remove the locking from the latter, because it is only called before registering the thermal zone and it cannot race with the zone's callbacks. Signed-off-by: Rafael J. Wysocki --- .../intel/int340x_thermal/int3403_thermal.c | 2 +- .../intel/int340x_thermal/int340x_thermal_zone.c | 51 +++++++++++++++++++--- .../intel/int340x_thermal/int340x_thermal_zone.h | 2 +- 3 files changed, 47 insertions(+), 8 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c index 71d084c4c456..e418d270bc76 100644 --- a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c @@ -69,7 +69,7 @@ static void int3403_notify(acpi_handle handle, THERMAL_TRIP_VIOLATED); break; case INT3403_PERF_TRIP_POINT_CHANGED: - int340x_thermal_read_trips(obj->int340x_zone); + int340x_thermal_update_trips(obj->int340x_zone); int340x_thermal_zone_device_update(obj->int340x_zone, THERMAL_TRIP_CHANGED); break; diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c index 40c1e8a8bc1b..78768d0b0d9d 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c @@ -168,13 +168,11 @@ static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, return 0; } -int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) +static int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) { int trip_cnt = int34x_zone->aux_trip_nr; int i; - mutex_lock(&int34x_zone->trip_mutex); - int34x_zone->crt_trip_id = -1; if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT", &int34x_zone->crt_temp)) @@ -202,11 +200,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) int34x_zone->act_trips[i].valid = true; } - mutex_unlock(&int34x_zone->trip_mutex); - return trip_cnt; } -EXPORT_SYMBOL_GPL(int340x_thermal_read_trips); static struct thermal_zone_params int340x_thermal_params = { .governor_name = "user_space", @@ -309,6 +304,50 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone } EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); +void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone) +{ + acpi_handle zone_handle = int34x_zone->adev->handle; + int i, err; + + mutex_lock(&int34x_zone->trip_mutex); + + if (int34x_zone->crt_trip_id > 0) { + err = int340x_thermal_get_trip_config(zone_handle, "_CRT", + &int34x_zone->crt_temp); + if (err) + int34x_zone->crt_temp = THERMAL_TEMP_INVALID; + } + + if (int34x_zone->hot_trip_id > 0) { + err = int340x_thermal_get_trip_config(zone_handle, "_HOT", + &int34x_zone->hot_temp); + if (err) + int34x_zone->hot_temp = THERMAL_TEMP_INVALID; + } + + if (int34x_zone->psv_trip_id > 0) { + err = int340x_thermal_get_trip_config(zone_handle, "_PSV", + &int34x_zone->psv_temp); + if (err) + int34x_zone->psv_temp = THERMAL_TEMP_INVALID; + } + + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { + char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; + + if (!int34x_zone->act_trips[i].valid) + break; + + err = int340x_thermal_get_trip_config(zone_handle, name, + &int34x_zone->act_trips[i].temp); + if (err) + int34x_zone->act_trips[i].temp = THERMAL_TEMP_INVALID; + } + + mutex_unlock(&int34x_zone->trip_mutex); +} +EXPORT_SYMBOL_GPL(int340x_thermal_update_trips); + MODULE_AUTHOR("Aaron Lu "); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("Intel INT340x common thermal zone handler"); diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h index 6610a9cc441b..0a7b0f009aa0 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h @@ -38,7 +38,7 @@ struct int34x_thermal_zone { struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, int (*get_temp) (struct thermal_zone_device *, int *)); void int340x_thermal_zone_remove(struct int34x_thermal_zone *); -int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone); +void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone); static inline void int340x_thermal_zone_set_priv_data( struct int34x_thermal_zone *tzone, void *priv_data) -- cgit v1.2.3 From 9e9b7e182cf34ce5e5f50f1fa2470d051e3c8f90 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 25 Jan 2023 15:54:03 +0100 Subject: thermal: intel: int340x: Use zone lock for synchronization Because the ->get_trip_temp() and ->get_trip_type() thermal zone callbacks are only invoked from __thermal_zone_get_trip() which is always called by the thermal core under the zone lock, it is sufficient for int340x_thermal_update_trips() to acquire the zone lock for mutual exclusion with those callbacks. Accordingly, modify int340x_thermal_update_trips() to use the zone lock instead of the internal trip_mutex and drop the latter which is not necessary any more. Signed-off-by: Rafael J. Wysocki --- .../intel/int340x_thermal/int340x_thermal_zone.c | 28 +++++++--------------- .../intel/int340x_thermal/int340x_thermal_zone.h | 1 - 2 files changed, 8 insertions(+), 21 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c index 78768d0b0d9d..dfc159367f84 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c @@ -41,9 +41,7 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, int trip, int *temp) { struct int34x_thermal_zone *d = zone->devdata; - int i, ret = 0; - - mutex_lock(&d->trip_mutex); + int i; if (trip < d->aux_trip_nr) *temp = d->aux_trips[trip]; @@ -62,12 +60,10 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, } } if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - ret = -EINVAL; + return -EINVAL; } - mutex_unlock(&d->trip_mutex); - - return ret; + return 0; } static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, @@ -75,9 +71,7 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, enum thermal_trip_type *type) { struct int34x_thermal_zone *d = zone->devdata; - int i, ret = 0; - - mutex_lock(&d->trip_mutex); + int i; if (trip < d->aux_trip_nr) *type = THERMAL_TRIP_PASSIVE; @@ -96,12 +90,10 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, } } if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - ret = -EINVAL; + return -EINVAL; } - mutex_unlock(&d->trip_mutex); - - return ret; + return 0; } static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, @@ -222,8 +214,6 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, if (!int34x_thermal_zone) return ERR_PTR(-ENOMEM); - mutex_init(&int34x_thermal_zone->trip_mutex); - int34x_thermal_zone->adev = adev; int34x_thermal_zone->ops = kmemdup(&int340x_thermal_zone_ops, @@ -286,7 +276,6 @@ err_thermal_zone: err_trip_alloc: kfree(int34x_thermal_zone->ops); err_ops_alloc: - mutex_destroy(&int34x_thermal_zone->trip_mutex); kfree(int34x_thermal_zone); return ERR_PTR(ret); } @@ -299,7 +288,6 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); kfree(int34x_thermal_zone->aux_trips); kfree(int34x_thermal_zone->ops); - mutex_destroy(&int34x_thermal_zone->trip_mutex); kfree(int34x_thermal_zone); } EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); @@ -309,7 +297,7 @@ void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone) acpi_handle zone_handle = int34x_zone->adev->handle; int i, err; - mutex_lock(&int34x_zone->trip_mutex); + mutex_lock(&int34x_zone->zone->lock); if (int34x_zone->crt_trip_id > 0) { err = int340x_thermal_get_trip_config(zone_handle, "_CRT", @@ -344,7 +332,7 @@ void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone) int34x_zone->act_trips[i].temp = THERMAL_TEMP_INVALID; } - mutex_unlock(&int34x_zone->trip_mutex); + mutex_unlock(&int34x_zone->zone->lock); } EXPORT_SYMBOL_GPL(int340x_thermal_update_trips); diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h index 0a7b0f009aa0..72a00581a46b 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h @@ -32,7 +32,6 @@ struct int34x_thermal_zone { struct thermal_zone_device_ops *ops; void *priv_data; struct acpi_lpat_conversion_table *lpat_table; - struct mutex trip_mutex; }; struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, -- cgit v1.2.3 From f4118dbe61bb30038ca7f3ecaf333cabc9c54141 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 25 Jan 2023 15:55:24 +0100 Subject: thermal: intel: int340x: Use generic trip points table Modify int340x_thermal_zone_add() to register the thermal zone along with a trip points table, which allows the trip-related zone callbacks to be dropped, because they are not needed any more. In order to consolidate the code, use ACPI trip library functions to populate generic trip points in int340x_thermal_read_trips() and to update them in int340x_thermal_update_trips(). Signed-off-by: Daniel Lezcano Co-developed-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/Kconfig | 1 + .../intel/int340x_thermal/int340x_thermal_zone.c | 253 +++++++-------------- .../intel/int340x_thermal/int340x_thermal_zone.h | 10 +- 3 files changed, 84 insertions(+), 180 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig index 0f511917e0e1..300ea53e9b33 100644 --- a/drivers/thermal/intel/int340x_thermal/Kconfig +++ b/drivers/thermal/intel/int340x_thermal/Kconfig @@ -9,6 +9,7 @@ config INT340X_THERMAL select THERMAL_GOV_USER_SPACE select ACPI_THERMAL_REL select ACPI_FAN + select THERMAL_ACPI select INTEL_SOC_DTS_IOSF_CORE select INTEL_TCC select PROC_THERMAL_MMIO_RAPL if POWERCAP diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c index dfc159367f84..09b1b51eb6a5 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c @@ -37,65 +37,6 @@ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, return 0; } -static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, - int trip, int *temp) -{ - struct int34x_thermal_zone *d = zone->devdata; - int i; - - if (trip < d->aux_trip_nr) - *temp = d->aux_trips[trip]; - else if (trip == d->crt_trip_id) - *temp = d->crt_temp; - else if (trip == d->psv_trip_id) - *temp = d->psv_temp; - else if (trip == d->hot_trip_id) - *temp = d->hot_temp; - else { - for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { - if (d->act_trips[i].valid && - d->act_trips[i].id == trip) { - *temp = d->act_trips[i].temp; - break; - } - } - if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - return -EINVAL; - } - - return 0; -} - -static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, - int trip, - enum thermal_trip_type *type) -{ - struct int34x_thermal_zone *d = zone->devdata; - int i; - - if (trip < d->aux_trip_nr) - *type = THERMAL_TRIP_PASSIVE; - else if (trip == d->crt_trip_id) - *type = THERMAL_TRIP_CRITICAL; - else if (trip == d->hot_trip_id) - *type = THERMAL_TRIP_HOT; - else if (trip == d->psv_trip_id) - *type = THERMAL_TRIP_PASSIVE; - else { - for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { - if (d->act_trips[i].valid && - d->act_trips[i].id == trip) { - *type = THERMAL_TRIP_ACTIVE; - break; - } - } - if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - return -EINVAL; - } - - return 0; -} - static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip, int temp) { @@ -109,25 +50,6 @@ static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, if (ACPI_FAILURE(status)) return -EIO; - d->aux_trips[trip] = temp; - - return 0; -} - - -static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, - int trip, int *temp) -{ - struct int34x_thermal_zone *d = zone->devdata; - acpi_status status; - unsigned long long hyst; - - status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst); - if (ACPI_FAILURE(status)) - *temp = 0; - else - *temp = hyst * 100; - return 0; } @@ -138,58 +60,35 @@ static void int340x_thermal_critical(struct thermal_zone_device *zone) static struct thermal_zone_device_ops int340x_thermal_zone_ops = { .get_temp = int340x_thermal_get_zone_temp, - .get_trip_temp = int340x_thermal_get_trip_temp, - .get_trip_type = int340x_thermal_get_trip_type, .set_trip_temp = int340x_thermal_set_trip_temp, - .get_trip_hyst = int340x_thermal_get_trip_hyst, .critical = int340x_thermal_critical, }; -static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, - int *temp) +static int int340x_thermal_read_trips(struct acpi_device *zone_adev, + struct thermal_trip *zone_trips, + int trip_cnt) { - unsigned long long r; - acpi_status status; + int i, ret; - status = acpi_evaluate_integer(handle, name, NULL, &r); - if (ACPI_FAILURE(status)) - return -EIO; + ret = thermal_acpi_trip_critical(zone_adev, &zone_trips[trip_cnt]); + if (!ret) + trip_cnt++; - *temp = deci_kelvin_to_millicelsius(r); + ret = thermal_acpi_trip_hot(zone_adev, &zone_trips[trip_cnt]); + if (!ret) + trip_cnt++; - return 0; -} - -static int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) -{ - int trip_cnt = int34x_zone->aux_trip_nr; - int i; - - int34x_zone->crt_trip_id = -1; - if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT", - &int34x_zone->crt_temp)) - int34x_zone->crt_trip_id = trip_cnt++; - - int34x_zone->hot_trip_id = -1; - if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_HOT", - &int34x_zone->hot_temp)) - int34x_zone->hot_trip_id = trip_cnt++; - - int34x_zone->psv_trip_id = -1; - if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_PSV", - &int34x_zone->psv_temp)) - int34x_zone->psv_trip_id = trip_cnt++; + ret = thermal_acpi_trip_passive(zone_adev, &zone_trips[trip_cnt]); + if (!ret) + trip_cnt++; for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { - char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; - if (int340x_thermal_get_trip_config(int34x_zone->adev->handle, - name, - &int34x_zone->act_trips[i].temp)) + ret = thermal_acpi_trip_active(zone_adev, i, &zone_trips[trip_cnt]); + if (ret) break; - int34x_zone->act_trips[i].id = trip_cnt++; - int34x_zone->act_trips[i].valid = true; + trip_cnt++; } return trip_cnt; @@ -204,10 +103,12 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, int (*get_temp) (struct thermal_zone_device *, int *)) { struct int34x_thermal_zone *int34x_thermal_zone; - acpi_status status; - unsigned long long trip_cnt; + struct thermal_trip *zone_trips; + unsigned long long trip_cnt = 0; + unsigned long long hyst; int trip_mask = 0; - int ret; + acpi_status status; + int i, ret; int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone), GFP_KERNEL); @@ -227,33 +128,42 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, int34x_thermal_zone->ops->get_temp = get_temp; status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); - if (ACPI_FAILURE(status)) - trip_cnt = 0; - else { - int i; - - int34x_thermal_zone->aux_trips = - kcalloc(trip_cnt, - sizeof(*int34x_thermal_zone->aux_trips), - GFP_KERNEL); - if (!int34x_thermal_zone->aux_trips) { - ret = -ENOMEM; - goto err_trip_alloc; - } - trip_mask = BIT(trip_cnt) - 1; + if (!ACPI_FAILURE(status)) { int34x_thermal_zone->aux_trip_nr = trip_cnt; - for (i = 0; i < trip_cnt; ++i) - int34x_thermal_zone->aux_trips[i] = THERMAL_TEMP_INVALID; + trip_mask = BIT(trip_cnt) - 1; + } + + zone_trips = kzalloc(sizeof(*zone_trips) * (trip_cnt + INT340X_THERMAL_MAX_TRIP_COUNT), + GFP_KERNEL); + if (!zone_trips) { + ret = -ENOMEM; + goto err_trips_alloc; + } + + for (i = 0; i < trip_cnt; i++) { + zone_trips[i].type = THERMAL_TRIP_PASSIVE; + zone_trips[i].temperature = THERMAL_TEMP_INVALID; } - trip_cnt = int340x_thermal_read_trips(int34x_thermal_zone); + trip_cnt = int340x_thermal_read_trips(adev, zone_trips, trip_cnt); + + status = acpi_evaluate_integer(adev->handle, "GTSH", NULL, &hyst); + if (ACPI_SUCCESS(status)) + hyst *= 100; + else + hyst = 0; + + for (i = 0; i < trip_cnt; ++i) + zone_trips[i].hysteresis = hyst; + + int34x_thermal_zone->trips = zone_trips; int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table( adev->handle); - int34x_thermal_zone->zone = thermal_zone_device_register( + int34x_thermal_zone->zone = thermal_zone_device_register_with_trips( acpi_device_bid(adev), - trip_cnt, + zone_trips, trip_cnt, trip_mask, int34x_thermal_zone, int34x_thermal_zone->ops, &int340x_thermal_params, @@ -271,9 +181,9 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, err_enable: thermal_zone_device_unregister(int34x_thermal_zone->zone); err_thermal_zone: + kfree(int34x_thermal_zone->trips); acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); - kfree(int34x_thermal_zone->aux_trips); -err_trip_alloc: +err_trips_alloc: kfree(int34x_thermal_zone->ops); err_ops_alloc: kfree(int34x_thermal_zone); @@ -286,7 +196,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone { thermal_zone_device_unregister(int34x_thermal_zone->zone); acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); - kfree(int34x_thermal_zone->aux_trips); + kfree(int34x_thermal_zone->trips); kfree(int34x_thermal_zone->ops); kfree(int34x_thermal_zone); } @@ -294,42 +204,41 @@ EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone) { - acpi_handle zone_handle = int34x_zone->adev->handle; - int i, err; + struct acpi_device *zone_adev = int34x_zone->adev; + struct thermal_trip *zone_trips = int34x_zone->trips; + int trip_cnt = int34x_zone->zone->num_trips; + int act_trip_nr = 0; + int i; mutex_lock(&int34x_zone->zone->lock); - if (int34x_zone->crt_trip_id > 0) { - err = int340x_thermal_get_trip_config(zone_handle, "_CRT", - &int34x_zone->crt_temp); - if (err) - int34x_zone->crt_temp = THERMAL_TEMP_INVALID; - } - - if (int34x_zone->hot_trip_id > 0) { - err = int340x_thermal_get_trip_config(zone_handle, "_HOT", - &int34x_zone->hot_temp); - if (err) - int34x_zone->hot_temp = THERMAL_TEMP_INVALID; - } - - if (int34x_zone->psv_trip_id > 0) { - err = int340x_thermal_get_trip_config(zone_handle, "_PSV", - &int34x_zone->psv_temp); - if (err) - int34x_zone->psv_temp = THERMAL_TEMP_INVALID; - } + for (i = int34x_zone->aux_trip_nr; i < trip_cnt; i++) { + struct thermal_trip trip; + int err; - for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { - char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; - - if (!int34x_zone->act_trips[i].valid) + switch (zone_trips[i].type) { + case THERMAL_TRIP_CRITICAL: + err = thermal_acpi_trip_critical(zone_adev, &trip); + break; + case THERMAL_TRIP_HOT: + err = thermal_acpi_trip_hot(zone_adev, &trip); break; + case THERMAL_TRIP_PASSIVE: + err = thermal_acpi_trip_passive(zone_adev, &trip); + break; + case THERMAL_TRIP_ACTIVE: + err = thermal_acpi_trip_active(zone_adev, act_trip_nr++, + &trip); + break; + default: + err = -ENODEV; + } + if (err) { + zone_trips[i].temperature = THERMAL_TEMP_INVALID; + continue; + } - err = int340x_thermal_get_trip_config(zone_handle, name, - &int34x_zone->act_trips[i].temp); - if (err) - int34x_zone->act_trips[i].temp = THERMAL_TEMP_INVALID; + zone_trips[i].temperature = trip.temperature; } mutex_unlock(&int34x_zone->zone->lock); diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h index 72a00581a46b..e0df6271facc 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h @@ -10,6 +10,7 @@ #include #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 +#define INT340X_THERMAL_MAX_TRIP_COUNT INT340X_THERMAL_MAX_ACT_TRIP_COUNT + 3 struct active_trip { int temp; @@ -19,15 +20,8 @@ struct active_trip { struct int34x_thermal_zone { struct acpi_device *adev; - struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT]; - unsigned long *aux_trips; + struct thermal_trip *trips; int aux_trip_nr; - int psv_temp; - int psv_trip_id; - int crt_temp; - int crt_trip_id; - int hot_temp; - int hot_trip_id; struct thermal_zone_device *zone; struct thermal_zone_device_ops *ops; void *priv_data; -- cgit v1.2.3