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