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_quark_dts_thermal.c (11818B)


      1/*
      2 * intel_quark_dts_thermal.c
      3 *
      4 * This file is provided under a dual BSD/GPLv2 license.  When using or
      5 * redistributing this file, you may do so under either license.
      6 *
      7 * GPL LICENSE SUMMARY
      8 *
      9 * Copyright(c) 2015 Intel Corporation.
     10 *
     11 * This program is free software; you can redistribute it and/or modify
     12 * it under the terms of version 2 of the GNU General Public License as
     13 * published by the Free Software Foundation.
     14 *
     15 * This program is distributed in the hope that it will be useful, but
     16 *  WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18 * General Public License for more details.
     19 *
     20 * Contact Information:
     21 *  Ong Boon Leong <boon.leong.ong@intel.com>
     22 *  Intel Malaysia, Penang
     23 *
     24 * BSD LICENSE
     25 *
     26 * Copyright(c) 2015 Intel Corporation.
     27 *
     28 * Redistribution and use in source and binary forms, with or without
     29 * modification, are permitted provided that the following conditions
     30 * are met:
     31 *
     32 *   * Redistributions of source code must retain the above copyright
     33 *     notice, this list of conditions and the following disclaimer.
     34 *   * Redistributions in binary form must reproduce the above copyright
     35 *     notice, this list of conditions and the following disclaimer in
     36 *     the documentation and/or other materials provided with the
     37 *     distribution.
     38 *   * Neither the name of Intel Corporation nor the names of its
     39 *     contributors may be used to endorse or promote products derived
     40 *     from this software without specific prior written permission.
     41 *
     42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     53 *
     54 * Quark DTS thermal driver is implemented by referencing
     55 * intel_soc_dts_thermal.c.
     56 */
     57
     58#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     59
     60#include <linux/module.h>
     61#include <linux/slab.h>
     62#include <linux/interrupt.h>
     63#include <linux/thermal.h>
     64#include <asm/cpu_device_id.h>
     65#include <asm/iosf_mbi.h>
     66
     67/* DTS reset is programmed via QRK_MBI_UNIT_SOC */
     68#define QRK_DTS_REG_OFFSET_RESET	0x34
     69#define QRK_DTS_RESET_BIT		BIT(0)
     70
     71/* DTS enable is programmed via QRK_MBI_UNIT_RMU */
     72#define QRK_DTS_REG_OFFSET_ENABLE	0xB0
     73#define QRK_DTS_ENABLE_BIT		BIT(15)
     74
     75/* Temperature Register is read via QRK_MBI_UNIT_RMU */
     76#define QRK_DTS_REG_OFFSET_TEMP		0xB1
     77#define QRK_DTS_MASK_TEMP		0xFF
     78#define QRK_DTS_OFFSET_TEMP		0
     79#define QRK_DTS_OFFSET_REL_TEMP		16
     80#define QRK_DTS_TEMP_BASE		50
     81
     82/* Programmable Trip Point Register is configured via QRK_MBI_UNIT_RMU */
     83#define QRK_DTS_REG_OFFSET_PTPS		0xB2
     84#define QRK_DTS_MASK_TP_THRES		0xFF
     85#define QRK_DTS_SHIFT_TP		8
     86#define QRK_DTS_ID_TP_CRITICAL		0
     87#define QRK_DTS_SAFE_TP_THRES		105
     88
     89/* Thermal Sensor Register Lock */
     90#define QRK_DTS_REG_OFFSET_LOCK		0x71
     91#define QRK_DTS_LOCK_BIT		BIT(5)
     92
     93/* Quark DTS has 2 trip points: hot & catastrophic */
     94#define QRK_MAX_DTS_TRIPS	2
     95/* If DTS not locked, all trip points are configurable */
     96#define QRK_DTS_WR_MASK_SET	0x3
     97/* If DTS locked, all trip points are not configurable */
     98#define QRK_DTS_WR_MASK_CLR	0
     99
    100#define DEFAULT_POLL_DELAY	2000
    101
    102struct soc_sensor_entry {
    103	bool locked;
    104	u32 store_ptps;
    105	u32 store_dts_enable;
    106	struct thermal_zone_device *tzone;
    107};
    108
    109static struct soc_sensor_entry *soc_dts;
    110
    111static int polling_delay = DEFAULT_POLL_DELAY;
    112module_param(polling_delay, int, 0644);
    113MODULE_PARM_DESC(polling_delay,
    114	"Polling interval for checking trip points (in milliseconds)");
    115
    116static DEFINE_MUTEX(dts_update_mutex);
    117
    118static int soc_dts_enable(struct thermal_zone_device *tzd)
    119{
    120	u32 out;
    121	struct soc_sensor_entry *aux_entry = tzd->devdata;
    122	int ret;
    123
    124	ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    125			    QRK_DTS_REG_OFFSET_ENABLE, &out);
    126	if (ret)
    127		return ret;
    128
    129	if (out & QRK_DTS_ENABLE_BIT)
    130		return 0;
    131
    132	if (!aux_entry->locked) {
    133		out |= QRK_DTS_ENABLE_BIT;
    134		ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
    135				     QRK_DTS_REG_OFFSET_ENABLE, out);
    136		if (ret)
    137			return ret;
    138	} else {
    139		pr_info("DTS is locked. Cannot enable DTS\n");
    140		ret = -EPERM;
    141	}
    142
    143	return ret;
    144}
    145
    146static int soc_dts_disable(struct thermal_zone_device *tzd)
    147{
    148	u32 out;
    149	struct soc_sensor_entry *aux_entry = tzd->devdata;
    150	int ret;
    151
    152	ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    153			    QRK_DTS_REG_OFFSET_ENABLE, &out);
    154	if (ret)
    155		return ret;
    156
    157	if (!(out & QRK_DTS_ENABLE_BIT))
    158		return 0;
    159
    160	if (!aux_entry->locked) {
    161		out &= ~QRK_DTS_ENABLE_BIT;
    162		ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
    163				     QRK_DTS_REG_OFFSET_ENABLE, out);
    164
    165		if (ret)
    166			return ret;
    167	} else {
    168		pr_info("DTS is locked. Cannot disable DTS\n");
    169		ret = -EPERM;
    170	}
    171
    172	return ret;
    173}
    174
    175static int _get_trip_temp(int trip, int *temp)
    176{
    177	int status;
    178	u32 out;
    179
    180	mutex_lock(&dts_update_mutex);
    181	status = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    182			       QRK_DTS_REG_OFFSET_PTPS, &out);
    183	mutex_unlock(&dts_update_mutex);
    184
    185	if (status)
    186		return status;
    187
    188	/*
    189	 * Thermal Sensor Programmable Trip Point Register has 8-bit
    190	 * fields for critical (catastrophic) and hot set trip point
    191	 * thresholds. The threshold value is always offset by its
    192	 * temperature base (50 degree Celsius).
    193	 */
    194	*temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES;
    195	*temp -= QRK_DTS_TEMP_BASE;
    196
    197	return 0;
    198}
    199
    200static inline int sys_get_trip_temp(struct thermal_zone_device *tzd,
    201				int trip, int *temp)
    202{
    203	return _get_trip_temp(trip, temp);
    204}
    205
    206static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp)
    207{
    208	return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp);
    209}
    210
    211static int update_trip_temp(struct soc_sensor_entry *aux_entry,
    212				int trip, int temp)
    213{
    214	u32 out;
    215	u32 temp_out;
    216	u32 store_ptps;
    217	int ret;
    218
    219	mutex_lock(&dts_update_mutex);
    220	if (aux_entry->locked) {
    221		ret = -EPERM;
    222		goto failed;
    223	}
    224
    225	ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    226			    QRK_DTS_REG_OFFSET_PTPS, &store_ptps);
    227	if (ret)
    228		goto failed;
    229
    230	/*
    231	 * Protection against unsafe trip point thresdhold value.
    232	 * As Quark X1000 data-sheet does not provide any recommendation
    233	 * regarding the safe trip point threshold value to use, we choose
    234	 * the safe value according to the threshold value set by UEFI BIOS.
    235	 */
    236	if (temp > QRK_DTS_SAFE_TP_THRES)
    237		temp = QRK_DTS_SAFE_TP_THRES;
    238
    239	/*
    240	 * Thermal Sensor Programmable Trip Point Register has 8-bit
    241	 * fields for critical (catastrophic) and hot set trip point
    242	 * thresholds. The threshold value is always offset by its
    243	 * temperature base (50 degree Celsius).
    244	 */
    245	temp_out = temp + QRK_DTS_TEMP_BASE;
    246	out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES <<
    247		(trip * QRK_DTS_SHIFT_TP)));
    248	out |= (temp_out & QRK_DTS_MASK_TP_THRES) <<
    249		(trip * QRK_DTS_SHIFT_TP);
    250
    251	ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
    252			     QRK_DTS_REG_OFFSET_PTPS, out);
    253
    254failed:
    255	mutex_unlock(&dts_update_mutex);
    256	return ret;
    257}
    258
    259static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
    260				int temp)
    261{
    262	return update_trip_temp(tzd->devdata, trip, temp);
    263}
    264
    265static int sys_get_trip_type(struct thermal_zone_device *thermal,
    266		int trip, enum thermal_trip_type *type)
    267{
    268	if (trip)
    269		*type = THERMAL_TRIP_HOT;
    270	else
    271		*type = THERMAL_TRIP_CRITICAL;
    272
    273	return 0;
    274}
    275
    276static int sys_get_curr_temp(struct thermal_zone_device *tzd,
    277				int *temp)
    278{
    279	u32 out;
    280	int ret;
    281
    282	mutex_lock(&dts_update_mutex);
    283	ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    284			    QRK_DTS_REG_OFFSET_TEMP, &out);
    285	mutex_unlock(&dts_update_mutex);
    286
    287	if (ret)
    288		return ret;
    289
    290	/*
    291	 * Thermal Sensor Temperature Register has 8-bit field
    292	 * for temperature value (offset by temperature base
    293	 * 50 degree Celsius).
    294	 */
    295	out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP;
    296	*temp = out - QRK_DTS_TEMP_BASE;
    297
    298	return 0;
    299}
    300
    301static int sys_change_mode(struct thermal_zone_device *tzd,
    302			   enum thermal_device_mode mode)
    303{
    304	int ret;
    305
    306	mutex_lock(&dts_update_mutex);
    307	if (mode == THERMAL_DEVICE_ENABLED)
    308		ret = soc_dts_enable(tzd);
    309	else
    310		ret = soc_dts_disable(tzd);
    311	mutex_unlock(&dts_update_mutex);
    312
    313	return ret;
    314}
    315
    316static struct thermal_zone_device_ops tzone_ops = {
    317	.get_temp = sys_get_curr_temp,
    318	.get_trip_temp = sys_get_trip_temp,
    319	.get_trip_type = sys_get_trip_type,
    320	.set_trip_temp = sys_set_trip_temp,
    321	.get_crit_temp = sys_get_crit_temp,
    322	.change_mode = sys_change_mode,
    323};
    324
    325static void free_soc_dts(struct soc_sensor_entry *aux_entry)
    326{
    327	if (aux_entry) {
    328		if (!aux_entry->locked) {
    329			mutex_lock(&dts_update_mutex);
    330			iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
    331				       QRK_DTS_REG_OFFSET_ENABLE,
    332				       aux_entry->store_dts_enable);
    333
    334			iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE,
    335				       QRK_DTS_REG_OFFSET_PTPS,
    336				       aux_entry->store_ptps);
    337			mutex_unlock(&dts_update_mutex);
    338		}
    339		thermal_zone_device_unregister(aux_entry->tzone);
    340		kfree(aux_entry);
    341	}
    342}
    343
    344static struct soc_sensor_entry *alloc_soc_dts(void)
    345{
    346	struct soc_sensor_entry *aux_entry;
    347	int err;
    348	u32 out;
    349	int wr_mask;
    350
    351	aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL);
    352	if (!aux_entry) {
    353		err = -ENOMEM;
    354		return ERR_PTR(-ENOMEM);
    355	}
    356
    357	/* Check if DTS register is locked */
    358	err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    359			    QRK_DTS_REG_OFFSET_LOCK, &out);
    360	if (err)
    361		goto err_ret;
    362
    363	if (out & QRK_DTS_LOCK_BIT) {
    364		aux_entry->locked = true;
    365		wr_mask = QRK_DTS_WR_MASK_CLR;
    366	} else {
    367		aux_entry->locked = false;
    368		wr_mask = QRK_DTS_WR_MASK_SET;
    369	}
    370
    371	/* Store DTS default state if DTS registers are not locked */
    372	if (!aux_entry->locked) {
    373		/* Store DTS default enable for restore on exit */
    374		err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    375				    QRK_DTS_REG_OFFSET_ENABLE,
    376				    &aux_entry->store_dts_enable);
    377		if (err)
    378			goto err_ret;
    379
    380		/* Store DTS default PTPS register for restore on exit */
    381		err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ,
    382				    QRK_DTS_REG_OFFSET_PTPS,
    383				    &aux_entry->store_ptps);
    384		if (err)
    385			goto err_ret;
    386	}
    387
    388	aux_entry->tzone = thermal_zone_device_register("quark_dts",
    389			QRK_MAX_DTS_TRIPS,
    390			wr_mask,
    391			aux_entry, &tzone_ops, NULL, 0, polling_delay);
    392	if (IS_ERR(aux_entry->tzone)) {
    393		err = PTR_ERR(aux_entry->tzone);
    394		goto err_ret;
    395	}
    396
    397	err = thermal_zone_device_enable(aux_entry->tzone);
    398	if (err)
    399		goto err_aux_status;
    400
    401	return aux_entry;
    402
    403err_aux_status:
    404	thermal_zone_device_unregister(aux_entry->tzone);
    405err_ret:
    406	kfree(aux_entry);
    407	return ERR_PTR(err);
    408}
    409
    410static const struct x86_cpu_id qrk_thermal_ids[] __initconst  = {
    411	X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
    412	{}
    413};
    414MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids);
    415
    416static int __init intel_quark_thermal_init(void)
    417{
    418	int err = 0;
    419
    420	if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available())
    421		return -ENODEV;
    422
    423	soc_dts = alloc_soc_dts();
    424	if (IS_ERR(soc_dts)) {
    425		err = PTR_ERR(soc_dts);
    426		goto err_free;
    427	}
    428
    429	return 0;
    430
    431err_free:
    432	free_soc_dts(soc_dts);
    433	return err;
    434}
    435
    436static void __exit intel_quark_thermal_exit(void)
    437{
    438	free_soc_dts(soc_dts);
    439}
    440
    441module_init(intel_quark_thermal_init)
    442module_exit(intel_quark_thermal_exit)
    443
    444MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver");
    445MODULE_AUTHOR("Ong Boon Leong <boon.leong.ong@intel.com>");
    446MODULE_LICENSE("Dual BSD/GPL");