cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel_soc_dts_iosf.c (11733B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * intel_soc_dts_iosf.c
      4 * Copyright (c) 2015, Intel Corporation.
      5 */
      6
      7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      8
      9#include <linux/bitops.h>
     10#include <linux/module.h>
     11#include <linux/slab.h>
     12#include <linux/interrupt.h>
     13#include <asm/iosf_mbi.h>
     14#include "intel_soc_dts_iosf.h"
     15
     16#define SOC_DTS_OFFSET_ENABLE		0xB0
     17#define SOC_DTS_OFFSET_TEMP		0xB1
     18
     19#define SOC_DTS_OFFSET_PTPS		0xB2
     20#define SOC_DTS_OFFSET_PTTS		0xB3
     21#define SOC_DTS_OFFSET_PTTSS		0xB4
     22#define SOC_DTS_OFFSET_PTMC		0x80
     23#define SOC_DTS_TE_AUX0			0xB5
     24#define SOC_DTS_TE_AUX1			0xB6
     25
     26#define SOC_DTS_AUX0_ENABLE_BIT		BIT(0)
     27#define SOC_DTS_AUX1_ENABLE_BIT		BIT(1)
     28#define SOC_DTS_CPU_MODULE0_ENABLE_BIT	BIT(16)
     29#define SOC_DTS_CPU_MODULE1_ENABLE_BIT	BIT(17)
     30#define SOC_DTS_TE_SCI_ENABLE		BIT(9)
     31#define SOC_DTS_TE_SMI_ENABLE		BIT(10)
     32#define SOC_DTS_TE_MSI_ENABLE		BIT(11)
     33#define SOC_DTS_TE_APICA_ENABLE		BIT(14)
     34#define SOC_DTS_PTMC_APIC_DEASSERT_BIT	BIT(4)
     35
     36/* DTS encoding for TJ MAX temperature */
     37#define SOC_DTS_TJMAX_ENCODING		0x7F
     38
     39/* Only 2 out of 4 is allowed for OSPM */
     40#define SOC_MAX_DTS_TRIPS		2
     41
     42/* Mask for two trips in status bits */
     43#define SOC_DTS_TRIP_MASK		0x03
     44
     45/* DTS0 and DTS 1 */
     46#define SOC_MAX_DTS_SENSORS		2
     47
     48static int get_tj_max(u32 *tj_max)
     49{
     50	u32 eax, edx;
     51	u32 val;
     52	int err;
     53
     54	err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
     55	if (err)
     56		goto err_ret;
     57	else {
     58		val = (eax >> 16) & 0xff;
     59		if (val)
     60			*tj_max = val * 1000;
     61		else {
     62			err = -EINVAL;
     63			goto err_ret;
     64		}
     65	}
     66
     67	return 0;
     68err_ret:
     69	*tj_max = 0;
     70
     71	return err;
     72}
     73
     74static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
     75			     int *temp)
     76{
     77	int status;
     78	u32 out;
     79	struct intel_soc_dts_sensor_entry *dts;
     80	struct intel_soc_dts_sensors *sensors;
     81
     82	dts = tzd->devdata;
     83	sensors = dts->sensors;
     84	mutex_lock(&sensors->dts_update_lock);
     85	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
     86			       SOC_DTS_OFFSET_PTPS, &out);
     87	mutex_unlock(&sensors->dts_update_lock);
     88	if (status)
     89		return status;
     90
     91	out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING;
     92	if (!out)
     93		*temp = 0;
     94	else
     95		*temp = sensors->tj_max - out * 1000;
     96
     97	return 0;
     98}
     99
    100static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
    101			    int thres_index, int temp,
    102			    enum thermal_trip_type trip_type)
    103{
    104	int status;
    105	u32 temp_out;
    106	u32 out;
    107	unsigned long update_ptps;
    108	u32 store_ptps;
    109	u32 store_ptmc;
    110	u32 store_te_out;
    111	u32 te_out;
    112	u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
    113	struct intel_soc_dts_sensors *sensors = dts->sensors;
    114
    115	if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
    116		int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
    117
    118	temp_out = (sensors->tj_max - temp) / 1000;
    119
    120	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    121			       SOC_DTS_OFFSET_PTPS, &store_ptps);
    122	if (status)
    123		return status;
    124
    125	update_ptps = store_ptps;
    126	bitmap_set_value8(&update_ptps, temp_out & 0xFF, thres_index * 8);
    127	out = update_ptps;
    128
    129	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    130				SOC_DTS_OFFSET_PTPS, out);
    131	if (status)
    132		return status;
    133
    134	pr_debug("update_trip_temp PTPS = %x\n", out);
    135	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    136			       SOC_DTS_OFFSET_PTMC, &out);
    137	if (status)
    138		goto err_restore_ptps;
    139
    140	store_ptmc = out;
    141
    142	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    143			       SOC_DTS_TE_AUX0 + thres_index,
    144			       &te_out);
    145	if (status)
    146		goto err_restore_ptmc;
    147
    148	store_te_out = te_out;
    149	/* Enable for CPU module 0 and module 1 */
    150	out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT |
    151					SOC_DTS_CPU_MODULE1_ENABLE_BIT);
    152	if (temp) {
    153		if (thres_index)
    154			out |= SOC_DTS_AUX1_ENABLE_BIT;
    155		else
    156			out |= SOC_DTS_AUX0_ENABLE_BIT;
    157		te_out |= int_enable_bit;
    158	} else {
    159		if (thres_index)
    160			out &= ~SOC_DTS_AUX1_ENABLE_BIT;
    161		else
    162			out &= ~SOC_DTS_AUX0_ENABLE_BIT;
    163		te_out &= ~int_enable_bit;
    164	}
    165	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    166				SOC_DTS_OFFSET_PTMC, out);
    167	if (status)
    168		goto err_restore_te_out;
    169
    170	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    171				SOC_DTS_TE_AUX0 + thres_index,
    172				te_out);
    173	if (status)
    174		goto err_restore_te_out;
    175
    176	dts->trip_types[thres_index] = trip_type;
    177
    178	return 0;
    179err_restore_te_out:
    180	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    181		       SOC_DTS_OFFSET_PTMC, store_te_out);
    182err_restore_ptmc:
    183	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    184		       SOC_DTS_OFFSET_PTMC, store_ptmc);
    185err_restore_ptps:
    186	iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    187		       SOC_DTS_OFFSET_PTPS, store_ptps);
    188	/* Nothing we can do if restore fails */
    189
    190	return status;
    191}
    192
    193static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
    194			     int temp)
    195{
    196	struct intel_soc_dts_sensor_entry *dts = tzd->devdata;
    197	struct intel_soc_dts_sensors *sensors = dts->sensors;
    198	int status;
    199
    200	if (temp > sensors->tj_max)
    201		return -EINVAL;
    202
    203	mutex_lock(&sensors->dts_update_lock);
    204	status = update_trip_temp(tzd->devdata, trip, temp,
    205				  dts->trip_types[trip]);
    206	mutex_unlock(&sensors->dts_update_lock);
    207
    208	return status;
    209}
    210
    211static int sys_get_trip_type(struct thermal_zone_device *tzd,
    212			     int trip, enum thermal_trip_type *type)
    213{
    214	struct intel_soc_dts_sensor_entry *dts;
    215
    216	dts = tzd->devdata;
    217
    218	*type = dts->trip_types[trip];
    219
    220	return 0;
    221}
    222
    223static int sys_get_curr_temp(struct thermal_zone_device *tzd,
    224			     int *temp)
    225{
    226	int status;
    227	u32 out;
    228	struct intel_soc_dts_sensor_entry *dts;
    229	struct intel_soc_dts_sensors *sensors;
    230	unsigned long raw;
    231
    232	dts = tzd->devdata;
    233	sensors = dts->sensors;
    234	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    235			       SOC_DTS_OFFSET_TEMP, &out);
    236	if (status)
    237		return status;
    238
    239	raw = out;
    240	out = bitmap_get_value8(&raw, dts->id * 8) - SOC_DTS_TJMAX_ENCODING;
    241	*temp = sensors->tj_max - out * 1000;
    242
    243	return 0;
    244}
    245
    246static struct thermal_zone_device_ops tzone_ops = {
    247	.get_temp = sys_get_curr_temp,
    248	.get_trip_temp = sys_get_trip_temp,
    249	.get_trip_type = sys_get_trip_type,
    250	.set_trip_temp = sys_set_trip_temp,
    251};
    252
    253static int soc_dts_enable(int id)
    254{
    255	u32 out;
    256	int ret;
    257
    258	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    259			    SOC_DTS_OFFSET_ENABLE, &out);
    260	if (ret)
    261		return ret;
    262
    263	if (!(out & BIT(id))) {
    264		out |= BIT(id);
    265		ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    266				     SOC_DTS_OFFSET_ENABLE, out);
    267		if (ret)
    268			return ret;
    269	}
    270
    271	return ret;
    272}
    273
    274static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
    275{
    276	if (dts) {
    277		iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    278			       SOC_DTS_OFFSET_ENABLE, dts->store_status);
    279		thermal_zone_device_unregister(dts->tzone);
    280	}
    281}
    282
    283static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
    284				bool notification_support, int trip_cnt,
    285				int read_only_trip_cnt)
    286{
    287	char name[10];
    288	unsigned long trip;
    289	int trip_count = 0;
    290	int trip_mask = 0;
    291	int writable_trip_cnt = 0;
    292	unsigned long ptps;
    293	u32 store_ptps;
    294	unsigned long i;
    295	int ret;
    296
    297	/* Store status to restor on exit */
    298	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    299			    SOC_DTS_OFFSET_ENABLE, &dts->store_status);
    300	if (ret)
    301		goto err_ret;
    302
    303	dts->id = id;
    304	if (notification_support) {
    305		trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
    306		writable_trip_cnt = trip_count - read_only_trip_cnt;
    307		trip_mask = GENMASK(writable_trip_cnt - 1, 0);
    308	}
    309
    310	/* Check if the writable trip we provide is not used by BIOS */
    311	ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    312			    SOC_DTS_OFFSET_PTPS, &store_ptps);
    313	if (ret)
    314		trip_mask = 0;
    315	else {
    316		ptps = store_ptps;
    317		for_each_set_clump8(i, trip, &ptps, writable_trip_cnt * 8)
    318			trip_mask &= ~BIT(i / 8);
    319	}
    320	dts->trip_mask = trip_mask;
    321	dts->trip_count = trip_count;
    322	snprintf(name, sizeof(name), "soc_dts%d", id);
    323	dts->tzone = thermal_zone_device_register(name,
    324						  trip_count,
    325						  trip_mask,
    326						  dts, &tzone_ops,
    327						  NULL, 0, 0);
    328	if (IS_ERR(dts->tzone)) {
    329		ret = PTR_ERR(dts->tzone);
    330		goto err_ret;
    331	}
    332	ret = thermal_zone_device_enable(dts->tzone);
    333	if (ret)
    334		goto err_enable;
    335
    336	ret = soc_dts_enable(id);
    337	if (ret)
    338		goto err_enable;
    339
    340	return 0;
    341err_enable:
    342	thermal_zone_device_unregister(dts->tzone);
    343err_ret:
    344	return ret;
    345}
    346
    347int intel_soc_dts_iosf_add_read_only_critical_trip(
    348	struct intel_soc_dts_sensors *sensors, int critical_offset)
    349{
    350	int i, j;
    351
    352	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
    353		struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i];
    354		int temp = sensors->tj_max - critical_offset;
    355		unsigned long count = entry->trip_count;
    356		unsigned long mask = entry->trip_mask;
    357
    358		j = find_first_zero_bit(&mask, count);
    359		if (j < count)
    360			return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL);
    361	}
    362
    363	return -EINVAL;
    364}
    365EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip);
    366
    367void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
    368{
    369	u32 sticky_out;
    370	int status;
    371	u32 ptmc_out;
    372	unsigned long flags;
    373
    374	spin_lock_irqsave(&sensors->intr_notify_lock, flags);
    375
    376	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    377			       SOC_DTS_OFFSET_PTMC, &ptmc_out);
    378	ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT;
    379	status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    380				SOC_DTS_OFFSET_PTMC, ptmc_out);
    381
    382	status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
    383			       SOC_DTS_OFFSET_PTTSS, &sticky_out);
    384	pr_debug("status %d PTTSS %x\n", status, sticky_out);
    385	if (sticky_out & SOC_DTS_TRIP_MASK) {
    386		int i;
    387		/* reset sticky bit */
    388		status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
    389					SOC_DTS_OFFSET_PTTSS, sticky_out);
    390		spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
    391
    392		for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
    393			pr_debug("TZD update for zone %d\n", i);
    394			thermal_zone_device_update(sensors->soc_dts[i].tzone,
    395						   THERMAL_EVENT_UNSPECIFIED);
    396		}
    397	} else
    398		spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
    399}
    400EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
    401
    402struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
    403	enum intel_soc_dts_interrupt_type intr_type, int trip_count,
    404	int read_only_trip_count)
    405{
    406	struct intel_soc_dts_sensors *sensors;
    407	bool notification;
    408	u32 tj_max;
    409	int ret;
    410	int i;
    411
    412	if (!iosf_mbi_available())
    413		return ERR_PTR(-ENODEV);
    414
    415	if (!trip_count || read_only_trip_count > trip_count)
    416		return ERR_PTR(-EINVAL);
    417
    418	if (get_tj_max(&tj_max))
    419		return ERR_PTR(-EINVAL);
    420
    421	sensors = kzalloc(sizeof(*sensors), GFP_KERNEL);
    422	if (!sensors)
    423		return ERR_PTR(-ENOMEM);
    424
    425	spin_lock_init(&sensors->intr_notify_lock);
    426	mutex_init(&sensors->dts_update_lock);
    427	sensors->intr_type = intr_type;
    428	sensors->tj_max = tj_max;
    429	if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE)
    430		notification = false;
    431	else
    432		notification = true;
    433	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
    434		sensors->soc_dts[i].sensors = sensors;
    435		ret = add_dts_thermal_zone(i, &sensors->soc_dts[i],
    436					   notification, trip_count,
    437					   read_only_trip_count);
    438		if (ret)
    439			goto err_free;
    440	}
    441
    442	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
    443		ret = update_trip_temp(&sensors->soc_dts[i], 0, 0,
    444				       THERMAL_TRIP_PASSIVE);
    445		if (ret)
    446			goto err_remove_zone;
    447
    448		ret = update_trip_temp(&sensors->soc_dts[i], 1, 0,
    449				       THERMAL_TRIP_PASSIVE);
    450		if (ret)
    451			goto err_remove_zone;
    452	}
    453
    454	return sensors;
    455err_remove_zone:
    456	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
    457		remove_dts_thermal_zone(&sensors->soc_dts[i]);
    458
    459err_free:
    460	kfree(sensors);
    461	return ERR_PTR(ret);
    462}
    463EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init);
    464
    465void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)
    466{
    467	int i;
    468
    469	for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
    470		update_trip_temp(&sensors->soc_dts[i], 0, 0, 0);
    471		update_trip_temp(&sensors->soc_dts[i], 1, 0, 0);
    472		remove_dts_thermal_zone(&sensors->soc_dts[i]);
    473	}
    474	kfree(sensors);
    475}
    476EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);
    477
    478MODULE_LICENSE("GPL v2");