2019-05-29 07:18:02 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2015-03-02 13:12:58 -08:00
|
|
|
/*
|
|
|
|
* intel_soc_dts_iosf.c
|
|
|
|
* Copyright (c) 2015, Intel Corporation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2019-12-04 16:51:32 -08:00
|
|
|
#include <linux/bitops.h>
|
2022-12-19 23:46:17 +08:00
|
|
|
#include <linux/intel_tcc.h>
|
2015-03-02 13:12:58 -08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <asm/iosf_mbi.h>
|
|
|
|
#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
|
|
|
|
|
|
|
|
/* Mask for two trips in status bits */
|
|
|
|
#define SOC_DTS_TRIP_MASK 0x03
|
|
|
|
|
2023-08-10 21:12:32 +02:00
|
|
|
static int update_trip_temp(struct intel_soc_dts_sensors *sensors,
|
2023-08-10 21:11:26 +02:00
|
|
|
int thres_index, int temp)
|
2015-03-02 13:12:58 -08:00
|
|
|
{
|
|
|
|
int status;
|
|
|
|
u32 temp_out;
|
|
|
|
u32 out;
|
2019-12-04 16:51:32 -08:00
|
|
|
unsigned long update_ptps;
|
2015-03-02 13:12:58 -08:00
|
|
|
u32 store_ptps;
|
|
|
|
u32 store_ptmc;
|
|
|
|
u32 store_te_out;
|
|
|
|
u32 te_out;
|
|
|
|
u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
|
|
|
|
|
|
|
|
if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
|
|
|
|
int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
|
|
|
|
|
|
|
|
temp_out = (sensors->tj_max - temp) / 1000;
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTPS, &store_ptps);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2019-12-04 16:51:32 -08:00
|
|
|
update_ptps = store_ptps;
|
|
|
|
bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8);
|
|
|
|
out = update_ptps;
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTPS, out);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
pr_debug("update_trip_temp PTPS = %x\n", out);
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTMC, &out);
|
|
|
|
if (status)
|
|
|
|
goto err_restore_ptps;
|
|
|
|
|
|
|
|
store_ptmc = out;
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
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;
|
|
|
|
}
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTMC, out);
|
|
|
|
if (status)
|
|
|
|
goto err_restore_te_out;
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_TE_AUX0 + thres_index,
|
|
|
|
te_out);
|
|
|
|
if (status)
|
|
|
|
goto err_restore_te_out;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err_restore_te_out:
|
2015-11-11 19:59:29 +02:00
|
|
|
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTMC, store_te_out);
|
|
|
|
err_restore_ptmc:
|
2015-11-11 19:59:29 +02:00
|
|
|
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTMC, store_ptmc);
|
|
|
|
err_restore_ptps:
|
2015-11-11 19:59:29 +02:00
|
|
|
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTPS, store_ptps);
|
|
|
|
/* Nothing we can do if restore fails */
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2023-08-10 21:11:26 +02:00
|
|
|
static int configure_trip(struct intel_soc_dts_sensor_entry *dts,
|
|
|
|
int thres_index, enum thermal_trip_type trip_type,
|
|
|
|
int temp)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2023-08-10 21:12:32 +02:00
|
|
|
ret = update_trip_temp(dts->sensors, thres_index, temp);
|
2023-08-10 21:11:26 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2023-08-10 21:17:36 +02:00
|
|
|
dts->trips[thres_index].temperature = temp;
|
|
|
|
dts->trips[thres_index].type = trip_type;
|
2023-08-10 21:11:26 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-02 13:12:58 -08:00
|
|
|
static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
|
2015-07-24 08:12:54 +02:00
|
|
|
int temp)
|
2015-03-02 13:12:58 -08:00
|
|
|
{
|
2023-03-01 21:14:30 +01:00
|
|
|
struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd);
|
2015-03-02 13:12:58 -08:00
|
|
|
struct intel_soc_dts_sensors *sensors = dts->sensors;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (temp > sensors->tj_max)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
mutex_lock(&sensors->dts_update_lock);
|
2023-08-10 21:12:32 +02:00
|
|
|
status = update_trip_temp(sensors, trip, temp);
|
2015-03-02 13:12:58 -08:00
|
|
|
mutex_unlock(&sensors->dts_update_lock);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sys_get_curr_temp(struct thermal_zone_device *tzd,
|
2015-07-24 08:12:54 +02:00
|
|
|
int *temp)
|
2015-03-02 13:12:58 -08:00
|
|
|
{
|
|
|
|
int status;
|
|
|
|
u32 out;
|
2023-03-01 21:14:30 +01:00
|
|
|
struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd);
|
2015-03-02 13:12:58 -08:00
|
|
|
struct intel_soc_dts_sensors *sensors;
|
2019-12-04 16:51:32 -08:00
|
|
|
unsigned long raw;
|
2015-03-02 13:12:58 -08:00
|
|
|
|
|
|
|
sensors = dts->sensors;
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_TEMP, &out);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2019-12-04 16:51:32 -08:00
|
|
|
raw = out;
|
|
|
|
out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING;
|
2015-03-02 13:12:58 -08:00
|
|
|
*temp = sensors->tj_max - out * 1000;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct thermal_zone_device_ops tzone_ops = {
|
|
|
|
.get_temp = sys_get_curr_temp,
|
|
|
|
.set_trip_temp = sys_set_trip_temp,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int soc_dts_enable(int id)
|
|
|
|
{
|
|
|
|
u32 out;
|
|
|
|
int ret;
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_ENABLE, &out);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (!(out & BIT(id))) {
|
|
|
|
out |= BIT(id);
|
2015-11-11 19:59:29 +02:00
|
|
|
ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_ENABLE, out);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
|
|
|
|
{
|
2023-08-13 10:52:20 +08:00
|
|
|
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
|
|
|
SOC_DTS_OFFSET_ENABLE, dts->store_status);
|
|
|
|
thermal_zone_device_unregister(dts->tzone);
|
2015-03-02 13:12:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
bool critical_trip)
|
2015-03-02 13:12:58 -08:00
|
|
|
{
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
int writable_trip_cnt = SOC_MAX_DTS_TRIPS;
|
2015-03-02 13:12:58 -08:00
|
|
|
char name[10];
|
2019-12-04 16:51:32 -08:00
|
|
|
unsigned long trip;
|
2023-08-10 21:09:54 +02:00
|
|
|
int trip_mask;
|
2019-12-04 16:51:32 -08:00
|
|
|
unsigned long ptps;
|
2015-03-02 13:12:58 -08:00
|
|
|
u32 store_ptps;
|
2019-12-04 16:51:32 -08:00
|
|
|
unsigned long i;
|
2015-03-02 13:12:58 -08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Store status to restor on exit */
|
2015-11-11 19:59:29 +02:00
|
|
|
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
|
|
|
SOC_DTS_OFFSET_ENABLE, &dts->store_status);
|
2015-03-02 13:12:58 -08:00
|
|
|
if (ret)
|
|
|
|
goto err_ret;
|
|
|
|
|
|
|
|
dts->id = id;
|
2023-08-10 21:09:54 +02:00
|
|
|
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
if (critical_trip)
|
|
|
|
writable_trip_cnt--;
|
|
|
|
|
2023-08-10 21:09:54 +02:00
|
|
|
trip_mask = GENMASK(writable_trip_cnt - 1, 0);
|
2015-03-02 13:12:58 -08:00
|
|
|
|
|
|
|
/* Check if the writable trip we provide is not used by BIOS */
|
2015-11-11 19:59:29 +02:00
|
|
|
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTPS, &store_ptps);
|
|
|
|
if (ret)
|
|
|
|
trip_mask = 0;
|
|
|
|
else {
|
2019-12-04 16:51:32 -08:00
|
|
|
ptps = store_ptps;
|
|
|
|
for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8)
|
|
|
|
trip_mask &= ~BIT(i / 8);
|
2015-03-02 13:12:58 -08:00
|
|
|
}
|
|
|
|
dts->trip_mask = trip_mask;
|
|
|
|
snprintf(name, sizeof(name), "soc_dts%d", id);
|
2023-08-10 21:17:36 +02:00
|
|
|
dts->tzone = thermal_zone_device_register_with_trips(name, dts->trips,
|
|
|
|
SOC_MAX_DTS_TRIPS,
|
|
|
|
trip_mask,
|
|
|
|
dts, &tzone_ops,
|
|
|
|
NULL, 0, 0);
|
2015-03-02 13:12:58 -08:00
|
|
|
if (IS_ERR(dts->tzone)) {
|
|
|
|
ret = PTR_ERR(dts->tzone);
|
|
|
|
goto err_ret;
|
|
|
|
}
|
2020-06-29 14:29:22 +02:00
|
|
|
ret = thermal_zone_device_enable(dts->tzone);
|
|
|
|
if (ret)
|
|
|
|
goto err_enable;
|
2015-03-02 13:12:58 -08:00
|
|
|
|
|
|
|
ret = soc_dts_enable(id);
|
|
|
|
if (ret)
|
|
|
|
goto err_enable;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err_enable:
|
|
|
|
thermal_zone_device_unregister(dts->tzone);
|
|
|
|
err_ret:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTMC, &ptmc_out);
|
|
|
|
ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT;
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
SOC_DTS_OFFSET_PTMC, ptmc_out);
|
|
|
|
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
2015-03-02 13:12:58 -08:00
|
|
|
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 */
|
2015-11-11 19:59:29 +02:00
|
|
|
status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
|
2015-03-02 13:12:58 -08:00
|
|
|
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);
|
2016-08-26 16:21:16 -07:00
|
|
|
thermal_zone_device_update(sensors->soc_dts[i].tzone,
|
|
|
|
THERMAL_EVENT_UNSPECIFIED);
|
2015-03-02 13:12:58 -08:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
|
|
|
|
|
2023-08-10 21:14:49 +02:00
|
|
|
static void dts_trips_reset(struct intel_soc_dts_sensors *sensors, int dts_index)
|
|
|
|
{
|
|
|
|
configure_trip(&sensors->soc_dts[dts_index], 0, 0, 0);
|
|
|
|
configure_trip(&sensors->soc_dts[dts_index], 1, 0, 0);
|
|
|
|
}
|
|
|
|
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
struct intel_soc_dts_sensors *
|
|
|
|
intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type,
|
|
|
|
bool critical_trip, int crit_offset)
|
2015-03-02 13:12:58 -08:00
|
|
|
{
|
|
|
|
struct intel_soc_dts_sensors *sensors;
|
2023-01-06 08:59:51 +08:00
|
|
|
int tj_max;
|
2015-03-02 13:12:58 -08:00
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!iosf_mbi_available())
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
|
2022-12-19 23:46:17 +08:00
|
|
|
tj_max = intel_tcc_get_tjmax(-1);
|
|
|
|
if (tj_max < 0)
|
|
|
|
return ERR_PTR(tj_max);
|
2015-03-02 13:12:58 -08:00
|
|
|
|
|
|
|
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;
|
2023-06-14 12:07:56 +02:00
|
|
|
sensors->tj_max = tj_max * 1000;
|
2023-08-10 21:09:54 +02:00
|
|
|
|
2015-03-02 13:12:58 -08:00
|
|
|
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
enum thermal_trip_type trip_type;
|
|
|
|
int temp;
|
|
|
|
|
2015-03-02 13:12:58 -08:00
|
|
|
sensors->soc_dts[i].sensors = sensors;
|
|
|
|
|
2023-08-10 21:11:26 +02:00
|
|
|
ret = configure_trip(&sensors->soc_dts[i], 0,
|
|
|
|
THERMAL_TRIP_PASSIVE, 0);
|
2015-03-02 13:12:58 -08:00
|
|
|
if (ret)
|
2023-08-10 21:13:25 +02:00
|
|
|
goto err_reset_trips;
|
2015-03-02 13:12:58 -08:00
|
|
|
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
if (critical_trip) {
|
|
|
|
trip_type = THERMAL_TRIP_CRITICAL;
|
|
|
|
temp = sensors->tj_max - crit_offset;
|
|
|
|
} else {
|
|
|
|
trip_type = THERMAL_TRIP_PASSIVE;
|
|
|
|
temp = 0;
|
|
|
|
}
|
|
|
|
ret = configure_trip(&sensors->soc_dts[i], 1, trip_type, temp);
|
2023-08-10 21:13:25 +02:00
|
|
|
if (ret)
|
|
|
|
goto err_reset_trips;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
|
thermal: intel: intel_soc_dts_iosf: Rework critical trip setup
Critical trip points appear in the DTS thermal zones only after those
thermal zones have been registered via intel_soc_dts_iosf_init().
Moreover, they are "created" by changing the type of an existing trip
point from THERMAL_TRIP_PASSIVE to THERMAL_TRIP_CRITICAL via
intel_soc_dts_iosf_add_read_only_critical_trip(), the caller of which
has to be careful enough to pass at least 1 as the number of read-only
trip points to intel_soc_dts_iosf_init() beforehand.
This is questionable, because user space may have started to use the
trips at the time when intel_soc_dts_iosf_add_read_only_critical_trip()
runs and there is no synchronization between it and sys_set_trip_temp().
To address it, use the observation that nonzero number of read-only
trip points is only passed to intel_soc_dts_iosf_init() when critical
trip points are going to be used, so in fact that function may get all
of the information regarding the critical trip points upfront and it
can configure them before registering the corresponding thermal zones.
Accordingly, replace the read_only_trip_count argument of
intel_soc_dts_iosf_init() with a pair of new arguments related to
critical trip points: a bool one indicating whether or not critical
trip points are to be used at all and an int one representing the
critical trip point temperature offset relative to Tj_max. Use these
arguments to configure the critical trip points before the registration
of the thermal zones and to compute the number of writeable trip points
in add_dts_thermal_zone().
Modify both callers of intel_soc_dts_iosf_init() to take these changes
into account and drop the intel_soc_dts_iosf_add_read_only_critical_trip()
call, that is not necessary any more, from intel_soc_thermal_init(),
which also allows it to return success right after requesting the IRQ.
Finally, drop intel_soc_dts_iosf_add_read_only_critical_trip()
altogether, because it does not have any more users.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
2023-08-10 21:16:14 +02:00
|
|
|
ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], critical_trip);
|
2015-03-02 13:12:58 -08:00
|
|
|
if (ret)
|
|
|
|
goto err_remove_zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sensors;
|
2023-08-10 21:13:25 +02:00
|
|
|
|
2015-03-02 13:12:58 -08:00
|
|
|
err_remove_zone:
|
|
|
|
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
|
|
|
|
remove_dts_thermal_zone(&sensors->soc_dts[i]);
|
|
|
|
|
2023-08-10 21:13:25 +02:00
|
|
|
err_reset_trips:
|
2023-08-10 21:14:49 +02:00
|
|
|
for (i = 0; i < SOC_MAX_DTS_SENSORS; i++)
|
|
|
|
dts_trips_reset(sensors, i);
|
2023-08-10 21:13:25 +02:00
|
|
|
|
2015-03-02 13:12:58 -08:00
|
|
|
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) {
|
2023-08-10 21:13:25 +02:00
|
|
|
remove_dts_thermal_zone(&sensors->soc_dts[i]);
|
2023-08-10 21:14:49 +02:00
|
|
|
dts_trips_reset(sensors, i);
|
2015-03-02 13:12:58 -08:00
|
|
|
}
|
|
|
|
kfree(sensors);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);
|
|
|
|
|
2022-12-19 23:46:17 +08:00
|
|
|
MODULE_IMPORT_NS(INTEL_TCC);
|
2015-03-02 13:12:58 -08:00
|
|
|
MODULE_LICENSE("GPL v2");
|