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

cbe_thermal.c (9886B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * thermal support for the cell processor
      4 *
      5 * This module adds some sysfs attributes to cpu and spu nodes.
      6 * Base for measurements are the digital thermal sensors (DTS)
      7 * located on the chip.
      8 * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
      9 * The attributes can be found under
     10 * /sys/devices/system/cpu/cpuX/thermal
     11 * /sys/devices/system/spu/spuX/thermal
     12 *
     13 * The following attributes are added for each node:
     14 * temperature:
     15 *	contains the current temperature measured by the DTS
     16 * throttle_begin:
     17 *	throttling begins when temperature is greater or equal to
     18 *	throttle_begin. Setting this value to 125 prevents throttling.
     19 * throttle_end:
     20 *	throttling is being ceased, if the temperature is lower than
     21 *	throttle_end. Due to a delay between applying throttling and
     22 *	a reduced temperature this value should be less than throttle_begin.
     23 *	A value equal to throttle_begin provides only a very little hysteresis.
     24 * throttle_full_stop:
     25 *	If the temperatrue is greater or equal to throttle_full_stop,
     26 *	full throttling is applied to the cpu or spu. This value should be
     27 *	greater than throttle_begin and throttle_end. Setting this value to
     28 *	65 prevents the unit from running code at all.
     29 *
     30 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
     31 *
     32 * Author: Christian Krafft <krafft@de.ibm.com>
     33 */
     34
     35#include <linux/module.h>
     36#include <linux/device.h>
     37#include <linux/kernel.h>
     38#include <linux/cpu.h>
     39#include <linux/stringify.h>
     40#include <asm/spu.h>
     41#include <asm/io.h>
     42#include <asm/cell-regs.h>
     43
     44#include "spu_priv1_mmio.h"
     45
     46#define TEMP_MIN 65
     47#define TEMP_MAX 125
     48
     49#define DEVICE_PREFIX_ATTR(_prefix,_name,_mode)			\
     50struct device_attribute attr_ ## _prefix ## _ ## _name = {	\
     51	.attr = { .name = __stringify(_name), .mode = _mode },	\
     52	.show	= _prefix ## _show_ ## _name,			\
     53	.store	= _prefix ## _store_ ## _name,			\
     54};
     55
     56static inline u8 reg_to_temp(u8 reg_value)
     57{
     58	return ((reg_value & 0x3f) << 1) + TEMP_MIN;
     59}
     60
     61static inline u8 temp_to_reg(u8 temp)
     62{
     63	return ((temp - TEMP_MIN) >> 1) & 0x3f;
     64}
     65
     66static struct cbe_pmd_regs __iomem *get_pmd_regs(struct device *dev)
     67{
     68	struct spu *spu;
     69
     70	spu = container_of(dev, struct spu, dev);
     71
     72	return cbe_get_pmd_regs(spu_devnode(spu));
     73}
     74
     75/* returns the value for a given spu in a given register */
     76static u8 spu_read_register_value(struct device *dev, union spe_reg __iomem *reg)
     77{
     78	union spe_reg value;
     79	struct spu *spu;
     80
     81	spu = container_of(dev, struct spu, dev);
     82	value.val = in_be64(&reg->val);
     83
     84	return value.spe[spu->spe_id];
     85}
     86
     87static ssize_t spu_show_temp(struct device *dev, struct device_attribute *attr,
     88			char *buf)
     89{
     90	u8 value;
     91	struct cbe_pmd_regs __iomem *pmd_regs;
     92
     93	pmd_regs = get_pmd_regs(dev);
     94
     95	value = spu_read_register_value(dev, &pmd_regs->ts_ctsr1);
     96
     97	return sprintf(buf, "%d\n", reg_to_temp(value));
     98}
     99
    100static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
    101{
    102	u64 value;
    103
    104	value = in_be64(&pmd_regs->tm_tpr.val);
    105	/* access the corresponding byte */
    106	value >>= pos;
    107	value &= 0x3F;
    108
    109	return sprintf(buf, "%d\n", reg_to_temp(value));
    110}
    111
    112static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
    113{
    114	u64 reg_value;
    115	unsigned int temp;
    116	u64 new_value;
    117	int ret;
    118
    119	ret = sscanf(buf, "%u", &temp);
    120
    121	if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
    122		return -EINVAL;
    123
    124	new_value = temp_to_reg(temp);
    125
    126	reg_value = in_be64(&pmd_regs->tm_tpr.val);
    127
    128	/* zero out bits for new value */
    129	reg_value &= ~(0xffull << pos);
    130	/* set bits to new value */
    131	reg_value |= new_value << pos;
    132
    133	out_be64(&pmd_regs->tm_tpr.val, reg_value);
    134	return size;
    135}
    136
    137static ssize_t spu_show_throttle_end(struct device *dev,
    138			struct device_attribute *attr, char *buf)
    139{
    140	return show_throttle(get_pmd_regs(dev), buf, 0);
    141}
    142
    143static ssize_t spu_show_throttle_begin(struct device *dev,
    144			struct device_attribute *attr, char *buf)
    145{
    146	return show_throttle(get_pmd_regs(dev), buf, 8);
    147}
    148
    149static ssize_t spu_show_throttle_full_stop(struct device *dev,
    150			struct device_attribute *attr, char *buf)
    151{
    152	return show_throttle(get_pmd_regs(dev), buf, 16);
    153}
    154
    155static ssize_t spu_store_throttle_end(struct device *dev,
    156			struct device_attribute *attr, const char *buf, size_t size)
    157{
    158	return store_throttle(get_pmd_regs(dev), buf, size, 0);
    159}
    160
    161static ssize_t spu_store_throttle_begin(struct device *dev,
    162			struct device_attribute *attr, const char *buf, size_t size)
    163{
    164	return store_throttle(get_pmd_regs(dev), buf, size, 8);
    165}
    166
    167static ssize_t spu_store_throttle_full_stop(struct device *dev,
    168			struct device_attribute *attr, const char *buf, size_t size)
    169{
    170	return store_throttle(get_pmd_regs(dev), buf, size, 16);
    171}
    172
    173static ssize_t ppe_show_temp(struct device *dev, char *buf, int pos)
    174{
    175	struct cbe_pmd_regs __iomem *pmd_regs;
    176	u64 value;
    177
    178	pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
    179	value = in_be64(&pmd_regs->ts_ctsr2);
    180
    181	value = (value >> pos) & 0x3f;
    182
    183	return sprintf(buf, "%d\n", reg_to_temp(value));
    184}
    185
    186
    187/* shows the temperature of the DTS on the PPE,
    188 * located near the linear thermal sensor */
    189static ssize_t ppe_show_temp0(struct device *dev,
    190			struct device_attribute *attr, char *buf)
    191{
    192	return ppe_show_temp(dev, buf, 32);
    193}
    194
    195/* shows the temperature of the second DTS on the PPE */
    196static ssize_t ppe_show_temp1(struct device *dev,
    197			struct device_attribute *attr, char *buf)
    198{
    199	return ppe_show_temp(dev, buf, 0);
    200}
    201
    202static ssize_t ppe_show_throttle_end(struct device *dev,
    203			struct device_attribute *attr, char *buf)
    204{
    205	return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 32);
    206}
    207
    208static ssize_t ppe_show_throttle_begin(struct device *dev,
    209			struct device_attribute *attr, char *buf)
    210{
    211	return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 40);
    212}
    213
    214static ssize_t ppe_show_throttle_full_stop(struct device *dev,
    215			struct device_attribute *attr, char *buf)
    216{
    217	return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 48);
    218}
    219
    220static ssize_t ppe_store_throttle_end(struct device *dev,
    221			struct device_attribute *attr, const char *buf, size_t size)
    222{
    223	return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 32);
    224}
    225
    226static ssize_t ppe_store_throttle_begin(struct device *dev,
    227			struct device_attribute *attr, const char *buf, size_t size)
    228{
    229	return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 40);
    230}
    231
    232static ssize_t ppe_store_throttle_full_stop(struct device *dev,
    233			struct device_attribute *attr, const char *buf, size_t size)
    234{
    235	return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 48);
    236}
    237
    238
    239static struct device_attribute attr_spu_temperature = {
    240	.attr = {.name = "temperature", .mode = 0400 },
    241	.show = spu_show_temp,
    242};
    243
    244static DEVICE_PREFIX_ATTR(spu, throttle_end, 0600);
    245static DEVICE_PREFIX_ATTR(spu, throttle_begin, 0600);
    246static DEVICE_PREFIX_ATTR(spu, throttle_full_stop, 0600);
    247
    248
    249static struct attribute *spu_attributes[] = {
    250	&attr_spu_temperature.attr,
    251	&attr_spu_throttle_end.attr,
    252	&attr_spu_throttle_begin.attr,
    253	&attr_spu_throttle_full_stop.attr,
    254	NULL,
    255};
    256
    257static const struct attribute_group spu_attribute_group = {
    258	.name	= "thermal",
    259	.attrs	= spu_attributes,
    260};
    261
    262static struct device_attribute attr_ppe_temperature0 = {
    263	.attr = {.name = "temperature0", .mode = 0400 },
    264	.show = ppe_show_temp0,
    265};
    266
    267static struct device_attribute attr_ppe_temperature1 = {
    268	.attr = {.name = "temperature1", .mode = 0400 },
    269	.show = ppe_show_temp1,
    270};
    271
    272static DEVICE_PREFIX_ATTR(ppe, throttle_end, 0600);
    273static DEVICE_PREFIX_ATTR(ppe, throttle_begin, 0600);
    274static DEVICE_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
    275
    276static struct attribute *ppe_attributes[] = {
    277	&attr_ppe_temperature0.attr,
    278	&attr_ppe_temperature1.attr,
    279	&attr_ppe_throttle_end.attr,
    280	&attr_ppe_throttle_begin.attr,
    281	&attr_ppe_throttle_full_stop.attr,
    282	NULL,
    283};
    284
    285static struct attribute_group ppe_attribute_group = {
    286	.name	= "thermal",
    287	.attrs	= ppe_attributes,
    288};
    289
    290/*
    291 * initialize throttling with default values
    292 */
    293static int __init init_default_values(void)
    294{
    295	int cpu;
    296	struct cbe_pmd_regs __iomem *pmd_regs;
    297	struct device *dev;
    298	union ppe_spe_reg tpr;
    299	union spe_reg str1;
    300	u64 str2;
    301	union spe_reg cr1;
    302	u64 cr2;
    303
    304	/* TPR defaults */
    305	/* ppe
    306	 *	1F - no full stop
    307	 *	08 - dynamic throttling starts if over 80 degrees
    308	 *	03 - dynamic throttling ceases if below 70 degrees */
    309	tpr.ppe = 0x1F0803;
    310	/* spe
    311	 *	10 - full stopped when over 96 degrees
    312	 *	08 - dynamic throttling starts if over 80 degrees
    313	 *	03 - dynamic throttling ceases if below 70 degrees
    314	 */
    315	tpr.spe = 0x100803;
    316
    317	/* STR defaults */
    318	/* str1
    319	 *	10 - stop 16 of 32 cycles
    320	 */
    321	str1.val = 0x1010101010101010ull;
    322	/* str2
    323	 *	10 - stop 16 of 32 cycles
    324	 */
    325	str2 = 0x10;
    326
    327	/* CR defaults */
    328	/* cr1
    329	 *	4 - normal operation
    330	 */
    331	cr1.val = 0x0404040404040404ull;
    332	/* cr2
    333	 *	4 - normal operation
    334	 */
    335	cr2 = 0x04;
    336
    337	for_each_possible_cpu (cpu) {
    338		pr_debug("processing cpu %d\n", cpu);
    339		dev = get_cpu_device(cpu);
    340
    341		if (!dev) {
    342			pr_info("invalid dev pointer for cbe_thermal\n");
    343			return -EINVAL;
    344		}
    345
    346		pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
    347
    348		if (!pmd_regs) {
    349			pr_info("invalid CBE regs pointer for cbe_thermal\n");
    350			return -EINVAL;
    351		}
    352
    353		out_be64(&pmd_regs->tm_str2, str2);
    354		out_be64(&pmd_regs->tm_str1.val, str1.val);
    355		out_be64(&pmd_regs->tm_tpr.val, tpr.val);
    356		out_be64(&pmd_regs->tm_cr1.val, cr1.val);
    357		out_be64(&pmd_regs->tm_cr2, cr2);
    358	}
    359
    360	return 0;
    361}
    362
    363
    364static int __init thermal_init(void)
    365{
    366	int rc = init_default_values();
    367
    368	if (rc == 0) {
    369		spu_add_dev_attr_group(&spu_attribute_group);
    370		cpu_add_dev_attr_group(&ppe_attribute_group);
    371	}
    372
    373	return rc;
    374}
    375module_init(thermal_init);
    376
    377static void __exit thermal_exit(void)
    378{
    379	spu_remove_dev_attr_group(&spu_attribute_group);
    380	cpu_remove_dev_attr_group(&ppe_attribute_group);
    381}
    382module_exit(thermal_exit);
    383
    384MODULE_LICENSE("GPL");
    385MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
    386