Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * thermal support for the cell processor
0004  *
0005  * This module adds some sysfs attributes to cpu and spu nodes.
0006  * Base for measurements are the digital thermal sensors (DTS)
0007  * located on the chip.
0008  * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
0009  * The attributes can be found under
0010  * /sys/devices/system/cpu/cpuX/thermal
0011  * /sys/devices/system/spu/spuX/thermal
0012  *
0013  * The following attributes are added for each node:
0014  * temperature:
0015  *  contains the current temperature measured by the DTS
0016  * throttle_begin:
0017  *  throttling begins when temperature is greater or equal to
0018  *  throttle_begin. Setting this value to 125 prevents throttling.
0019  * throttle_end:
0020  *  throttling is being ceased, if the temperature is lower than
0021  *  throttle_end. Due to a delay between applying throttling and
0022  *  a reduced temperature this value should be less than throttle_begin.
0023  *  A value equal to throttle_begin provides only a very little hysteresis.
0024  * throttle_full_stop:
0025  *  If the temperatrue is greater or equal to throttle_full_stop,
0026  *  full throttling is applied to the cpu or spu. This value should be
0027  *  greater than throttle_begin and throttle_end. Setting this value to
0028  *  65 prevents the unit from running code at all.
0029  *
0030  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
0031  *
0032  * Author: Christian Krafft <krafft@de.ibm.com>
0033  */
0034 
0035 #include <linux/module.h>
0036 #include <linux/device.h>
0037 #include <linux/kernel.h>
0038 #include <linux/cpu.h>
0039 #include <linux/stringify.h>
0040 #include <asm/spu.h>
0041 #include <asm/io.h>
0042 #include <asm/cell-regs.h>
0043 
0044 #include "spu_priv1_mmio.h"
0045 
0046 #define TEMP_MIN 65
0047 #define TEMP_MAX 125
0048 
0049 #define DEVICE_PREFIX_ATTR(_prefix,_name,_mode)         \
0050 struct device_attribute attr_ ## _prefix ## _ ## _name = {  \
0051     .attr = { .name = __stringify(_name), .mode = _mode },  \
0052     .show   = _prefix ## _show_ ## _name,           \
0053     .store  = _prefix ## _store_ ## _name,          \
0054 };
0055 
0056 static inline u8 reg_to_temp(u8 reg_value)
0057 {
0058     return ((reg_value & 0x3f) << 1) + TEMP_MIN;
0059 }
0060 
0061 static inline u8 temp_to_reg(u8 temp)
0062 {
0063     return ((temp - TEMP_MIN) >> 1) & 0x3f;
0064 }
0065 
0066 static struct cbe_pmd_regs __iomem *get_pmd_regs(struct device *dev)
0067 {
0068     struct spu *spu;
0069 
0070     spu = container_of(dev, struct spu, dev);
0071 
0072     return cbe_get_pmd_regs(spu_devnode(spu));
0073 }
0074 
0075 /* returns the value for a given spu in a given register */
0076 static u8 spu_read_register_value(struct device *dev, union spe_reg __iomem *reg)
0077 {
0078     union spe_reg value;
0079     struct spu *spu;
0080 
0081     spu = container_of(dev, struct spu, dev);
0082     value.val = in_be64(&reg->val);
0083 
0084     return value.spe[spu->spe_id];
0085 }
0086 
0087 static ssize_t spu_show_temp(struct device *dev, struct device_attribute *attr,
0088             char *buf)
0089 {
0090     u8 value;
0091     struct cbe_pmd_regs __iomem *pmd_regs;
0092 
0093     pmd_regs = get_pmd_regs(dev);
0094 
0095     value = spu_read_register_value(dev, &pmd_regs->ts_ctsr1);
0096 
0097     return sprintf(buf, "%d\n", reg_to_temp(value));
0098 }
0099 
0100 static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
0101 {
0102     u64 value;
0103 
0104     value = in_be64(&pmd_regs->tm_tpr.val);
0105     /* access the corresponding byte */
0106     value >>= pos;
0107     value &= 0x3F;
0108 
0109     return sprintf(buf, "%d\n", reg_to_temp(value));
0110 }
0111 
0112 static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
0113 {
0114     u64 reg_value;
0115     unsigned int temp;
0116     u64 new_value;
0117     int ret;
0118 
0119     ret = sscanf(buf, "%u", &temp);
0120 
0121     if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
0122         return -EINVAL;
0123 
0124     new_value = temp_to_reg(temp);
0125 
0126     reg_value = in_be64(&pmd_regs->tm_tpr.val);
0127 
0128     /* zero out bits for new value */
0129     reg_value &= ~(0xffull << pos);
0130     /* set bits to new value */
0131     reg_value |= new_value << pos;
0132 
0133     out_be64(&pmd_regs->tm_tpr.val, reg_value);
0134     return size;
0135 }
0136 
0137 static ssize_t spu_show_throttle_end(struct device *dev,
0138             struct device_attribute *attr, char *buf)
0139 {
0140     return show_throttle(get_pmd_regs(dev), buf, 0);
0141 }
0142 
0143 static ssize_t spu_show_throttle_begin(struct device *dev,
0144             struct device_attribute *attr, char *buf)
0145 {
0146     return show_throttle(get_pmd_regs(dev), buf, 8);
0147 }
0148 
0149 static ssize_t spu_show_throttle_full_stop(struct device *dev,
0150             struct device_attribute *attr, char *buf)
0151 {
0152     return show_throttle(get_pmd_regs(dev), buf, 16);
0153 }
0154 
0155 static ssize_t spu_store_throttle_end(struct device *dev,
0156             struct device_attribute *attr, const char *buf, size_t size)
0157 {
0158     return store_throttle(get_pmd_regs(dev), buf, size, 0);
0159 }
0160 
0161 static ssize_t spu_store_throttle_begin(struct device *dev,
0162             struct device_attribute *attr, const char *buf, size_t size)
0163 {
0164     return store_throttle(get_pmd_regs(dev), buf, size, 8);
0165 }
0166 
0167 static ssize_t spu_store_throttle_full_stop(struct device *dev,
0168             struct device_attribute *attr, const char *buf, size_t size)
0169 {
0170     return store_throttle(get_pmd_regs(dev), buf, size, 16);
0171 }
0172 
0173 static ssize_t ppe_show_temp(struct device *dev, char *buf, int pos)
0174 {
0175     struct cbe_pmd_regs __iomem *pmd_regs;
0176     u64 value;
0177 
0178     pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
0179     value = in_be64(&pmd_regs->ts_ctsr2);
0180 
0181     value = (value >> pos) & 0x3f;
0182 
0183     return sprintf(buf, "%d\n", reg_to_temp(value));
0184 }
0185 
0186 
0187 /* shows the temperature of the DTS on the PPE,
0188  * located near the linear thermal sensor */
0189 static ssize_t ppe_show_temp0(struct device *dev,
0190             struct device_attribute *attr, char *buf)
0191 {
0192     return ppe_show_temp(dev, buf, 32);
0193 }
0194 
0195 /* shows the temperature of the second DTS on the PPE */
0196 static ssize_t ppe_show_temp1(struct device *dev,
0197             struct device_attribute *attr, char *buf)
0198 {
0199     return ppe_show_temp(dev, buf, 0);
0200 }
0201 
0202 static ssize_t ppe_show_throttle_end(struct device *dev,
0203             struct device_attribute *attr, char *buf)
0204 {
0205     return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 32);
0206 }
0207 
0208 static ssize_t ppe_show_throttle_begin(struct device *dev,
0209             struct device_attribute *attr, char *buf)
0210 {
0211     return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 40);
0212 }
0213 
0214 static ssize_t ppe_show_throttle_full_stop(struct device *dev,
0215             struct device_attribute *attr, char *buf)
0216 {
0217     return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 48);
0218 }
0219 
0220 static ssize_t ppe_store_throttle_end(struct device *dev,
0221             struct device_attribute *attr, const char *buf, size_t size)
0222 {
0223     return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 32);
0224 }
0225 
0226 static ssize_t ppe_store_throttle_begin(struct device *dev,
0227             struct device_attribute *attr, const char *buf, size_t size)
0228 {
0229     return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 40);
0230 }
0231 
0232 static ssize_t ppe_store_throttle_full_stop(struct device *dev,
0233             struct device_attribute *attr, const char *buf, size_t size)
0234 {
0235     return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 48);
0236 }
0237 
0238 
0239 static struct device_attribute attr_spu_temperature = {
0240     .attr = {.name = "temperature", .mode = 0400 },
0241     .show = spu_show_temp,
0242 };
0243 
0244 static DEVICE_PREFIX_ATTR(spu, throttle_end, 0600);
0245 static DEVICE_PREFIX_ATTR(spu, throttle_begin, 0600);
0246 static DEVICE_PREFIX_ATTR(spu, throttle_full_stop, 0600);
0247 
0248 
0249 static struct attribute *spu_attributes[] = {
0250     &attr_spu_temperature.attr,
0251     &attr_spu_throttle_end.attr,
0252     &attr_spu_throttle_begin.attr,
0253     &attr_spu_throttle_full_stop.attr,
0254     NULL,
0255 };
0256 
0257 static const struct attribute_group spu_attribute_group = {
0258     .name   = "thermal",
0259     .attrs  = spu_attributes,
0260 };
0261 
0262 static struct device_attribute attr_ppe_temperature0 = {
0263     .attr = {.name = "temperature0", .mode = 0400 },
0264     .show = ppe_show_temp0,
0265 };
0266 
0267 static struct device_attribute attr_ppe_temperature1 = {
0268     .attr = {.name = "temperature1", .mode = 0400 },
0269     .show = ppe_show_temp1,
0270 };
0271 
0272 static DEVICE_PREFIX_ATTR(ppe, throttle_end, 0600);
0273 static DEVICE_PREFIX_ATTR(ppe, throttle_begin, 0600);
0274 static DEVICE_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
0275 
0276 static struct attribute *ppe_attributes[] = {
0277     &attr_ppe_temperature0.attr,
0278     &attr_ppe_temperature1.attr,
0279     &attr_ppe_throttle_end.attr,
0280     &attr_ppe_throttle_begin.attr,
0281     &attr_ppe_throttle_full_stop.attr,
0282     NULL,
0283 };
0284 
0285 static struct attribute_group ppe_attribute_group = {
0286     .name   = "thermal",
0287     .attrs  = ppe_attributes,
0288 };
0289 
0290 /*
0291  * initialize throttling with default values
0292  */
0293 static int __init init_default_values(void)
0294 {
0295     int cpu;
0296     struct cbe_pmd_regs __iomem *pmd_regs;
0297     struct device *dev;
0298     union ppe_spe_reg tpr;
0299     union spe_reg str1;
0300     u64 str2;
0301     union spe_reg cr1;
0302     u64 cr2;
0303 
0304     /* TPR defaults */
0305     /* ppe
0306      *  1F - no full stop
0307      *  08 - dynamic throttling starts if over 80 degrees
0308      *  03 - dynamic throttling ceases if below 70 degrees */
0309     tpr.ppe = 0x1F0803;
0310     /* spe
0311      *  10 - full stopped when over 96 degrees
0312      *  08 - dynamic throttling starts if over 80 degrees
0313      *  03 - dynamic throttling ceases if below 70 degrees
0314      */
0315     tpr.spe = 0x100803;
0316 
0317     /* STR defaults */
0318     /* str1
0319      *  10 - stop 16 of 32 cycles
0320      */
0321     str1.val = 0x1010101010101010ull;
0322     /* str2
0323      *  10 - stop 16 of 32 cycles
0324      */
0325     str2 = 0x10;
0326 
0327     /* CR defaults */
0328     /* cr1
0329      *  4 - normal operation
0330      */
0331     cr1.val = 0x0404040404040404ull;
0332     /* cr2
0333      *  4 - normal operation
0334      */
0335     cr2 = 0x04;
0336 
0337     for_each_possible_cpu (cpu) {
0338         pr_debug("processing cpu %d\n", cpu);
0339         dev = get_cpu_device(cpu);
0340 
0341         if (!dev) {
0342             pr_info("invalid dev pointer for cbe_thermal\n");
0343             return -EINVAL;
0344         }
0345 
0346         pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
0347 
0348         if (!pmd_regs) {
0349             pr_info("invalid CBE regs pointer for cbe_thermal\n");
0350             return -EINVAL;
0351         }
0352 
0353         out_be64(&pmd_regs->tm_str2, str2);
0354         out_be64(&pmd_regs->tm_str1.val, str1.val);
0355         out_be64(&pmd_regs->tm_tpr.val, tpr.val);
0356         out_be64(&pmd_regs->tm_cr1.val, cr1.val);
0357         out_be64(&pmd_regs->tm_cr2, cr2);
0358     }
0359 
0360     return 0;
0361 }
0362 
0363 
0364 static int __init thermal_init(void)
0365 {
0366     int rc = init_default_values();
0367 
0368     if (rc == 0) {
0369         spu_add_dev_attr_group(&spu_attribute_group);
0370         cpu_add_dev_attr_group(&ppe_attribute_group);
0371     }
0372 
0373     return rc;
0374 }
0375 module_init(thermal_init);
0376 
0377 static void __exit thermal_exit(void)
0378 {
0379     spu_remove_dev_attr_group(&spu_attribute_group);
0380     cpu_remove_dev_attr_group(&ppe_attribute_group);
0381 }
0382 module_exit(thermal_exit);
0383 
0384 MODULE_LICENSE("GPL");
0385 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
0386