summaryrefslogtreecommitdiff
path: root/drivers/thermal/intel
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thermal/intel')
-rw-r--r--drivers/thermal/intel/Kconfig6
-rw-r--r--drivers/thermal/intel/int340x_thermal/Kconfig4
-rw-r--r--drivers/thermal/intel/int340x_thermal/Makefile1
-rw-r--r--drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c5
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3400_thermal.c34
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3401_thermal.c2
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3402_thermal.c5
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3403_thermal.c15
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3406_thermal.c2
-rw-r--r--drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c70
-rw-r--r--drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h2
-rw-r--r--drivers/thermal/intel/int340x_thermal/platform_temperature_control.c243
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device.c33
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device.h6
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c155
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c7
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c13
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c71
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c121
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c11
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c3
-rw-r--r--drivers/thermal/intel/intel_hfi.c157
-rw-r--r--drivers/thermal/intel/intel_pch_thermal.c33
-rw-r--r--drivers/thermal/intel/intel_powerclamp.c40
-rw-r--r--drivers/thermal/intel/intel_quark_dts_thermal.c64
-rw-r--r--drivers/thermal/intel/intel_soc_dts_iosf.c87
-rw-r--r--drivers/thermal/intel/intel_soc_dts_iosf.h2
-rw-r--r--drivers/thermal/intel/intel_soc_dts_thermal.c2
-rw-r--r--drivers/thermal/intel/intel_tcc.c195
-rw-r--r--drivers/thermal/intel/intel_tcc_cooling.c39
-rw-r--r--drivers/thermal/intel/therm_throt.c10
-rw-r--r--drivers/thermal/intel/x86_pkg_temp_thermal.c62
32 files changed, 1050 insertions, 450 deletions
diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig
index b43953b5539f..e0268fac7093 100644
--- a/drivers/thermal/intel/Kconfig
+++ b/drivers/thermal/intel/Kconfig
@@ -21,9 +21,8 @@ config INTEL_TCC
config X86_PKG_TEMP_THERMAL
tristate "X86 package temperature thermal driver"
- depends on X86_THERMAL_VECTOR
- select THERMAL_GOV_USER_SPACE
- select THERMAL_WRITABLE_TRIPS
+ depends on X86_THERMAL_VECTOR && NET
+ select THERMAL_NETLINK
select INTEL_TCC
default m
help
@@ -47,7 +46,6 @@ config INTEL_SOC_DTS_THERMAL
tristate "Intel SoCs DTS thermal driver"
depends on X86 && PCI && ACPI
select INTEL_SOC_DTS_IOSF_CORE
- select THERMAL_WRITABLE_TRIPS
help
Enable this to register Intel SoCs (e.g. Bay Trail) platform digital
temperature sensor (DTS). These SoCs have two additional DTSs in
diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig
index e76b13e44d03..4c699f0896b5 100644
--- a/drivers/thermal/intel/int340x_thermal/Kconfig
+++ b/drivers/thermal/intel/int340x_thermal/Kconfig
@@ -5,8 +5,8 @@
config INT340X_THERMAL
tristate "ACPI INT340X thermal drivers"
- depends on X86_64 && ACPI && PCI
- select THERMAL_GOV_USER_SPACE
+ depends on X86_64 && ACPI && PCI && NET
+ select THERMAL_NETLINK
select ACPI_THERMAL_REL
select ACPI_FAN
select ACPI_THERMAL_LIB
diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index fe3f43924525..184318d1792b 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci_legacy.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o
obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o
+obj-$(CONFIG_INT340X_THERMAL) += platform_temperature_control.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_req.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o
diff --git a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
index dc519a665c18..cb149bcdd7d5 100644
--- a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
+++ b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
@@ -309,7 +309,7 @@ static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **ps
if (knob->type == ACPI_TYPE_STRING) {
memset(&psvt->limit, 0, sizeof(u64));
- strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
+ strscpy(psvt->limit.string, psvt_ptr->limit.str_ptr, ACPI_LIMIT_STR_MAX_LEN);
} else {
psvt->limit.integer = psvt_ptr->limit.integer;
}
@@ -468,7 +468,7 @@ static int fill_psvt(char __user *ubuf)
psvt_user[i].unlimit_coeff = psvts[i].unlimit_coeff;
psvt_user[i].control_knob_type = psvts[i].control_knob_type;
if (psvt_user[i].control_knob_type == ACPI_TYPE_STRING)
- strncpy(psvt_user[i].limit.string, psvts[i].limit.string,
+ strscpy(psvt_user[i].limit.string, psvts[i].limit.string,
ACPI_LIMIT_STR_MAX_LEN);
else
psvt_user[i].limit.integer = psvts[i].limit.integer;
@@ -564,7 +564,6 @@ static const struct file_operations acpi_thermal_rel_fops = {
.open = acpi_thermal_rel_open,
.release = acpi_thermal_rel_release,
.unlocked_ioctl = acpi_thermal_rel_ioctl,
- .llseek = no_llseek,
};
static struct miscdevice acpi_thermal_rel_misc_device = {
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index 427d370648d5..0e07693ecf59 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -73,19 +73,7 @@ struct odvp_attr {
struct device_attribute attr;
};
-static ssize_t data_vault_read(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t off, size_t count)
-{
- memcpy(buf, attr->private + off, count);
- return count;
-}
-
-static BIN_ATTR_RO(data_vault, 0);
-
-static struct bin_attribute *data_attributes[] = {
- &bin_attr_data_vault,
- NULL,
-};
+static BIN_ATTR_SIMPLE_RO(data_vault);
static ssize_t imok_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -115,10 +103,6 @@ static const struct attribute_group imok_attribute_group = {
.attrs = imok_attr,
};
-static const struct attribute_group data_attribute_group = {
- .bin_attrs = data_attributes,
-};
-
static ssize_t available_uuids_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -144,7 +128,7 @@ static ssize_t current_uuid_show(struct device *dev,
struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
int i, length = 0;
- if (priv->current_uuid_index > 0)
+ if (priv->current_uuid_index >= 0)
return sprintf(buf, "%s\n",
int3400_thermal_uuids[priv->current_uuid_index]);
@@ -537,7 +521,6 @@ static struct thermal_zone_device_ops int3400_thermal_ops = {
};
static struct thermal_zone_params int3400_thermal_params = {
- .governor_name = "user_space",
.no_hwmon = true,
};
@@ -578,7 +561,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
if (!adev)
return -ENODEV;
- priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -631,8 +614,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
}
if (!ZERO_OR_NULL_PTR(priv->data_vault)) {
- result = sysfs_create_group(&pdev->dev.kobj,
- &data_attribute_group);
+ result = device_create_bin_file(&pdev->dev, &bin_attr_data_vault);
if (result)
goto free_uuid;
}
@@ -655,7 +637,7 @@ free_notify:
free_sysfs:
cleanup_odvp(priv);
if (!ZERO_OR_NULL_PTR(priv->data_vault)) {
- sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
+ device_remove_bin_file(&pdev->dev, &bin_attr_data_vault);
kfree(priv->data_vault);
}
free_uuid:
@@ -690,7 +672,7 @@ static void int3400_thermal_remove(struct platform_device *pdev)
acpi_thermal_rel_misc_device_remove(priv->adev->handle);
if (!ZERO_OR_NULL_PTR(priv->data_vault))
- sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group);
+ device_remove_bin_file(&pdev->dev, &bin_attr_data_vault);
sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group);
sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group);
thermal_zone_device_unregister(priv->thermal);
@@ -705,7 +687,9 @@ static const struct acpi_device_id int3400_thermal_match[] = {
{"INTC1040", 0},
{"INTC1041", 0},
{"INTC1042", 0},
+ {"INTC1068", 0},
{"INTC10A0", 0},
+ {"INTC10D4", 0},
{}
};
@@ -713,7 +697,7 @@ MODULE_DEVICE_TABLE(acpi, int3400_thermal_match);
static struct platform_driver int3400_thermal_driver = {
.probe = int3400_thermal_probe,
- .remove_new = int3400_thermal_remove,
+ .remove = int3400_thermal_remove,
.driver = {
.name = "int3400 thermal",
.acpi_match_table = ACPI_PTR(int3400_thermal_match),
diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
index 193645a73861..96d6277a5a8c 100644
--- a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
@@ -60,7 +60,7 @@ static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, int3401_thermal_suspend,
static struct platform_driver int3401_driver = {
.probe = int3401_add,
- .remove_new = int3401_remove,
+ .remove = int3401_remove,
.driver = {
.name = "int3401 thermal",
.acpi_match_table = int3401_device_ids,
diff --git a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c
index ab8bfb5a3946..57b90005888a 100644
--- a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c
@@ -45,6 +45,9 @@ static int int3402_thermal_probe(struct platform_device *pdev)
struct int3402_thermal_data *d;
int ret;
+ if (!adev)
+ return -ENODEV;
+
if (!acpi_has_method(adev->handle, "_TMP"))
return -ENODEV;
@@ -89,7 +92,7 @@ MODULE_DEVICE_TABLE(acpi, int3402_thermal_match);
static struct platform_driver int3402_thermal_driver = {
.probe = int3402_thermal_probe,
- .remove_new = int3402_thermal_remove,
+ .remove = int3402_thermal_remove,
.driver = {
.name = "int3402 thermal",
.acpi_match_table = int3402_thermal_match,
diff --git a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c
index 9b33fd3a66da..5a925a8df7b3 100644
--- a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c
@@ -25,17 +25,6 @@ struct int3403_sensor {
struct int34x_thermal_zone *int340x_zone;
};
-struct int3403_performance_state {
- u64 performance;
- u64 power;
- u64 latency;
- u64 linear;
- u64 control;
- u64 raw_performace;
- char *raw_unit;
- int reserved;
-};
-
struct int3403_cdev {
struct thermal_cooling_device *cdev;
unsigned long max_state;
@@ -284,14 +273,16 @@ static const struct acpi_device_id int3403_device_ids[] = {
{"INTC1043", 0},
{"INTC1046", 0},
{"INTC1062", 0},
+ {"INTC1069", 0},
{"INTC10A1", 0},
+ {"INTC10D5", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
static struct platform_driver int3403_driver = {
.probe = int3403_add,
- .remove_new = int3403_remove,
+ .remove = int3403_remove,
.driver = {
.name = "int3403 thermal",
.acpi_match_table = int3403_device_ids,
diff --git a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c
index 1c266493c1aa..e21fcbccf4ba 100644
--- a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c
@@ -195,7 +195,7 @@ MODULE_DEVICE_TABLE(acpi, int3406_thermal_match);
static struct platform_driver int3406_thermal_driver = {
.probe = int3406_thermal_probe,
- .remove_new = int3406_thermal_remove,
+ .remove = int3406_thermal_remove,
.driver = {
.name = "int3406 thermal",
.acpi_match_table = int3406_thermal_match,
diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
index 3e4bfe817fac..3d9efe69d562 100644
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
+++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
@@ -39,13 +39,14 @@ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
}
static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
- int trip, int temp)
+ const struct thermal_trip *trip, int temp)
{
struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);
- char name[] = {'P', 'A', 'T', '0' + trip, '\0'};
+ unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);
+ char name[] = {'P', 'A', 'T', '0' + trip_index, '\0'};
acpi_status status;
- if (trip > 9)
+ if (trip_index > 9)
return -EINVAL;
status = acpi_execute_simple_method(d->adev->handle, name,
@@ -58,23 +59,8 @@ static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
static void int340x_thermal_critical(struct thermal_zone_device *zone)
{
- dev_dbg(&zone->device, "%s: critical temperature reached\n", zone->type);
-}
-
-static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
- .get_temp = int340x_thermal_get_zone_temp,
- .set_trip_temp = int340x_thermal_set_trip_temp,
- .critical = int340x_thermal_critical,
-};
-
-static inline void *int_to_trip_priv(int i)
-{
- return (void *)(long)i;
-}
-
-static inline int trip_priv_to_int(const struct thermal_trip *trip)
-{
- return (long)trip->priv;
+ dev_dbg(thermal_zone_device(zone), "%s: critical temperature reached\n",
+ thermal_zone_device_type(zone));
}
static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
@@ -111,7 +97,7 @@ static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
break;
zone_trips[trip_cnt].type = THERMAL_TRIP_ACTIVE;
- zone_trips[trip_cnt].priv = int_to_trip_priv(i);
+ zone_trips[trip_cnt].priv = THERMAL_INT_TO_TRIP_PRIV(i);
trip_cnt++;
}
@@ -119,18 +105,21 @@ static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
}
static struct thermal_zone_params int340x_thermal_params = {
- .governor_name = "user_space",
.no_hwmon = true,
};
struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
int (*get_temp) (struct thermal_zone_device *, int *))
{
+ const struct thermal_zone_device_ops zone_ops = {
+ .set_trip_temp = int340x_thermal_set_trip_temp,
+ .critical = int340x_thermal_critical,
+ .get_temp = get_temp ? get_temp : int340x_thermal_get_zone_temp,
+ };
struct int34x_thermal_zone *int34x_zone;
struct thermal_trip *zone_trips;
unsigned long long trip_cnt = 0;
unsigned long long hyst;
- int trip_mask = 0;
acpi_status status;
int i, ret;
@@ -140,24 +129,12 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
int34x_zone->adev = adev;
- int34x_zone->ops = kmemdup(&int340x_thermal_zone_ops,
- sizeof(int340x_thermal_zone_ops), GFP_KERNEL);
- if (!int34x_zone->ops) {
- ret = -ENOMEM;
- goto err_ops_alloc;
- }
-
- if (get_temp)
- int34x_zone->ops->get_temp = get_temp;
-
status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
- if (ACPI_SUCCESS(status)) {
+ if (ACPI_SUCCESS(status))
int34x_zone->aux_trip_nr = trip_cnt;
- trip_mask = BIT(trip_cnt) - 1;
- }
- zone_trips = kzalloc(sizeof(*zone_trips) * (trip_cnt + INT340X_THERMAL_MAX_TRIP_COUNT),
- GFP_KERNEL);
+ zone_trips = kcalloc(trip_cnt + INT340X_THERMAL_MAX_TRIP_COUNT,
+ sizeof(*zone_trips), GFP_KERNEL);
if (!zone_trips) {
ret = -ENOMEM;
goto err_trips_alloc;
@@ -166,6 +143,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
for (i = 0; i < trip_cnt; i++) {
zone_trips[i].type = THERMAL_TRIP_PASSIVE;
zone_trips[i].temperature = THERMAL_TEMP_INVALID;
+ zone_trips[i].flags = THERMAL_TRIP_FLAG_RW_TEMP;
+ zone_trips[i].priv = THERMAL_INT_TO_TRIP_PRIV(i);
}
trip_cnt = int340x_thermal_read_trips(adev, zone_trips, trip_cnt);
@@ -179,17 +158,17 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
for (i = 0; i < trip_cnt; ++i)
zone_trips[i].hysteresis = hyst;
- int34x_zone->trips = zone_trips;
-
int34x_zone->lpat_table = acpi_lpat_get_conversion_table(adev->handle);
int34x_zone->zone = thermal_zone_device_register_with_trips(
acpi_device_bid(adev),
zone_trips, trip_cnt,
- trip_mask, int34x_zone,
- int34x_zone->ops,
+ int34x_zone,
+ &zone_ops,
&int340x_thermal_params,
0, 0);
+ kfree(zone_trips);
+
if (IS_ERR(int34x_zone->zone)) {
ret = PTR_ERR(int34x_zone->zone);
goto err_thermal_zone;
@@ -203,11 +182,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
err_enable:
thermal_zone_device_unregister(int34x_zone->zone);
err_thermal_zone:
- kfree(int34x_zone->trips);
acpi_lpat_free_conversion_table(int34x_zone->lpat_table);
err_trips_alloc:
- kfree(int34x_zone->ops);
-err_ops_alloc:
kfree(int34x_zone);
return ERR_PTR(ret);
}
@@ -217,8 +193,6 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_zone)
{
thermal_zone_device_unregister(int34x_zone->zone);
acpi_lpat_free_conversion_table(int34x_zone->lpat_table);
- kfree(int34x_zone->trips);
- kfree(int34x_zone->ops);
kfree(int34x_zone);
}
EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
@@ -241,7 +215,7 @@ static int int340x_update_one_trip(struct thermal_trip *trip, void *arg)
break;
case THERMAL_TRIP_ACTIVE:
err = thermal_acpi_active_trip_temp(zone_adev,
- trip_priv_to_int(trip),
+ THERMAL_TRIP_PRIV_TO_INT(trip->priv),
&temp);
break;
default:
diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h
index e0df6271facc..d504e271009a 100644
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h
+++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h
@@ -20,10 +20,8 @@ struct active_trip {
struct int34x_thermal_zone {
struct acpi_device *adev;
- struct thermal_trip *trips;
int aux_trip_nr;
struct thermal_zone_device *zone;
- struct thermal_zone_device_ops *ops;
void *priv_data;
struct acpi_lpat_conversion_table *lpat_table;
};
diff --git a/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c b/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c
new file mode 100644
index 000000000000..2d6504514893
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device platform temperature controls
+ * Copyright (c) 2025, Intel Corporation.
+ */
+
+/*
+ * Platform temperature controls hardware interface
+ *
+ * The hardware control interface is via MMIO offsets in the processor
+ * thermal device MMIO space. There are three instances of MMIO registers.
+ * All registers are 64 bit wide with RW access.
+ *
+ * Name: PLATFORM_TEMPERATURE_CONTROL
+ * Offsets: 0x5B20, 0x5B28, 0x5B30
+ *
+ * Bits Description
+ * 7:0 TARGET_TEMP : Target temperature limit to which the control
+ * mechanism is regulating. Units: 0.5C.
+ * 8:8 ENABLE: Read current enable status of the feature or enable
+ * feature.
+ * 11:9 GAIN: Sets the aggressiveness of control loop from 0 to 7
+ * 7 graceful, favors performance at the expense of temperature
+ * overshoots
+ * 0 aggressive, favors tight regulation over performance
+ * 12:12 TEMPERATURE_OVERRIDE_EN
+ * When set, hardware will use TEMPERATURE_OVERRIDE values instead
+ * of reading from corresponding sensor.
+ * 15:13 RESERVED
+ * 23:16 MIN_PERFORMANCE_LEVEL: Minimum Performance level below which the
+ * there will be no throttling. 0 - all levels of throttling allowed
+ * including survivability actions. 255 - no throttling allowed.
+ * 31:24 TEMPERATURE_OVERRIDE: Allows SW to override the input temperature.
+ * hardware will use this value instead of the sensor temperature.
+ * Units: 0.5C.
+ * 63:32 RESERVED
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+struct mmio_reg {
+ int bits;
+ u16 mask;
+ u16 shift;
+ u16 units;
+};
+
+#define MAX_ATTR_GROUP_NAME_LEN 32
+#define PTC_MAX_ATTRS 3
+
+struct ptc_data {
+ u32 offset;
+ struct attribute_group ptc_attr_group;
+ struct attribute *ptc_attrs[PTC_MAX_ATTRS];
+ struct device_attribute temperature_target_attr;
+ struct device_attribute enable_attr;
+ char group_name[MAX_ATTR_GROUP_NAME_LEN];
+};
+
+static const struct mmio_reg ptc_mmio_regs[] = {
+ { 8, 0xFF, 0, 500}, /* temperature_target, units 0.5C*/
+ { 1, 0x01, 8, 0}, /* enable */
+ { 3, 0x7, 9, 0}, /* gain */
+ { 8, 0xFF, 16, 0}, /* min_performance_level */
+ { 1, 0x1, 12, 0}, /* temperature_override_enable */
+ { 8, 0xFF, 24, 500}, /* temperature_override, units 0.5C */
+};
+
+#define PTC_MAX_INSTANCES 3
+
+/* Unique offset for each PTC instance */
+static u32 ptc_offsets[PTC_MAX_INSTANCES] = {0x5B20, 0x5B28, 0x5B30};
+
+/* These will represent sysfs attribute names */
+static const char * const ptc_strings[] = {
+ "temperature_target",
+ "enable",
+ NULL
+};
+
+/* Lock to protect concurrent read/write and read-modify-write */
+static DEFINE_MUTEX(ptc_lock);
+
+static ssize_t ptc_mmio_show(struct ptc_data *data, struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct proc_thermal_device *proc_priv;
+ const struct mmio_reg *mmio_regs;
+ int ret, units;
+ u64 reg_val;
+
+ proc_priv = pci_get_drvdata(pdev);
+ mmio_regs = ptc_mmio_regs;
+ ret = match_string(ptc_strings, -1, attr->attr.name);
+ if (ret < 0)
+ return ret;
+
+ units = mmio_regs[ret].units;
+
+ guard(mutex)(&ptc_lock);
+
+ reg_val = readq((void __iomem *) (proc_priv->mmio_base + data->offset));
+ ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;
+ if (units)
+ ret *= units;
+
+ return sysfs_emit(buf, "%d\n", ret);
+}
+
+#define PTC_SHOW(suffix)\
+static ssize_t suffix##_show(struct device *dev,\
+ struct device_attribute *attr,\
+ char *buf)\
+{\
+ struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\
+ return ptc_mmio_show(data, dev, attr, buf);\
+}
+
+static void ptc_mmio_write(struct pci_dev *pdev, u32 offset, int index, u32 value)
+{
+ struct proc_thermal_device *proc_priv;
+ u64 mask, reg_val;
+
+ proc_priv = pci_get_drvdata(pdev);
+
+ mask = GENMASK_ULL(ptc_mmio_regs[index].shift + ptc_mmio_regs[index].bits - 1,
+ ptc_mmio_regs[index].shift);
+
+ guard(mutex)(&ptc_lock);
+
+ reg_val = readq((void __iomem *) (proc_priv->mmio_base + offset));
+ reg_val &= ~mask;
+ reg_val |= (value << ptc_mmio_regs[index].shift);
+ writeq(reg_val, (void __iomem *) (proc_priv->mmio_base + offset));
+}
+
+static int ptc_store(struct ptc_data *data, struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned int input;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &input);
+ if (ret)
+ return ret;
+
+ ret = match_string(ptc_strings, -1, attr->attr.name);
+ if (ret < 0)
+ return ret;
+
+ if (ptc_mmio_regs[ret].units)
+ input /= ptc_mmio_regs[ret].units;
+
+ if (input > ptc_mmio_regs[ret].mask)
+ return -EINVAL;
+
+ ptc_mmio_write(pdev, data->offset, ret, input);
+
+ return count;
+}
+
+#define PTC_STORE(suffix)\
+static ssize_t suffix##_store(struct device *dev,\
+ struct device_attribute *attr,\
+ const char *buf, size_t count)\
+{\
+ struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\
+ return ptc_store(data, dev, attr, buf, count);\
+}
+
+PTC_SHOW(temperature_target);
+PTC_STORE(temperature_target);
+PTC_SHOW(enable);
+PTC_STORE(enable);
+
+#define ptc_init_attribute(_name)\
+ do {\
+ sysfs_attr_init(&data->_name##_attr.attr);\
+ data->_name##_attr.show = _name##_show;\
+ data->_name##_attr.store = _name##_store;\
+ data->_name##_attr.attr.name = #_name;\
+ data->_name##_attr.attr.mode = 0644;\
+ } while (0)
+
+static int ptc_create_groups(struct pci_dev *pdev, int instance, struct ptc_data *data)
+{
+ int ret, index = 0;
+
+ ptc_init_attribute(temperature_target);
+ ptc_init_attribute(enable);
+
+ data->ptc_attrs[index++] = &data->temperature_target_attr.attr;
+ data->ptc_attrs[index++] = &data->enable_attr.attr;
+ data->ptc_attrs[index] = NULL;
+
+ snprintf(data->group_name, MAX_ATTR_GROUP_NAME_LEN,
+ "ptc_%d_control", instance);
+ data->ptc_attr_group.name = data->group_name;
+ data->ptc_attr_group.attrs = data->ptc_attrs;
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &data->ptc_attr_group);
+
+ return ret;
+}
+
+static struct ptc_data ptc_instance[PTC_MAX_INSTANCES];
+
+int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) {
+ int i;
+
+ for (i = 0; i < PTC_MAX_INSTANCES; i++) {
+ ptc_instance[i].offset = ptc_offsets[i];
+ ptc_create_groups(pdev, i, &ptc_instance[i]);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_ptc_add);
+
+void proc_thermal_ptc_remove(struct pci_dev *pdev)
+{
+ struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
+
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) {
+ int i;
+
+ for (i = 0; i < PTC_MAX_INSTANCES; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &ptc_instance[i].ptc_attr_group);
+ }
+}
+EXPORT_SYMBOL_GPL(proc_thermal_ptc_remove);
+
+MODULE_IMPORT_NS("INT340X_THERMAL");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Processor Thermal PTC Interface");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 649f67fdf345..29fcece48cad 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/thermal.h>
+#include <asm/msr.h>
#include "int340x_thermal_zone.h"
#include "processor_thermal_device.h"
#include "../intel_soc_dts_iosf.h"
@@ -153,7 +154,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
u64 val;
int err;
- err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
+ err = rdmsrq_safe(MSR_PLATFORM_INFO, &val);
if (err)
return err;
@@ -176,14 +177,14 @@ static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,
int *temp)
{
int cpu;
- int curr_temp;
+ int curr_temp, ret;
*temp = 0;
for_each_online_cpu(cpu) {
- curr_temp = intel_tcc_get_temp(cpu, false);
- if (curr_temp < 0)
- return curr_temp;
+ ret = intel_tcc_get_temp(cpu, &curr_temp, false);
+ if (ret < 0)
+ return ret;
if (!*temp || curr_temp > *temp)
*temp = curr_temp;
}
@@ -399,13 +400,21 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
}
}
+ if (feature_mask & PROC_THERMAL_FEATURE_PTC) {
+ ret = proc_thermal_ptc_add(pdev, proc_priv);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add PTC MMIO interface\n");
+ goto err_rem_rapl;
+ }
+ }
+
if (feature_mask & PROC_THERMAL_FEATURE_FIVR ||
feature_mask & PROC_THERMAL_FEATURE_DVFS ||
feature_mask & PROC_THERMAL_FEATURE_DLVR) {
ret = proc_thermal_rfim_add(pdev, proc_priv);
if (ret) {
dev_err(&pdev->dev, "failed to add RFIM interface\n");
- goto err_rem_rapl;
+ goto err_rem_ptc;
}
}
@@ -427,6 +436,8 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
err_rem_rfim:
proc_thermal_rfim_remove(pdev);
+err_rem_ptc:
+ proc_thermal_ptc_remove(pdev);
err_rem_rapl:
proc_thermal_rapl_remove();
@@ -439,8 +450,12 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
proc_thermal_rapl_remove();
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC)
+ proc_thermal_ptc_remove(pdev);
+
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
- proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
+ proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS ||
+ proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR)
proc_thermal_rfim_remove(pdev);
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR)
@@ -453,8 +468,8 @@ 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_IMPORT_NS(INT340X_THERMAL);
+MODULE_IMPORT_NS("INTEL_TCC");
+MODULE_IMPORT_NS("INT340X_THERMAL");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index 95c6013a33fb..9a6ca43b6fa2 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -25,10 +25,12 @@
#define PCI_DEVICE_ID_INTEL_HSB_THERMAL 0x0A03
#define PCI_DEVICE_ID_INTEL_ICL_THERMAL 0x8a03
#define PCI_DEVICE_ID_INTEL_JSL_THERMAL 0x4E03
+#define PCI_DEVICE_ID_INTEL_LNLM_THERMAL 0x641D
#define PCI_DEVICE_ID_INTEL_MTLP_THERMAL 0x7D03
#define PCI_DEVICE_ID_INTEL_RPL_THERMAL 0xA71D
#define PCI_DEVICE_ID_INTEL_SKL_THERMAL 0x1903
#define PCI_DEVICE_ID_INTEL_TGL_THERMAL 0x9A03
+#define PCI_DEVICE_ID_INTEL_PTL_THERMAL 0xB01D
struct power_config {
u32 index;
@@ -64,6 +66,8 @@ struct rapl_mmio_regs {
#define PROC_THERMAL_FEATURE_DLVR 0x10
#define PROC_THERMAL_FEATURE_WT_HINT 0x20
#define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40
+#define PROC_THERMAL_FEATURE_MSI_SUPPORT 0x80
+#define PROC_THERMAL_FEATURE_PTC 0x100
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -120,4 +124,6 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
struct proc_thermal_device *proc_priv,
kernel_ulong_t feature_mask);
void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_ptc_remove(struct pci_dev *pdev);
#endif
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 d7495571dd5d..00160936070a 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
@@ -63,6 +63,18 @@ static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
{ PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
};
+/* List of supported MSI IDs (sources) */
+enum proc_thermal_msi_ids {
+ PKG_THERMAL,
+ DDR_THERMAL,
+ THERM_POWER_FLOOR,
+ WORKLOAD_CHANGE,
+ MSI_THERMAL_MAX
+};
+
+/* Stores IRQ associated with a MSI ID */
+static int proc_thermal_msi_map[MSI_THERMAL_MAX];
+
#define B0D4_THERMAL_NOTIFY_DELAY 1000
static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
@@ -146,22 +158,41 @@ static irqreturn_t proc_thermal_irq_thread_handler(int irq, void *devid)
return IRQ_HANDLED;
}
+static int proc_thermal_match_msi_irq(int irq)
+{
+ int i;
+
+ if (!use_msi)
+ goto msi_fail;
+
+ for (i = 0; i < MSI_THERMAL_MAX; i++) {
+ if (proc_thermal_msi_map[i] == irq)
+ return i;
+ }
+
+msi_fail:
+ return -EOPNOTSUPP;
+}
+
static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
{
struct proc_thermal_pci *pci_info = devid;
struct proc_thermal_device *proc_priv;
- int ret = IRQ_HANDLED;
+ int ret = IRQ_NONE, msi_id;
u32 status;
proc_priv = pci_info->proc_priv;
+ msi_id = proc_thermal_match_msi_irq(irq);
+
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
- if (proc_thermal_check_wt_intr(pci_info->proc_priv))
+ if (msi_id == WORKLOAD_CHANGE || proc_thermal_check_wt_intr(pci_info->proc_priv))
ret = IRQ_WAKE_THREAD;
}
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR) {
- if (proc_thermal_check_power_floor_intr(pci_info->proc_priv))
+ if (msi_id == THERM_POWER_FLOOR ||
+ proc_thermal_check_power_floor_intr(pci_info->proc_priv))
ret = IRQ_WAKE_THREAD;
}
@@ -171,10 +202,11 @@ static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
* interrupt before scheduling work function for thermal threshold.
*/
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
- if (status) {
+ if (msi_id == PKG_THERMAL || status) {
/* Disable enable interrupt flag */
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
pkg_thermal_schedule_work(&pci_info->work);
+ ret = IRQ_HANDLED;
}
pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);
@@ -193,7 +225,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
return 0;
}
-static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
+static int sys_set_trip_temp(struct thermal_zone_device *tzd,
+ const struct thermal_trip *trip, int temp)
{
struct proc_thermal_pci *pci_info = thermal_zone_device_priv(tzd);
int tjmax, _temp;
@@ -233,26 +266,75 @@ static int get_trip_temp(struct proc_thermal_pci *pci_info)
return temp;
}
-static struct thermal_trip psv_trip = {
- .type = THERMAL_TRIP_PASSIVE,
-};
-
-static struct thermal_zone_device_ops tzone_ops = {
+static const struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.set_trip_temp = sys_set_trip_temp,
};
static struct thermal_zone_params tzone_params = {
- .governor_name = "user_space",
.no_hwmon = true,
};
+static bool msi_irq;
+
+static void proc_thermal_free_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
+{
+ int i;
+
+ for (i = 0; i < MSI_THERMAL_MAX; i++) {
+ if (proc_thermal_msi_map[i])
+ devm_free_irq(&pdev->dev, proc_thermal_msi_map[i], pci_info);
+ }
+
+ pci_free_irq_vectors(pdev);
+}
+
+static int proc_thermal_setup_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
+{
+ int ret, i, irq, count;
+
+ count = pci_alloc_irq_vectors(pdev, 1, MSI_THERMAL_MAX, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ if (count < 0) {
+ dev_err(&pdev->dev, "Failed to allocate vectors!\n");
+ return count;
+ }
+
+ dev_info(&pdev->dev, "msi enabled:%d msix enabled:%d\n", pdev->msi_enabled,
+ pdev->msix_enabled);
+
+ for (i = 0; i < count; i++) {
+ irq = pci_irq_vector(pdev, i);
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
+ proc_thermal_irq_thread_handler,
+ 0, KBUILD_MODNAME, pci_info);
+ if (ret) {
+ dev_err(&pdev->dev, "Request IRQ %d failed\n", irq);
+ goto err_free_msi_vectors;
+ }
+
+ proc_thermal_msi_map[i] = irq;
+ }
+
+ msi_irq = true;
+
+ return 0;
+
+err_free_msi_vectors:
+ proc_thermal_free_msi(pdev, pci_info);
+
+ return ret;
+}
+
static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct proc_thermal_device *proc_priv;
struct proc_thermal_pci *pci_info;
+ struct thermal_trip psv_trip = {
+ .type = THERMAL_TRIP_PASSIVE,
+ .flags = THERMAL_TRIP_FLAG_RW_TEMP,
+ };
int irq_flag = 0, irq, ret;
- bool msi_irq = false;
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
if (!proc_priv)
@@ -290,7 +372,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
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,
+ 1, pci_info,
&tzone_ops,
&tzone_params, 0, 0);
if (IS_ERR(pci_info->tzone)) {
@@ -298,27 +380,24 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
goto err_del_legacy;
}
- if (use_msi && (pdev->msi_enabled || pdev->msix_enabled)) {
- /* request and enable interrupt */
- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to allocate vectors!\n");
- goto err_ret_tzone;
- }
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MSI_SUPPORT)
+ use_msi = true;
- irq = pci_irq_vector(pdev, 0);
- msi_irq = true;
+ if (use_msi) {
+ ret = proc_thermal_setup_msi(pdev, pci_info);
+ if (ret)
+ goto err_ret_tzone;
} else {
irq_flag = IRQF_SHARED;
irq = pdev->irq;
- }
- ret = devm_request_threaded_irq(&pdev->dev, irq,
- proc_thermal_irq_handler, proc_thermal_irq_thread_handler,
- irq_flag, KBUILD_MODNAME, pci_info);
- if (ret) {
- dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
- goto err_free_vectors;
+ ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
+ proc_thermal_irq_thread_handler, irq_flag,
+ KBUILD_MODNAME, pci_info);
+ if (ret) {
+ dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
+ goto err_ret_tzone;
+ }
}
ret = thermal_zone_device_enable(pci_info->tzone);
@@ -329,14 +408,13 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
err_free_vectors:
if (msi_irq)
- pci_free_irq_vectors(pdev);
+ proc_thermal_free_msi(pdev, pci_info);
err_ret_tzone:
thermal_zone_device_unregister(pci_info->tzone);
err_del_legacy:
if (!pci_info->no_legacy)
proc_thermal_remove(proc_priv);
proc_thermal_mmio_remove(pdev, proc_priv);
- pci_disable_device(pdev);
return ret;
}
@@ -351,14 +429,13 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev)
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
- devm_free_irq(&pdev->dev, pdev->irq, pci_info);
- pci_free_irq_vectors(pdev);
+ if (msi_irq)
+ proc_thermal_free_msi(pdev, pci_info);
thermal_zone_device_unregister(pci_info->tzone);
proc_thermal_mmio_remove(pdev, pci_info->proc_priv);
if (!pci_info->no_legacy)
proc_thermal_remove(proc_priv);
- pci_disable_device(pdev);
}
#ifdef CONFIG_PM_SLEEP
@@ -407,6 +484,10 @@ static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
static const struct pci_device_id proc_thermal_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
+ { PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
+ PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
+ PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR |
+ PROC_THERMAL_FEATURE_PTC) },
{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL |
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR |
PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },
@@ -414,6 +495,10 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_WT_HINT) },
{ PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
+ { PCI_DEVICE_DATA(INTEL, PTL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
+ PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
+ PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT |
+ PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) },
{ },
};
@@ -429,7 +514,7 @@ static struct pci_driver proc_thermal_pci_driver = {
module_pci_driver(proc_thermal_pci_driver);
-MODULE_IMPORT_NS(INT340X_THERMAL);
+MODULE_IMPORT_NS("INT340X_THERMAL");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
index 4d3bd32ff9ea..b1d531ef440f 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
@@ -94,7 +94,7 @@ int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp
return ret;
}
-EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, "INT340X_THERMAL");
int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
{
@@ -106,7 +106,7 @@ int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data
return ret;
}
-EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, "INT340X_THERMAL");
#define MBOX_CAMARILLO_RD_INTR_CONFIG 0x1E
#define MBOX_CAMARILLO_WR_INTR_CONFIG 0x1F
@@ -153,6 +153,7 @@ unlock:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, "INT340X_THERMAL");
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Processor Thermal Mail Box Interface");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c
index a1a108407f0f..25cdbb6d91a6 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c
@@ -42,7 +42,7 @@ int proc_thermal_read_power_floor_status(struct proc_thermal_device *proc_priv)
status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
return (status & SOC_POWER_FLOOR_STATUS) >> SOC_POWER_FLOOR_SHIFT;
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_read_power_floor_status, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_read_power_floor_status, "INT340X_THERMAL");
static bool enable_state;
static DEFINE_MUTEX(pf_lock);
@@ -69,13 +69,13 @@ pf_unlock:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_set_state, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_set_state, "INT340X_THERMAL");
bool proc_thermal_power_floor_get_state(struct proc_thermal_device *proc_priv)
{
return enable_state;
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_get_state, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_get_state, "INT340X_THERMAL");
/**
* proc_thermal_check_power_floor_intr() - Check power floor interrupt.
@@ -94,7 +94,7 @@ bool proc_thermal_check_power_floor_intr(struct proc_thermal_device *proc_priv)
int_status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
return !!(int_status & SOC_POWER_FLOOR_INT_ACTIVE);
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_check_power_floor_intr, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_check_power_floor_intr, "INT340X_THERMAL");
/**
* proc_thermal_power_floor_intr_callback() - Process power floor notification
@@ -120,7 +120,8 @@ void proc_thermal_power_floor_intr_callback(struct pci_dev *pdev,
sysfs_notify(&pdev->dev.kobj, "power_limits", "power_floor_status");
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_intr_callback, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_intr_callback, "INT340X_THERMAL");
-MODULE_IMPORT_NS(INT340X_THERMAL);
+MODULE_IMPORT_NS("INT340X_THERMAL");
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Processor Thermal power floor notification Interface");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
index 2f00fc3bf274..bde2cc386afd 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
@@ -13,48 +13,12 @@ static struct rapl_if_priv rapl_mmio_priv;
static const struct rapl_mmio_regs rapl_mmio_default = {
.reg_unit = 0x5938,
- .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
+ .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930, 0x59b0},
.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
- .limits[RAPL_DOMAIN_PACKAGE] = BIT(POWER_LIMIT2),
+ .limits[RAPL_DOMAIN_PACKAGE] = BIT(POWER_LIMIT2) | BIT(POWER_LIMIT4),
.limits[RAPL_DOMAIN_DRAM] = BIT(POWER_LIMIT2),
};
-static int rapl_mmio_cpu_online(unsigned int cpu)
-{
- struct rapl_package *rp;
-
- /* mmio rapl supports package 0 only for now */
- if (topology_physical_package_id(cpu))
- return 0;
-
- rp = rapl_find_package_domain(cpu, &rapl_mmio_priv, true);
- if (!rp) {
- rp = rapl_add_package(cpu, &rapl_mmio_priv, true);
- if (IS_ERR(rp))
- return PTR_ERR(rp);
- }
- cpumask_set_cpu(cpu, &rp->cpumask);
- return 0;
-}
-
-static int rapl_mmio_cpu_down_prep(unsigned int cpu)
-{
- struct rapl_package *rp;
- int lead_cpu;
-
- rp = rapl_find_package_domain(cpu, &rapl_mmio_priv, true);
- if (!rp)
- return 0;
-
- cpumask_clear_cpu(cpu, &rp->cpumask);
- lead_cpu = cpumask_first(&rp->cpumask);
- if (lead_cpu >= nr_cpu_ids)
- rapl_remove_package(rp);
- else if (rp->lead_cpu == cpu)
- rp->lead_cpu = lead_cpu;
- return 0;
-}
-
static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
{
if (!ra->reg.mmio)
@@ -82,6 +46,7 @@ static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default;
+ struct rapl_package *rp;
enum rapl_domain_reg_id reg;
enum rapl_domain_type domain;
int ret;
@@ -109,27 +74,41 @@ int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc
return PTR_ERR(rapl_mmio_priv.control_type);
}
- ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
- rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
- if (ret < 0) {
- powercap_unregister_control_type(rapl_mmio_priv.control_type);
- rapl_mmio_priv.control_type = NULL;
- return ret;
+ /* Register a RAPL package device for package 0 which is always online */
+ rp = rapl_find_package_domain(0, &rapl_mmio_priv, false);
+ if (rp) {
+ ret = -EEXIST;
+ goto err;
+ }
+
+ rp = rapl_add_package(0, &rapl_mmio_priv, false);
+ if (IS_ERR(rp)) {
+ ret = PTR_ERR(rp);
+ goto err;
}
- rapl_mmio_priv.pcap_rapl_online = ret;
return 0;
+
+err:
+ powercap_unregister_control_type(rapl_mmio_priv.control_type);
+ rapl_mmio_priv.control_type = NULL;
+ return ret;
}
EXPORT_SYMBOL_GPL(proc_thermal_rapl_add);
void proc_thermal_rapl_remove(void)
{
+ struct rapl_package *rp;
+
if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
return;
- cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
+ rp = rapl_find_package_domain(0, &rapl_mmio_priv, false);
+ if (rp)
+ rapl_remove_package(rp);
powercap_unregister_control_type(rapl_mmio_priv.control_type);
}
EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove);
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("RAPL interface using MMIO");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
index 546b70434004..3a028b78d9af 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
@@ -9,7 +9,7 @@
#include <linux/pci.h>
#include "processor_thermal_device.h"
-MODULE_IMPORT_NS(INT340X_THERMAL);
+MODULE_IMPORT_NS("INT340X_THERMAL");
struct mmio_reg {
int read_only;
@@ -19,6 +19,12 @@ struct mmio_reg {
u16 shift;
};
+struct mapping_table {
+ const char *attr_name;
+ const u32 value;
+ const char *mapped_str;
+};
+
/* These will represent sysfs attribute names */
static const char * const fivr_strings[] = {
"vco_ref_code_lo",
@@ -62,6 +68,78 @@ static const struct mmio_reg dlvr_mmio_regs[] = {
{ 1, 0x15A10, 1, 0x1, 16}, /* dlvr_pll_busy */
};
+static const struct mmio_reg lnl_dlvr_mmio_regs[] = {
+ { 0, 0x5A08, 5, 0x1F, 0}, /* dlvr_spread_spectrum_pct */
+ { 0, 0x5A08, 1, 0x1, 5}, /* dlvr_control_mode */
+ { 0, 0x5A08, 1, 0x1, 6}, /* dlvr_control_lock */
+ { 0, 0x5A08, 1, 0x1, 7}, /* dlvr_rfim_enable */
+ { 0, 0x5A08, 2, 0x3, 8}, /* dlvr_freq_select */
+ { 1, 0x5A10, 2, 0x3, 30}, /* dlvr_hardware_rev */
+ { 1, 0x5A10, 2, 0x3, 0}, /* dlvr_freq_mhz */
+ { 1, 0x5A10, 1, 0x1, 23}, /* dlvr_pll_busy */
+};
+
+static const struct mapping_table lnl_dlvr_mapping[] = {
+ {"dlvr_freq_select", 0, "2227.2"},
+ {"dlvr_freq_select", 1, "2140"},
+ {"dlvr_freq_mhz", 0, "2227.2"},
+ {"dlvr_freq_mhz", 1, "2140"},
+ {NULL, 0, NULL},
+};
+
+static int match_mapping_table(const struct mapping_table *table, const char *attr_name,
+ bool match_int_value, const u32 value, const char *value_str,
+ char **result_str, u32 *result_int)
+{
+ bool attr_matched = false;
+ int i = 0;
+
+ if (!table)
+ return -EOPNOTSUPP;
+
+ while (table[i].attr_name) {
+ if (strncmp(table[i].attr_name, attr_name, strlen(attr_name)))
+ goto match_next;
+
+ attr_matched = true;
+
+ if (match_int_value) {
+ if (table[i].value != value)
+ goto match_next;
+
+ *result_str = (char *)table[i].mapped_str;
+ return 0;
+ }
+
+ if (strncmp(table[i].mapped_str, value_str, strlen(table[i].mapped_str)))
+ goto match_next;
+
+ *result_int = table[i].value;
+
+ return 0;
+match_next:
+ i++;
+ }
+
+ /* If attribute name is matched, then the user space value is invalid */
+ if (attr_matched)
+ return -EINVAL;
+
+ return -EOPNOTSUPP;
+}
+
+static int get_mapped_string(const struct mapping_table *table, const char *attr_name,
+ u32 value, char **result)
+{
+ return match_mapping_table(table, attr_name, true, value, NULL, result, NULL);
+}
+
+static int get_mapped_value(const struct mapping_table *table, const char *attr_name,
+ const char *value, unsigned int *result)
+{
+ return match_mapping_table(table, attr_name, false, 0, value, NULL, result);
+}
+
/* These will represent sysfs attribute names */
static const char * const dvfs_strings[] = {
"rfi_restriction_run_busy",
@@ -88,17 +166,22 @@ static const struct mmio_reg adl_dvfs_mmio_regs[] = {
{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
};
+static const struct mapping_table *dlvr_mapping;
+static const struct mmio_reg *dlvr_mmio_regs_table;
+
#define RFIM_SHOW(suffix, table)\
static ssize_t suffix##_show(struct device *dev,\
struct device_attribute *attr,\
char *buf)\
{\
+ const struct mmio_reg *mmio_regs = dlvr_mmio_regs_table;\
+ const struct mapping_table *mapping = dlvr_mapping;\
struct proc_thermal_device *proc_priv;\
struct pci_dev *pdev = to_pci_dev(dev);\
- const struct mmio_reg *mmio_regs;\
const char **match_strs;\
+ int ret, err;\
u32 reg_val;\
- int ret;\
+ char *str;\
\
proc_priv = pci_get_drvdata(pdev);\
if (table == 1) {\
@@ -106,7 +189,6 @@ static ssize_t suffix##_show(struct device *dev,\
mmio_regs = adl_dvfs_mmio_regs;\
} else if (table == 2) { \
match_strs = (const char **)dlvr_strings;\
- mmio_regs = dlvr_mmio_regs;\
} else {\
match_strs = (const char **)fivr_strings;\
mmio_regs = tgl_fivr_mmio_regs;\
@@ -116,7 +198,12 @@ static ssize_t suffix##_show(struct device *dev,\
return ret;\
reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
- return sprintf(buf, "%u\n", ret);\
+ err = get_mapped_string(mapping, attr->attr.name, ret, &str);\
+ if (!err)\
+ return sprintf(buf, "%s\n", str);\
+ if (err == -EOPNOTSUPP)\
+ return sprintf(buf, "%u\n", ret);\
+ return err;\
}
#define RFIM_STORE(suffix, table)\
@@ -124,11 +211,12 @@ static ssize_t suffix##_store(struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count)\
{\
+ const struct mmio_reg *mmio_regs = dlvr_mmio_regs_table;\
+ const struct mapping_table *mapping = dlvr_mapping;\
struct proc_thermal_device *proc_priv;\
struct pci_dev *pdev = to_pci_dev(dev);\
unsigned int input;\
const char **match_strs;\
- const struct mmio_reg *mmio_regs;\
int ret, err;\
u32 reg_val;\
u32 mask;\
@@ -139,7 +227,6 @@ static ssize_t suffix##_store(struct device *dev,\
mmio_regs = adl_dvfs_mmio_regs;\
} else if (table == 2) { \
match_strs = (const char **)dlvr_strings;\
- mmio_regs = dlvr_mmio_regs;\
} else {\
match_strs = (const char **)fivr_strings;\
mmio_regs = tgl_fivr_mmio_regs;\
@@ -150,9 +237,14 @@ static ssize_t suffix##_store(struct device *dev,\
return ret;\
if (mmio_regs[ret].read_only)\
return -EPERM;\
- err = kstrtouint(buf, 10, &input);\
- if (err)\
+ err = get_mapped_value(mapping, attr->attr.name, buf, &input);\
+ if (err == -EINVAL)\
return err;\
+ if (err == -EOPNOTSUPP) {\
+ err = kstrtouint(buf, 10, &input);\
+ if (err)\
+ return err;\
+ } \
mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
reg_val &= ~mask;\
@@ -347,6 +439,16 @@ int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc
}
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_LNLM_THERMAL:
+ case PCI_DEVICE_ID_INTEL_PTL_THERMAL:
+ dlvr_mmio_regs_table = lnl_dlvr_mmio_regs;
+ dlvr_mapping = lnl_dlvr_mapping;
+ break;
+ default:
+ dlvr_mmio_regs_table = dlvr_mmio_regs;
+ break;
+ }
ret = sysfs_create_group(&pdev->dev.kobj, &dlvr_attribute_group);
if (ret)
return ret;
@@ -384,3 +486,4 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev)
EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Processor Thermal RFIM Interface");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
index 9d5e4c169d1b..68e8391af8f4 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
@@ -204,7 +204,7 @@ bool proc_thermal_check_wt_intr(struct proc_thermal_device *proc_priv)
return false;
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_check_wt_intr, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_check_wt_intr, "INT340X_THERMAL");
/* Callback to notify user space */
void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
@@ -217,7 +217,7 @@ void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_dev
sysfs_notify(&pdev->dev.kobj, "workload_hint", "workload_type_index");
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_intr_callback, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_intr_callback, "INT340X_THERMAL");
static bool workload_hint_created;
@@ -233,7 +233,7 @@ int proc_thermal_wt_hint_add(struct pci_dev *pdev, struct proc_thermal_device *p
return 0;
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_add, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_add, "INT340X_THERMAL");
void proc_thermal_wt_hint_remove(struct pci_dev *pdev)
{
@@ -249,7 +249,8 @@ void proc_thermal_wt_hint_remove(struct pci_dev *pdev)
workload_hint_created = false;
}
-EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_remove, INT340X_THERMAL);
+EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_remove, "INT340X_THERMAL");
-MODULE_IMPORT_NS(INT340X_THERMAL);
+MODULE_IMPORT_NS("INT340X_THERMAL");
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Processor Thermal Work Load type hint Interface");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c
index 711c4f761c9a..b95810f4a011 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c
@@ -132,5 +132,6 @@ void proc_thermal_wt_req_remove(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(proc_thermal_wt_req_remove);
-MODULE_IMPORT_NS(INT340X_THERMAL);
+MODULE_IMPORT_NS("INT340X_THERMAL");
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Processor Thermal Work Load type request Interface");
diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c
index 3b04c6ec4fca..bd2fca7dc017 100644
--- a/drivers/thermal/intel/intel_hfi.c
+++ b/drivers/thermal/intel/intel_hfi.c
@@ -159,14 +159,15 @@ struct hfi_cpu_info {
static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 };
static int max_hfi_instances;
+static int hfi_clients_nr;
static struct hfi_instance *hfi_instances;
static struct hfi_features hfi_features;
static DEFINE_MUTEX(hfi_instance_lock);
static struct workqueue_struct *hfi_updates_wq;
-#define HFI_UPDATE_INTERVAL HZ
-#define HFI_MAX_THERM_NOTIFY_COUNT 16
+#define HFI_UPDATE_DELAY_MS 100
+#define HFI_THERMNL_CAPS_PER_EVENT 64
static void get_hfi_caps(struct hfi_instance *hfi_instance,
struct thermal_genl_cpu_caps *cpu_caps)
@@ -217,14 +218,14 @@ static void update_capabilities(struct hfi_instance *hfi_instance)
get_hfi_caps(hfi_instance, cpu_caps);
- if (cpu_count < HFI_MAX_THERM_NOTIFY_COUNT)
+ if (cpu_count < HFI_THERMNL_CAPS_PER_EVENT)
goto last_cmd;
- /* Process complete chunks of HFI_MAX_THERM_NOTIFY_COUNT capabilities. */
+ /* Process complete chunks of HFI_THERMNL_CAPS_PER_EVENT capabilities. */
for (i = 0;
- (i + HFI_MAX_THERM_NOTIFY_COUNT) <= cpu_count;
- i += HFI_MAX_THERM_NOTIFY_COUNT)
- thermal_genl_cpu_capability_event(HFI_MAX_THERM_NOTIFY_COUNT,
+ (i + HFI_THERMNL_CAPS_PER_EVENT) <= cpu_count;
+ i += HFI_THERMNL_CAPS_PER_EVENT)
+ thermal_genl_cpu_capability_event(HFI_THERMNL_CAPS_PER_EVENT,
&cpu_caps[i]);
cpu_count = cpu_count - i;
@@ -283,7 +284,7 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
if (!raw_spin_trylock(&hfi_instance->event_lock))
return;
- rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr);
+ rdmsrq(MSR_IA32_PACKAGE_THERM_STATUS, msr);
hfi = msr & PACKAGE_THERM_STATUS_HFI_UPDATED;
if (!hfi) {
raw_spin_unlock(&hfi_instance->event_lock);
@@ -321,7 +322,7 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
raw_spin_unlock(&hfi_instance->event_lock);
queue_delayed_work(hfi_updates_wq, &hfi_instance->update_work,
- HFI_UPDATE_INTERVAL);
+ msecs_to_jiffies(HFI_UPDATE_DELAY_MS));
}
static void init_hfi_cpu_index(struct hfi_cpu_info *info)
@@ -355,9 +356,9 @@ static void hfi_enable(void)
{
u64 msr_val;
- rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
+ rdmsrq(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
msr_val |= HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
- wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
+ wrmsrq(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
}
static void hfi_set_hw_table(struct hfi_instance *hfi_instance)
@@ -367,7 +368,7 @@ static void hfi_set_hw_table(struct hfi_instance *hfi_instance)
hw_table_pa = virt_to_phys(hfi_instance->hw_table);
msr_val = hw_table_pa | HW_FEEDBACK_PTR_VALID_BIT;
- wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
+ wrmsrq(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
}
/* Caller must hold hfi_instance_lock. */
@@ -376,9 +377,9 @@ static void hfi_disable(void)
u64 msr_val;
int i;
- rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
+ rdmsrq(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
msr_val &= ~HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
- wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
+ wrmsrq(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
/*
* Wait for hardware to acknowledge the disabling of HFI. Some
@@ -387,7 +388,7 @@ static void hfi_disable(void)
* memory.
*/
for (i = 0; i < 2000; i++) {
- rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ rdmsrq(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
if (msr_val & PACKAGE_THERM_STATUS_HFI_UPDATED)
break;
@@ -400,10 +401,10 @@ static void hfi_disable(void)
* intel_hfi_online() - Enable HFI on @cpu
* @cpu: CPU in which the HFI will be enabled
*
- * Enable the HFI to be used in @cpu. The HFI is enabled at the die/package
- * level. The first CPU in the die/package to come online does the full HFI
+ * Enable the HFI to be used in @cpu. The HFI is enabled at the package
+ * level. The first CPU in the package to come online does the full HFI
* initialization. Subsequent CPUs will just link themselves to the HFI
- * instance of their die/package.
+ * instance of their package.
*
* This function is called before enabling the thermal vector in the local APIC
* in order to ensure that @cpu has an associated HFI instance when it receives
@@ -413,31 +414,31 @@ void intel_hfi_online(unsigned int cpu)
{
struct hfi_instance *hfi_instance;
struct hfi_cpu_info *info;
- u16 die_id;
+ u16 pkg_id;
/* Nothing to do if hfi_instances are missing. */
if (!hfi_instances)
return;
/*
- * Link @cpu to the HFI instance of its package/die. It does not
+ * Link @cpu to the HFI instance of its package. It does not
* matter whether the instance has been initialized.
*/
info = &per_cpu(hfi_cpu_info, cpu);
- die_id = topology_logical_die_id(cpu);
+ pkg_id = topology_logical_package_id(cpu);
hfi_instance = info->hfi_instance;
if (!hfi_instance) {
- if (die_id >= max_hfi_instances)
+ if (pkg_id >= max_hfi_instances)
return;
- hfi_instance = &hfi_instances[die_id];
+ hfi_instance = &hfi_instances[pkg_id];
info->hfi_instance = hfi_instance;
}
init_hfi_cpu_index(info);
/*
- * Now check if the HFI instance of the package/die of @cpu has been
+ * Now check if the HFI instance of the package of @cpu has been
* initialized (by checking its header). In such case, all we have to
* do is to add @cpu to this instance's cpumask and enable the instance
* if needed.
@@ -477,8 +478,11 @@ void intel_hfi_online(unsigned int cpu)
enable:
cpumask_set_cpu(cpu, hfi_instance->cpus);
- /* Enable this HFI instance if this is its first online CPU. */
- if (cpumask_weight(hfi_instance->cpus) == 1) {
+ /*
+ * Enable this HFI instance if this is its first online CPU and
+ * there are user-space clients of thermal events.
+ */
+ if (cpumask_weight(hfi_instance->cpus) == 1 && hfi_clients_nr > 0) {
hfi_set_hw_table(hfi_instance);
hfi_enable();
}
@@ -500,7 +504,7 @@ free_hw_table:
*
* On some processors, hardware remembers previous programming settings even
* after being reprogrammed. Thus, keep HFI enabled even if all CPUs in the
- * die/package of @cpu are offline. See note in intel_hfi_online().
+ * package of @cpu are offline. See note in intel_hfi_online().
*/
void intel_hfi_offline(unsigned int cpu)
{
@@ -573,18 +577,33 @@ static __init int hfi_parse_features(void)
return 0;
}
-static void hfi_do_enable(void)
+/*
+ * If concurrency is not prevented by other means, the HFI enable/disable
+ * routines must be called under hfi_instance_lock."
+ */
+static void hfi_enable_instance(void *ptr)
+{
+ hfi_set_hw_table(ptr);
+ hfi_enable();
+}
+
+static void hfi_disable_instance(void *ptr)
+{
+ hfi_disable();
+}
+
+static void hfi_syscore_resume(void)
{
/* This code runs only on the boot CPU. */
struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0);
struct hfi_instance *hfi_instance = info->hfi_instance;
/* No locking needed. There is no concurrency with CPU online. */
- hfi_set_hw_table(hfi_instance);
- hfi_enable();
+ if (hfi_clients_nr > 0)
+ hfi_enable_instance(hfi_instance);
}
-static int hfi_do_disable(void)
+static int hfi_syscore_suspend(void)
{
/* No locking needed. There is no concurrency with CPU offline. */
hfi_disable();
@@ -593,8 +612,58 @@ static int hfi_do_disable(void)
}
static struct syscore_ops hfi_pm_ops = {
- .resume = hfi_do_enable,
- .suspend = hfi_do_disable,
+ .resume = hfi_syscore_resume,
+ .suspend = hfi_syscore_suspend,
+};
+
+static int hfi_thermal_notify(struct notifier_block *nb, unsigned long state,
+ void *_notify)
+{
+ struct thermal_genl_notify *notify = _notify;
+ struct hfi_instance *hfi_instance;
+ smp_call_func_t func = NULL;
+ unsigned int cpu;
+ int i;
+
+ if (notify->mcgrp != THERMAL_GENL_EVENT_GROUP)
+ return NOTIFY_DONE;
+
+ if (state != THERMAL_NOTIFY_BIND && state != THERMAL_NOTIFY_UNBIND)
+ return NOTIFY_DONE;
+
+ mutex_lock(&hfi_instance_lock);
+
+ switch (state) {
+ case THERMAL_NOTIFY_BIND:
+ if (++hfi_clients_nr == 1)
+ func = hfi_enable_instance;
+ break;
+ case THERMAL_NOTIFY_UNBIND:
+ if (--hfi_clients_nr == 0)
+ func = hfi_disable_instance;
+ break;
+ }
+
+ if (!func)
+ goto out;
+
+ for (i = 0; i < max_hfi_instances; i++) {
+ hfi_instance = &hfi_instances[i];
+ if (cpumask_empty(hfi_instance->cpus))
+ continue;
+
+ cpu = cpumask_any(hfi_instance->cpus);
+ smp_call_function_single(cpu, func, hfi_instance, true);
+ }
+
+out:
+ mutex_unlock(&hfi_instance_lock);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hfi_thermal_nb = {
+ .notifier_call = hfi_thermal_notify,
};
void __init intel_hfi_init(void)
@@ -605,9 +674,13 @@ void __init intel_hfi_init(void)
if (hfi_parse_features())
return;
- /* There is one HFI instance per die/package. */
- max_hfi_instances = topology_max_packages() *
- topology_max_die_per_package();
+ /*
+ * Note: HFI resources are managed at the physical package scope.
+ * There could be platforms that enumerate packages as Linux dies.
+ * Special handling would be needed if this happens on an HFI-capable
+ * platform.
+ */
+ max_hfi_instances = topology_max_packages();
/*
* This allocation may fail. CPU hotplug callbacks must check
@@ -628,10 +701,22 @@ void __init intel_hfi_init(void)
if (!hfi_updates_wq)
goto err_nomem;
+ /*
+ * Both thermal core and Intel HFI can not be build as modules.
+ * As kernel build-in drivers they are initialized before user-space
+ * starts, hence we can not miss BIND/UNBIND events when applications
+ * add/remove thermal multicast group to/from a netlink socket.
+ */
+ if (thermal_genl_register_notifier(&hfi_thermal_nb))
+ goto err_nl_notif;
+
register_syscore_ops(&hfi_pm_ops);
return;
+err_nl_notif:
+ destroy_workqueue(hfi_updates_wq);
+
err_nomem:
for (j = 0; j < i; ++j) {
hfi_instance = &hfi_instances[j];
diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c
index b3905e34c507..fc326985796c 100644
--- a/drivers/thermal/intel/intel_pch_thermal.c
+++ b/drivers/thermal/intel/intel_pch_thermal.c
@@ -84,7 +84,6 @@ struct pch_thermal_device {
void __iomem *hw_base;
struct pci_dev *pdev;
struct thermal_zone_device *tzd;
- struct thermal_trip trips[PCH_MAX_TRIPS];
bool bios_enabled;
};
@@ -94,7 +93,8 @@ struct pch_thermal_device {
* passive trip temperature using _PSV method. There is no specific
* passive temperature setting in MMIO interface of this PCI device.
*/
-static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, int trip)
+static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
+ struct thermal_trip *trip)
{
struct acpi_device *adev;
int temp;
@@ -106,12 +106,13 @@ static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, int trip)
if (thermal_acpi_passive_trip_temp(adev, &temp) || temp <= 0)
return 0;
- ptd->trips[trip].type = THERMAL_TRIP_PASSIVE;
- ptd->trips[trip].temperature = temp;
+ trip->type = THERMAL_TRIP_PASSIVE;
+ trip->temperature = temp;
return 1;
}
#else
-static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, int trip)
+static int pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
+ struct thermal_trip *trip)
{
return 0;
}
@@ -131,7 +132,7 @@ static void pch_critical(struct thermal_zone_device *tzd)
thermal_zone_device_type(tzd));
}
-static struct thermal_zone_device_ops tzd_ops = {
+static const struct thermal_zone_device_ops tzd_ops = {
.get_temp = pch_thermal_get_temp,
.critical = pch_critical,
};
@@ -159,6 +160,7 @@ static const char *board_names[] = {
static int intel_pch_thermal_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
+ struct thermal_trip ptd_trips[PCH_MAX_TRIPS] = { 0 };
enum pch_board_ids board_id = id->driver_data;
struct pch_thermal_device *ptd;
int nr_trips = 0;
@@ -220,22 +222,22 @@ read_trips:
trip_temp = readw(ptd->hw_base + WPT_CTT);
trip_temp &= 0x1FF;
if (trip_temp) {
- ptd->trips[nr_trips].temperature = GET_WPT_TEMP(trip_temp);
- ptd->trips[nr_trips++].type = THERMAL_TRIP_CRITICAL;
+ ptd_trips[nr_trips].temperature = GET_WPT_TEMP(trip_temp);
+ ptd_trips[nr_trips++].type = THERMAL_TRIP_CRITICAL;
}
trip_temp = readw(ptd->hw_base + WPT_PHL);
trip_temp &= 0x1FF;
if (trip_temp) {
- ptd->trips[nr_trips].temperature = GET_WPT_TEMP(trip_temp);
- ptd->trips[nr_trips++].type = THERMAL_TRIP_HOT;
+ ptd_trips[nr_trips].temperature = GET_WPT_TEMP(trip_temp);
+ ptd_trips[nr_trips++].type = THERMAL_TRIP_HOT;
}
- nr_trips += pch_wpt_add_acpi_psv_trip(ptd, nr_trips);
+ nr_trips += pch_wpt_add_acpi_psv_trip(ptd, &ptd_trips[nr_trips]);
ptd->tzd = thermal_zone_device_register_with_trips(board_names[board_id],
- ptd->trips, nr_trips,
- 0, ptd, &tzd_ops,
+ ptd_trips, nr_trips,
+ ptd, &tzd_ops,
NULL, 0, 0);
if (IS_ERR(ptd->tzd)) {
dev_err(&pdev->dev, "Failed to register thermal zone %s\n",
@@ -296,6 +298,11 @@ static int intel_pch_thermal_suspend_noirq(struct device *device)
/* Get the PCH current temperature value */
pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
+ if (pch_cur_temp >= pch_thr_temp)
+ dev_warn(&ptd->pdev->dev,
+ "CPU-PCH current temp [%dC] higher than the threshold temp [%dC], S0ix might fail. Start cooling...\n",
+ pch_cur_temp, pch_thr_temp);
+
/*
* If current PCH temperature is higher than configured PCH threshold
* value, run some delay loop with sleep to let the current temperature
diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c
index 5ac5cb60bae6..9a4cec000910 100644
--- a/drivers/thermal/intel/intel_powerclamp.c
+++ b/drivers/thermal/intel/intel_powerclamp.c
@@ -49,7 +49,6 @@
*/
#define DEFAULT_DURATION_JIFFIES (6)
-static unsigned int target_mwait;
static struct dentry *debug_dir;
static bool poll_pkg_cstate_enable;
@@ -312,34 +311,6 @@ MODULE_PARM_DESC(window_size, "sliding window in number of clamping cycles\n"
"\twindow size results in slower response time but more smooth\n"
"\tclamping results. default to 2.");
-static void find_target_mwait(void)
-{
- unsigned int eax, ebx, ecx, edx;
- unsigned int highest_cstate = 0;
- unsigned int highest_subcstate = 0;
- int i;
-
- if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
- return;
-
- cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
-
- if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
- !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
- return;
-
- edx >>= MWAIT_SUBSTATE_SIZE;
- for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
- if (edx & MWAIT_SUBSTATE_MASK) {
- highest_cstate = i;
- highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
- }
- }
- target_mwait = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
- (highest_subcstate - 1);
-
-}
-
struct pkg_cstate_info {
bool skip;
int msr_index;
@@ -369,7 +340,7 @@ static bool has_pkg_state_counter(void)
/* check if any one of the counter msrs exists */
while (info->msr_index) {
- if (!rdmsrl_safe(info->msr_index, &val))
+ if (!rdmsrq_safe(info->msr_index, &val))
return true;
info++;
}
@@ -385,7 +356,7 @@ static u64 pkg_state_counter(void)
while (info->msr_index) {
if (!info->skip) {
- if (!rdmsrl_safe(info->msr_index, &val))
+ if (!rdmsrq_safe(info->msr_index, &val))
count += val;
else
info->skip = true;
@@ -616,7 +587,7 @@ static int powerclamp_idle_injection_register(void)
poll_pkg_cstate_enable = false;
if (cpumask_equal(cpu_present_mask, idle_injection_cpu_mask)) {
ii_dev = idle_inject_register_full(idle_injection_cpu_mask, idle_inject_update);
- if (topology_max_packages() == 1 && topology_max_die_per_package() == 1)
+ if (topology_max_packages() == 1 && topology_max_dies_per_package() == 1)
poll_pkg_cstate_enable = true;
} else {
ii_dev = idle_inject_register(idle_injection_cpu_mask);
@@ -759,9 +730,6 @@ static int __init powerclamp_probe(void)
return -ENODEV;
}
- /* find the deepest mwait value */
- find_target_mwait();
-
return 0;
}
@@ -841,7 +809,7 @@ static void __exit powerclamp_exit(void)
}
module_exit(powerclamp_exit);
-MODULE_IMPORT_NS(IDLE_INJECT);
+MODULE_IMPORT_NS("IDLE_INJECT");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index 646ca8bd40a9..89498eb29a89 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -93,10 +93,6 @@
/* Quark DTS has 2 trip points: hot & catastrophic */
#define QRK_MAX_DTS_TRIPS 2
-/* If DTS not locked, all trip points are configurable */
-#define QRK_DTS_WR_MASK_SET 0x3
-/* If DTS locked, all trip points are not configurable */
-#define QRK_DTS_WR_MASK_CLR 0
#define DEFAULT_POLL_DELAY 2000
@@ -105,7 +101,6 @@ struct soc_sensor_entry {
u32 store_ptps;
u32 store_dts_enable;
struct thermal_zone_device *tzone;
- struct thermal_trip trips[QRK_MAX_DTS_TRIPS];
};
static struct soc_sensor_entry *soc_dts;
@@ -200,7 +195,7 @@ static int get_trip_temp(int trip)
}
static int update_trip_temp(struct soc_sensor_entry *aux_entry,
- int trip, int temp)
+ int trip_index, int temp)
{
u32 out;
u32 temp_out;
@@ -235,9 +230,9 @@ static int update_trip_temp(struct soc_sensor_entry *aux_entry,
*/
temp_out = temp + QRK_DTS_TEMP_BASE;
out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES <<
- (trip * QRK_DTS_SHIFT_TP)));
+ (trip_index * QRK_DTS_SHIFT_TP)));
out |= (temp_out & QRK_DTS_MASK_TP_THRES) <<
- (trip * QRK_DTS_SHIFT_TP);
+ (trip_index * QRK_DTS_SHIFT_TP);
ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
QRK_DTS_REG_OFFSET_PTPS, out);
@@ -247,10 +242,26 @@ failed:
return ret;
}
-static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
- int temp)
+static inline int sys_set_trip_temp(struct thermal_zone_device *tzd,
+ const struct thermal_trip *trip,
+ int temp)
{
- return update_trip_temp(thermal_zone_device_priv(tzd), trip, temp);
+ unsigned int trip_index;
+
+ switch (trip->type) {
+ case THERMAL_TRIP_HOT:
+ trip_index = QRK_DTS_ID_TP_HOT;
+ break;
+
+ case THERMAL_TRIP_CRITICAL:
+ trip_index = QRK_DTS_ID_TP_CRITICAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return update_trip_temp(thermal_zone_device_priv(tzd), trip_index, temp);
}
static int sys_get_curr_temp(struct thermal_zone_device *tzd,
@@ -293,7 +304,7 @@ static int sys_change_mode(struct thermal_zone_device *tzd,
return ret;
}
-static struct thermal_zone_device_ops tzone_ops = {
+static const struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.set_trip_temp = sys_set_trip_temp,
.change_mode = sys_change_mode,
@@ -320,10 +331,10 @@ static void free_soc_dts(struct soc_sensor_entry *aux_entry)
static struct soc_sensor_entry *alloc_soc_dts(void)
{
+ struct thermal_trip trips[QRK_MAX_DTS_TRIPS] = { 0 };
struct soc_sensor_entry *aux_entry;
int err;
u32 out;
- int wr_mask;
aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL);
if (!aux_entry) {
@@ -337,13 +348,7 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
if (err)
goto err_ret;
- if (out & QRK_DTS_LOCK_BIT) {
- aux_entry->locked = true;
- wr_mask = QRK_DTS_WR_MASK_CLR;
- } else {
- aux_entry->locked = false;
- wr_mask = QRK_DTS_WR_MASK_SET;
- }
+ aux_entry->locked = !!(out & QRK_DTS_LOCK_BIT);
/* Store DTS default state if DTS registers are not locked */
if (!aux_entry->locked) {
@@ -360,19 +365,22 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
&aux_entry->store_ptps);
if (err)
goto err_ret;
+
+ trips[QRK_DTS_ID_TP_CRITICAL].flags |= THERMAL_TRIP_FLAG_RW_TEMP;
+ trips[QRK_DTS_ID_TP_HOT].flags |= THERMAL_TRIP_FLAG_RW_TEMP;
}
- aux_entry->trips[QRK_DTS_ID_TP_CRITICAL].temperature = get_trip_temp(QRK_DTS_ID_TP_CRITICAL);
- aux_entry->trips[QRK_DTS_ID_TP_CRITICAL].type = THERMAL_TRIP_CRITICAL;
+ trips[QRK_DTS_ID_TP_CRITICAL].temperature = get_trip_temp(QRK_DTS_ID_TP_CRITICAL);
+ trips[QRK_DTS_ID_TP_CRITICAL].type = THERMAL_TRIP_CRITICAL;
- aux_entry->trips[QRK_DTS_ID_TP_HOT].temperature = get_trip_temp(QRK_DTS_ID_TP_HOT);
- aux_entry->trips[QRK_DTS_ID_TP_HOT].type = THERMAL_TRIP_HOT;
+ trips[QRK_DTS_ID_TP_HOT].temperature = get_trip_temp(QRK_DTS_ID_TP_HOT);
+ trips[QRK_DTS_ID_TP_HOT].type = THERMAL_TRIP_HOT;
aux_entry->tzone = thermal_zone_device_register_with_trips("quark_dts",
- aux_entry->trips,
+ trips,
QRK_MAX_DTS_TRIPS,
- wr_mask,
- aux_entry, &tzone_ops,
+ aux_entry,
+ &tzone_ops,
NULL, 0, polling_delay);
if (IS_ERR(aux_entry->tzone)) {
err = PTR_ERR(aux_entry->tzone);
@@ -393,7 +401,7 @@ err_ret:
}
static const struct x86_cpu_id qrk_thermal_ids[] __initconst = {
- X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
+ X86_MATCH_VFM(INTEL_QUARK_X1000, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids);
diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c
index d00def3c4703..ea87439fe7a9 100644
--- a/drivers/thermal/intel/intel_soc_dts_iosf.c
+++ b/drivers/thermal/intel/intel_soc_dts_iosf.c
@@ -129,34 +129,20 @@ err_restore_ptps:
return status;
}
-static int configure_trip(struct intel_soc_dts_sensor_entry *dts,
- int thres_index, enum thermal_trip_type trip_type,
- int temp)
-{
- int ret;
-
- ret = update_trip_temp(dts->sensors, thres_index, temp);
- if (ret)
- return ret;
-
- dts->trips[thres_index].temperature = temp;
- dts->trips[thres_index].type = trip_type;
-
- return 0;
-}
-
-static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
+static int sys_set_trip_temp(struct thermal_zone_device *tzd,
+ const struct thermal_trip *trip,
int temp)
{
struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd);
struct intel_soc_dts_sensors *sensors = dts->sensors;
+ unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);
int status;
if (temp > sensors->tj_max)
return -EINVAL;
mutex_lock(&sensors->dts_update_lock);
- status = update_trip_temp(sensors, trip, temp);
+ status = update_trip_temp(sensors, trip_index, temp);
mutex_unlock(&sensors->dts_update_lock);
return status;
@@ -184,7 +170,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
return 0;
}
-static struct thermal_zone_device_ops tzone_ops = {
+static const struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.set_trip_temp = sys_set_trip_temp,
};
@@ -218,15 +204,10 @@ static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
}
static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
- bool critical_trip)
+ struct thermal_trip *trips)
{
- int writable_trip_cnt = SOC_MAX_DTS_TRIPS;
char name[10];
- unsigned long trip;
- int trip_mask;
- unsigned long ptps;
u32 store_ptps;
- unsigned long i;
int ret;
/* Store status to restor on exit */
@@ -237,26 +218,20 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
dts->id = id;
- if (critical_trip)
- writable_trip_cnt--;
-
- trip_mask = GENMASK(writable_trip_cnt - 1, 0);
-
/* Check if the writable trip we provide is not used by BIOS */
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
SOC_DTS_OFFSET_PTPS, &store_ptps);
- if (ret)
- trip_mask = 0;
- else {
- ptps = store_ptps;
- for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8)
- trip_mask &= ~BIT(i / 8);
+ if (!ret) {
+ int i;
+
+ for (i = 0; i <= 1; i++) {
+ if (store_ptps & (0xFFU << i * 8))
+ trips[i].flags &= ~THERMAL_TRIP_FLAG_RW_TEMP;
+ }
}
- dts->trip_mask = trip_mask;
snprintf(name, sizeof(name), "soc_dts%d", id);
- dts->tzone = thermal_zone_device_register_with_trips(name, dts->trips,
+ dts->tzone = thermal_zone_device_register_with_trips(name, trips,
SOC_MAX_DTS_TRIPS,
- trip_mask,
dts, &tzone_ops,
NULL, 0, 0);
if (IS_ERR(dts->tzone)) {
@@ -315,14 +290,24 @@ EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
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);
+ update_trip_temp(sensors, 0, 0);
+ update_trip_temp(sensors, 1, 0);
+}
+
+static void set_trip(struct thermal_trip *trip, enum thermal_trip_type type,
+ u8 flags, int temp, unsigned int index)
+{
+ trip->type = type;
+ trip->flags = flags;
+ trip->temperature = temp;
+ trip->priv = THERMAL_INT_TO_TRIP_PRIV(index);
}
struct intel_soc_dts_sensors *
intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type,
bool critical_trip, int crit_offset)
{
+ struct thermal_trip trips[SOC_MAX_DTS_SENSORS][SOC_MAX_DTS_TRIPS] = { 0 };
struct intel_soc_dts_sensors *sensors;
int tj_max;
int ret;
@@ -345,30 +330,33 @@ intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type,
sensors->tj_max = tj_max * 1000;
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- enum thermal_trip_type trip_type;
int temp;
sensors->soc_dts[i].sensors = sensors;
- ret = configure_trip(&sensors->soc_dts[i], 0,
- THERMAL_TRIP_PASSIVE, 0);
+ set_trip(&trips[i][0], THERMAL_TRIP_PASSIVE,
+ THERMAL_TRIP_FLAG_RW_TEMP, 0, 0);
+
+ ret = update_trip_temp(sensors, 0, 0);
if (ret)
goto err_reset_trips;
if (critical_trip) {
- trip_type = THERMAL_TRIP_CRITICAL;
temp = sensors->tj_max - crit_offset;
+ set_trip(&trips[i][1], THERMAL_TRIP_CRITICAL, 0, temp, 1);
} else {
- trip_type = THERMAL_TRIP_PASSIVE;
+ set_trip(&trips[i][1], THERMAL_TRIP_PASSIVE,
+ THERMAL_TRIP_FLAG_RW_TEMP, 0, 1);
temp = 0;
}
- ret = configure_trip(&sensors->soc_dts[i], 1, trip_type, temp);
+
+ ret = update_trip_temp(sensors, 1, temp);
if (ret)
goto err_reset_trips;
}
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], critical_trip);
+ ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], trips[i]);
if (ret)
goto err_remove_zone;
}
@@ -400,5 +388,6 @@ 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_IMPORT_NS("INTEL_TCC");
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SoC DTS driver using side band interface");
diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.h b/drivers/thermal/intel/intel_soc_dts_iosf.h
index 162841df0ebe..44eee844ab3c 100644
--- a/drivers/thermal/intel/intel_soc_dts_iosf.h
+++ b/drivers/thermal/intel/intel_soc_dts_iosf.h
@@ -28,8 +28,6 @@ struct intel_soc_dts_sensors;
struct intel_soc_dts_sensor_entry {
int id;
u32 store_status;
- u32 trip_mask;
- struct thermal_trip trips[SOC_MAX_DTS_TRIPS];
struct thermal_zone_device *tzone;
struct intel_soc_dts_sensors *sensors;
};
diff --git a/drivers/thermal/intel/intel_soc_dts_thermal.c b/drivers/thermal/intel/intel_soc_dts_thermal.c
index 9c825c6e1f38..718c6326eaf4 100644
--- a/drivers/thermal/intel/intel_soc_dts_thermal.c
+++ b/drivers/thermal/intel/intel_soc_dts_thermal.c
@@ -36,7 +36,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data)
}
static const struct x86_cpu_id soc_thermal_ids[] = {
- X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, BYT_SOC_DTS_APIC_IRQ),
+ X86_MATCH_VFM(INTEL_ATOM_SILVERMONT, BYT_SOC_DTS_APIC_IRQ),
{}
};
MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids);
diff --git a/drivers/thermal/intel/intel_tcc.c b/drivers/thermal/intel/intel_tcc.c
index 2e5c741c41ca..b2a615aea7c1 100644
--- a/drivers/thermal/intel/intel_tcc.c
+++ b/drivers/thermal/intel/intel_tcc.c
@@ -6,9 +6,171 @@
#include <linux/errno.h>
#include <linux/intel_tcc.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
#include <asm/msr.h>
/**
+ * struct temp_masks - Bitmasks for temperature readings
+ * @tcc_offset: TCC offset in MSR_TEMPERATURE_TARGET
+ * @digital_readout: Digital readout in MSR_IA32_THERM_STATUS
+ * @pkg_digital_readout: Digital readout in MSR_IA32_PACKAGE_THERM_STATUS
+ *
+ * Bitmasks to extract the fields of the MSR_TEMPERATURE and IA32_[PACKAGE]_
+ * THERM_STATUS registers for different processor models.
+ *
+ * The bitmask of TjMax is not included in this structure. It is always 0xff.
+ */
+struct temp_masks {
+ u32 tcc_offset;
+ u32 digital_readout;
+ u32 pkg_digital_readout;
+};
+
+#define TCC_MODEL_TEMP_MASKS(model, _tcc_offset, _digital_readout, \
+ _pkg_digital_readout) \
+ static const struct temp_masks temp_##model __initconst = { \
+ .tcc_offset = _tcc_offset, \
+ .digital_readout = _digital_readout, \
+ .pkg_digital_readout = _pkg_digital_readout \
+ }
+
+TCC_MODEL_TEMP_MASKS(nehalem, 0, 0x7f, 0x7f);
+TCC_MODEL_TEMP_MASKS(haswell_x, 0xf, 0x7f, 0x7f);
+TCC_MODEL_TEMP_MASKS(broadwell, 0x3f, 0x7f, 0x7f);
+TCC_MODEL_TEMP_MASKS(goldmont, 0x7f, 0x7f, 0x7f);
+TCC_MODEL_TEMP_MASKS(tigerlake, 0x3f, 0xff, 0xff);
+TCC_MODEL_TEMP_MASKS(sapphirerapids, 0x3f, 0x7f, 0xff);
+
+/* Use these masks for processors not included in @tcc_cpu_ids. */
+static struct temp_masks intel_tcc_temp_masks __ro_after_init = {
+ .tcc_offset = 0x7f,
+ .digital_readout = 0xff,
+ .pkg_digital_readout = 0xff,
+};
+
+static const struct x86_cpu_id intel_tcc_cpu_ids[] __initconst = {
+ X86_MATCH_VFM(INTEL_CORE_YONAH, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_CORE2_MEROM, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_CORE2_MEROM_L, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_CORE2_PENRYN, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_CORE2_DUNNINGTON, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_NEHALEM, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_NEHALEM_G, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_NEHALEM_EP, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_NEHALEM_EX, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_WESTMERE, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_WESTMERE_EP, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_WESTMERE_EX, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_SANDYBRIDGE, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_SANDYBRIDGE_X, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_IVYBRIDGE, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_IVYBRIDGE_X, &temp_haswell_x),
+ X86_MATCH_VFM(INTEL_HASWELL, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_HASWELL_X, &temp_haswell_x),
+ X86_MATCH_VFM(INTEL_HASWELL_L, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_HASWELL_G, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_BROADWELL, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_BROADWELL_G, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_BROADWELL_X, &temp_haswell_x),
+ X86_MATCH_VFM(INTEL_BROADWELL_D, &temp_haswell_x),
+ X86_MATCH_VFM(INTEL_SKYLAKE_L, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_SKYLAKE, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_SKYLAKE_X, &temp_haswell_x),
+ X86_MATCH_VFM(INTEL_KABYLAKE_L, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_KABYLAKE, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_COMETLAKE, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_COMETLAKE_L, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_CANNONLAKE_L, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ICELAKE_X, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ICELAKE_D, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ICELAKE, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ICELAKE_L, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ICELAKE_NNPI, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ROCKETLAKE, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_TIGERLAKE_L, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_TIGERLAKE, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &temp_sapphirerapids),
+ X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &temp_sapphirerapids),
+ X86_MATCH_VFM(INTEL_LAKEFIELD, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ALDERLAKE, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_ALDERLAKE_L, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_RAPTORLAKE, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_RAPTORLAKE_P, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_RAPTORLAKE_S, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_ATOM_BONNELL, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_ATOM_BONNELL_MID, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_ATOM_SALTWELL, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_ATOM_SALTWELL_MID, &temp_nehalem),
+ X86_MATCH_VFM(INTEL_ATOM_SILVERMONT, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_D, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_MID, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_AIRMONT, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_MID2, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_AIRMONT_NP, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &temp_goldmont),
+ X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_D, &temp_goldmont),
+ X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, &temp_goldmont),
+ X86_MATCH_VFM(INTEL_ATOM_TREMONT_D, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_TREMONT, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, &temp_tigerlake),
+ X86_MATCH_VFM(INTEL_XEON_PHI_KNL, &temp_broadwell),
+ X86_MATCH_VFM(INTEL_XEON_PHI_KNM, &temp_broadwell),
+ {}
+};
+
+static int __init intel_tcc_init(void)
+{
+ const struct x86_cpu_id *id;
+
+ id = x86_match_cpu(intel_tcc_cpu_ids);
+ if (id)
+ memcpy(&intel_tcc_temp_masks, (const void *)id->driver_data,
+ sizeof(intel_tcc_temp_masks));
+
+ return 0;
+}
+/*
+ * Use subsys_initcall to ensure temperature bitmasks are initialized before
+ * the drivers that use this library.
+ */
+subsys_initcall(intel_tcc_init);
+
+/**
+ * intel_tcc_get_offset_mask() - Returns the bitmask to read TCC offset
+ *
+ * Get the model-specific bitmask to extract TCC_OFFSET from the MSR
+ * TEMPERATURE_TARGET register. If the mask is 0, it means the processor does
+ * not support TCC offset.
+ *
+ * Return: The model-specific bitmask for TCC offset.
+ */
+u32 intel_tcc_get_offset_mask(void)
+{
+ return intel_tcc_temp_masks.tcc_offset;
+}
+EXPORT_SYMBOL_NS(intel_tcc_get_offset_mask, "INTEL_TCC");
+
+/**
+ * get_temp_mask() - Returns the model-specific bitmask for temperature
+ *
+ * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
+ *
+ * Get the model-specific bitmask to extract the temperature reading from the
+ * MSR_IA32_[PACKAGE]_THERM_STATUS register.
+ *
+ * Callers must check if the thermal status registers are supported.
+ *
+ * Return: The model-specific bitmask for temperature reading
+ */
+static u32 get_temp_mask(bool pkg)
+{
+ return pkg ? intel_tcc_temp_masks.pkg_digital_readout :
+ intel_tcc_temp_masks.digital_readout;
+}
+
+/**
* intel_tcc_get_tjmax() - returns the default TCC activation Temperature
* @cpu: cpu that the MSR should be run on, nagative value means any cpu.
*
@@ -33,7 +195,7 @@ int intel_tcc_get_tjmax(int cpu)
return val ? val : -ENODATA;
}
-EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC);
+EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, "INTEL_TCC");
/**
* intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
@@ -56,9 +218,9 @@ int intel_tcc_get_offset(int cpu)
if (err)
return err;
- return (low >> 24) & 0x3f;
+ return (low >> 24) & intel_tcc_temp_masks.tcc_offset;
}
-EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC);
+EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, "INTEL_TCC");
/**
* intel_tcc_set_offset() - set the TCC offset value to Tjmax
@@ -76,7 +238,10 @@ int intel_tcc_set_offset(int cpu, int offset)
u32 low, high;
int err;
- if (offset < 0 || offset > 0x3f)
+ if (!intel_tcc_temp_masks.tcc_offset)
+ return -ENODEV;
+
+ if (offset < 0 || offset > intel_tcc_temp_masks.tcc_offset)
return -EINVAL;
if (cpu < 0)
@@ -90,7 +255,7 @@ int intel_tcc_set_offset(int cpu, int offset)
if (low & BIT(31))
return -EPERM;
- low &= ~(0x3f << 24);
+ low &= ~(intel_tcc_temp_masks.tcc_offset << 24);
low |= offset << 24;
if (cpu < 0)
@@ -98,23 +263,24 @@ int intel_tcc_set_offset(int cpu, int offset)
else
return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high);
}
-EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC);
+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.
+ * @temp: pointer to the memory for saving cpu temperature.
* @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.
+ * Return: 0 on success, negative error code otherwise.
*/
-int intel_tcc_get_temp(int cpu, bool pkg)
+int intel_tcc_get_temp(int cpu, int *temp, bool pkg)
{
- u32 low, high;
u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
- int tjmax, temp, err;
+ u32 low, high, mask;
+ int tjmax, err;
tjmax = intel_tcc_get_tjmax(cpu);
if (tjmax < 0)
@@ -131,9 +297,10 @@ int intel_tcc_get_temp(int cpu, bool pkg)
if (!(low & BIT(31)))
return -ENODATA;
- temp = tjmax - ((low >> 16) & 0x7f);
+ mask = get_temp_mask(pkg);
+
+ *temp = tjmax - ((low >> 16) & mask);
- /* Do not allow negative CPU temperature */
- return temp >= 0 ? temp : -ENODATA;
+ return 0;
}
-EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC);
+EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, "INTEL_TCC");
diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c
index 6c392147e6d1..f352ecafbedf 100644
--- a/drivers/thermal/intel/intel_tcc_cooling.c
+++ b/drivers/thermal/intel/intel_tcc_cooling.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/thermal.h>
#include <asm/cpu_device_id.h>
+#include <asm/msr.h>
#define TCC_PROGRAMMABLE BIT(30)
#define TCC_LOCKED BIT(31)
@@ -20,7 +21,7 @@ static struct thermal_cooling_device *tcc_cdev;
static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
*state)
{
- *state = 0x3f;
+ *state = intel_tcc_get_offset_mask();
return 0;
}
@@ -49,21 +50,21 @@ static const struct thermal_cooling_device_ops tcc_cooling_ops = {
};
static const struct x86_cpu_id tcc_ids[] __initconst = {
- X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, NULL),
+ X86_MATCH_VFM(INTEL_SKYLAKE, NULL),
+ X86_MATCH_VFM(INTEL_SKYLAKE_L, NULL),
+ X86_MATCH_VFM(INTEL_KABYLAKE, NULL),
+ X86_MATCH_VFM(INTEL_KABYLAKE_L, NULL),
+ X86_MATCH_VFM(INTEL_ICELAKE, NULL),
+ X86_MATCH_VFM(INTEL_ICELAKE_L, NULL),
+ X86_MATCH_VFM(INTEL_TIGERLAKE, NULL),
+ X86_MATCH_VFM(INTEL_TIGERLAKE_L, NULL),
+ X86_MATCH_VFM(INTEL_COMETLAKE, NULL),
+ X86_MATCH_VFM(INTEL_ALDERLAKE, NULL),
+ X86_MATCH_VFM(INTEL_ALDERLAKE_L, NULL),
+ X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, NULL),
+ X86_MATCH_VFM(INTEL_RAPTORLAKE, NULL),
+ X86_MATCH_VFM(INTEL_RAPTORLAKE_P, NULL),
+ X86_MATCH_VFM(INTEL_RAPTORLAKE_S, NULL),
{}
};
@@ -81,14 +82,14 @@ static int __init tcc_cooling_init(void)
if (!id)
return -ENODEV;
- err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
+ err = rdmsrq_safe(MSR_PLATFORM_INFO, &val);
if (err)
return err;
if (!(val & TCC_PROGRAMMABLE))
return -ENODEV;
- err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+ err = rdmsrq_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err)
return err;
@@ -118,7 +119,7 @@ static void __exit tcc_cooling_exit(void)
module_exit(tcc_cooling_exit)
-MODULE_IMPORT_NS(INTEL_TCC);
+MODULE_IMPORT_NS("INTEL_TCC");
MODULE_DESCRIPTION("TCC offset cooling device Driver");
MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c
index e69868e868eb..debc94e2dc16 100644
--- a/drivers/thermal/intel/therm_throt.c
+++ b/drivers/thermal/intel/therm_throt.c
@@ -273,7 +273,7 @@ void thermal_clear_package_intr_status(int level, u64 bit_mask)
}
msr_val &= ~bit_mask;
- wrmsrl(msr, msr_val);
+ wrmsrq(msr, msr_val);
}
EXPORT_SYMBOL_GPL(thermal_clear_package_intr_status);
@@ -287,7 +287,7 @@ static void get_therm_status(int level, bool *proc_hot, u8 *temp)
else
msr = MSR_IA32_PACKAGE_THERM_STATUS;
- rdmsrl(msr, msr_val);
+ rdmsrq(msr, msr_val);
if (msr_val & THERM_STATUS_PROCHOT_LOG)
*proc_hot = true;
else
@@ -643,7 +643,7 @@ static void notify_thresholds(__u64 msr_val)
void __weak notify_hwp_interrupt(void)
{
- wrmsrl_safe(MSR_HWP_STATUS, 0);
+ wrmsrq_safe(MSR_HWP_STATUS, 0);
}
/* Thermal transition interrupt handler */
@@ -654,7 +654,7 @@ void intel_thermal_interrupt(void)
if (static_cpu_has(X86_FEATURE_HWP))
notify_hwp_interrupt();
- rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
+ rdmsrq(MSR_IA32_THERM_STATUS, msr_val);
/* Check for violation of core thermal thresholds*/
notify_thresholds(msr_val);
@@ -669,7 +669,7 @@ void intel_thermal_interrupt(void)
CORE_LEVEL);
if (this_cpu_has(X86_FEATURE_PTS)) {
- rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ rdmsrq(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
/* check violations of package thermal thresholds */
notify_package_thresholds(msr_val);
therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index 11a7f8108bbb..3fc679b6f11b 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <asm/cpu_device_id.h>
+#include <asm/msr.h>
#include "thermal_interrupt.h"
@@ -53,7 +54,6 @@ struct zone_device {
u32 msr_pkg_therm_high;
struct delayed_work work;
struct thermal_zone_device *tzone;
- struct thermal_trip *trips;
struct cpumask cpumask;
};
@@ -108,11 +108,11 @@ static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu)
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
{
struct zone_device *zonedev = thermal_zone_device_priv(tzd);
- int val;
+ int val, ret;
- val = intel_tcc_get_temp(zonedev->cpu, true);
- if (val < 0)
- return val;
+ ret = intel_tcc_get_temp(zonedev->cpu, &val, true);
+ if (ret < 0)
+ return ret;
*temp = val * 1000;
pr_debug("sys_get_curr_temp %d\n", *temp);
@@ -120,9 +120,11 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
}
static int
-sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
+sys_set_trip_temp(struct thermal_zone_device *tzd,
+ const struct thermal_trip *trip, int temp)
{
struct zone_device *zonedev = thermal_zone_device_priv(tzd);
+ unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);
u32 l, h, mask, shift, intr;
int tj_max, val, ret;
@@ -133,7 +135,7 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
val = (tj_max - temp)/1000;
- if (trip >= MAX_NUMBER_OF_TRIPS || val < 0 || val > 0x7f)
+ if (trip_index >= MAX_NUMBER_OF_TRIPS || val < 0 || val > 0x7f)
return -EINVAL;
ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
@@ -141,7 +143,7 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
if (ret < 0)
return ret;
- if (trip) {
+ if (trip_index) {
mask = THERM_MASK_THRESHOLD1;
shift = THERM_SHIFT_THRESHOLD1;
intr = THERM_INT_THRESHOLD1_ENABLE;
@@ -167,7 +169,7 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
}
/* Thermal zone callback registry */
-static struct thermal_zone_device_ops tzone_ops = {
+static const struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.set_trip_temp = sys_set_trip_temp,
};
@@ -268,17 +270,13 @@ static int pkg_thermal_notify(u64 msr_val)
return 0;
}
-static struct thermal_trip *pkg_temp_thermal_trips_init(int cpu, int tj_max, int num_trips)
+static int pkg_temp_thermal_trips_init(int cpu, int tj_max,
+ struct thermal_trip *trips, int num_trips)
{
- struct thermal_trip *trips;
unsigned long thres_reg_value;
u32 mask, shift, eax, edx;
int ret, i;
- trips = kzalloc(sizeof(*trips) * num_trips, GFP_KERNEL);
- if (!trips)
- return ERR_PTR(-ENOMEM);
-
for (i = 0; i < num_trips; i++) {
if (i) {
@@ -291,10 +289,8 @@ static struct thermal_trip *pkg_temp_thermal_trips_init(int cpu, int tj_max, int
ret = rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
&eax, &edx);
- if (ret < 0) {
- kfree(trips);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ return ret;
thres_reg_value = (eax & mask) >> shift;
@@ -302,16 +298,19 @@ static struct thermal_trip *pkg_temp_thermal_trips_init(int cpu, int tj_max, int
tj_max - thres_reg_value * 1000 : THERMAL_TEMP_INVALID;
trips[i].type = THERMAL_TRIP_PASSIVE;
+ trips[i].flags |= THERMAL_TRIP_FLAG_RW_TEMP;
+ trips[i].priv = THERMAL_INT_TO_TRIP_PRIV(i);
pr_debug("%s: cpu=%d, trip=%d, temp=%d\n",
__func__, cpu, i, trips[i].temperature);
}
- return trips;
+ return 0;
}
static int pkg_temp_thermal_device_add(unsigned int cpu)
{
+ struct thermal_trip trips[MAX_NUMBER_OF_TRIPS] = { 0 };
int id = topology_logical_die_id(cpu);
u32 eax, ebx, ecx, edx;
struct zone_device *zonedev;
@@ -331,26 +330,24 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
tj_max = intel_tcc_get_tjmax(cpu);
if (tj_max < 0)
return tj_max;
+ tj_max *= 1000;
zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL);
if (!zonedev)
return -ENOMEM;
- zonedev->trips = pkg_temp_thermal_trips_init(cpu, tj_max, thres_count);
- if (IS_ERR(zonedev->trips)) {
- err = PTR_ERR(zonedev->trips);
+ err = pkg_temp_thermal_trips_init(cpu, tj_max, trips, thres_count);
+ if (err)
goto out_kfree_zonedev;
- }
INIT_DELAYED_WORK(&zonedev->work, pkg_temp_thermal_threshold_work_fn);
zonedev->cpu = cpu;
zonedev->tzone = thermal_zone_device_register_with_trips("x86_pkg_temp",
- zonedev->trips, thres_count,
- (thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01,
+ trips, thres_count,
zonedev, &tzone_ops, &pkg_temp_tz_params, 0, 0);
if (IS_ERR(zonedev->tzone)) {
err = PTR_ERR(zonedev->tzone);
- goto out_kfree_trips;
+ goto out_kfree_zonedev;
}
err = thermal_zone_device_enable(zonedev->tzone);
if (err)
@@ -369,8 +366,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
out_unregister_tz:
thermal_zone_device_unregister(zonedev->tzone);
-out_kfree_trips:
- kfree(zonedev->trips);
out_kfree_zonedev:
kfree(zonedev);
return err;
@@ -457,10 +452,9 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
raw_spin_unlock_irq(&pkg_temp_lock);
/* Final cleanup if this is the last cpu */
- if (lastcpu) {
- kfree(zonedev->trips);
+ if (lastcpu)
kfree(zonedev);
- }
+
return 0;
}
@@ -494,7 +488,7 @@ static int __init pkg_temp_thermal_init(void)
if (!x86_match_cpu(pkg_temp_thermal_ids))
return -ENODEV;
- max_id = topology_max_packages() * topology_max_die_per_package();
+ max_id = topology_max_packages() * topology_max_dies_per_package();
zones = kcalloc(max_id, sizeof(struct zone_device *),
GFP_KERNEL);
if (!zones)
@@ -532,7 +526,7 @@ static void __exit pkg_temp_thermal_exit(void)
}
module_exit(pkg_temp_thermal_exit)
-MODULE_IMPORT_NS(INTEL_TCC);
+MODULE_IMPORT_NS("INTEL_TCC");
MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");