Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] cell: add temperature to SPU and CPU sysfs entries

This patch adds a module that registers sysfs attributes to CPU and SPU
containing the temperature of the CBE.

They can be found under
/sys/devices/system/spu/cpuX/thermal/temperature[0|1]
/sys/devices/system/spu/spuX/thermal/temperature

The temperature is read from the on-chip temperature sensors.

Signed-off-by: Christian Krafft <krafft@de.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Christian Krafft and committed by
Paul Mackerras
b3d7dc19 0344c6c5

+233
+1
arch/powerpc/configs/cell_defconfig
··· 149 149 CONFIG_SPU_FS=m 150 150 CONFIG_SPU_BASE=y 151 151 CONFIG_CBE_RAS=y 152 + CONFIG_CBE_THERM=m 152 153 153 154 # 154 155 # Kernel options
+5
arch/powerpc/platforms/cell/Kconfig
··· 20 20 bool "RAS features for bare metal Cell BE" 21 21 default y 22 22 23 + config CBE_THERM 24 + tristate "CBE thermal support" 25 + default m 26 + depends on CBE_RAS 27 + 23 28 endmenu
+2
arch/powerpc/platforms/cell/Makefile
··· 3 3 pmu.o 4 4 obj-$(CONFIG_CBE_RAS) += ras.o 5 5 6 + obj-$(CONFIG_CBE_THERM) += cbe_thermal.o 7 + 6 8 ifeq ($(CONFIG_SMP),y) 7 9 obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o 8 10 endif
+225
arch/powerpc/platforms/cell/cbe_thermal.c
··· 1 + /* 2 + * thermal support for the cell processor 3 + * 4 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 5 + * 6 + * Author: Christian Krafft <krafft@de.ibm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2, or (at your option) 11 + * any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 + */ 22 + 23 + #include <linux/module.h> 24 + #include <linux/sysdev.h> 25 + #include <linux/kernel.h> 26 + #include <linux/cpu.h> 27 + #include <asm/spu.h> 28 + #include <asm/io.h> 29 + #include <asm/prom.h> 30 + 31 + #include "cbe_regs.h" 32 + 33 + static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev) 34 + { 35 + struct spu *spu; 36 + 37 + spu = container_of(sysdev, struct spu, sysdev); 38 + 39 + return cbe_get_pmd_regs(spu->devnode); 40 + } 41 + 42 + /* returns the value for a given spu in a given register */ 43 + static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg) 44 + { 45 + unsigned int *id; 46 + union spe_reg value; 47 + struct spu *spu; 48 + 49 + /* getting the id from the reg attribute will not work on future device-tree layouts 50 + * in future we should store the id to the spu struct and use it here */ 51 + spu = container_of(sysdev, struct spu, sysdev); 52 + id = (unsigned int *)get_property(spu->devnode, "reg", NULL); 53 + value.val = in_be64(&reg->val); 54 + 55 + return value.spe[*id]; 56 + } 57 + 58 + static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf) 59 + { 60 + int value; 61 + struct cbe_pmd_regs __iomem *pmd_regs; 62 + 63 + pmd_regs = get_pmd_regs(sysdev); 64 + 65 + value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1); 66 + /* clear all other bits */ 67 + value &= 0x3F; 68 + /* temp is stored in steps of 2 degrees */ 69 + value *= 2; 70 + /* base temp is 65 degrees */ 71 + value += 65; 72 + 73 + return sprintf(buf, "%d\n", (int) value); 74 + } 75 + 76 + static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos) 77 + { 78 + struct cbe_pmd_regs __iomem *pmd_regs; 79 + u64 value; 80 + 81 + pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); 82 + value = in_be64(&pmd_regs->ts_ctsr2); 83 + 84 + /* access the corresponding byte */ 85 + value >>= pos; 86 + /* clear all other bits */ 87 + value &= 0x3F; 88 + /* temp is stored in steps of 2 degrees */ 89 + value *= 2; 90 + /* base temp is 65 degrees */ 91 + value += 65; 92 + 93 + return sprintf(buf, "%d\n", (int) value); 94 + } 95 + 96 + 97 + /* shows the temperature of the DTS on the PPE, 98 + * located near the linear thermal sensor */ 99 + static ssize_t ppe_show_temp0(struct sys_device *sysdev, char *buf) 100 + { 101 + return ppe_show_temp(sysdev, buf, 32); 102 + } 103 + 104 + /* shows the temperature of the second DTS on the PPE */ 105 + static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf) 106 + { 107 + return ppe_show_temp(sysdev, buf, 0); 108 + } 109 + 110 + static struct sysdev_attribute attr_spu_temperature = { 111 + .attr = {.name = "temperature", .mode = 0400 }, 112 + .show = spu_show_temp, 113 + }; 114 + 115 + static struct attribute *spu_attributes[] = { 116 + &attr_spu_temperature.attr, 117 + }; 118 + 119 + static struct attribute_group spu_attribute_group = { 120 + .name = "thermal", 121 + .attrs = spu_attributes, 122 + }; 123 + 124 + static struct sysdev_attribute attr_ppe_temperature0 = { 125 + .attr = {.name = "temperature0", .mode = 0400 }, 126 + .show = ppe_show_temp0, 127 + }; 128 + 129 + static struct sysdev_attribute attr_ppe_temperature1 = { 130 + .attr = {.name = "temperature1", .mode = 0400 }, 131 + .show = ppe_show_temp1, 132 + }; 133 + 134 + static struct attribute *ppe_attributes[] = { 135 + &attr_ppe_temperature0.attr, 136 + &attr_ppe_temperature1.attr, 137 + }; 138 + 139 + static struct attribute_group ppe_attribute_group = { 140 + .name = "thermal", 141 + .attrs = ppe_attributes, 142 + }; 143 + 144 + /* 145 + * initialize throttling with default values 146 + */ 147 + static void __init init_default_values(void) 148 + { 149 + int cpu; 150 + struct cbe_pmd_regs __iomem *pmd_regs; 151 + struct sys_device *sysdev; 152 + union ppe_spe_reg tpr; 153 + union spe_reg str1; 154 + u64 str2; 155 + union spe_reg cr1; 156 + u64 cr2; 157 + 158 + /* TPR defaults */ 159 + /* ppe 160 + * 1F - no full stop 161 + * 08 - dynamic throttling starts if over 80 degrees 162 + * 03 - dynamic throttling ceases if below 70 degrees */ 163 + tpr.ppe = 0x1F0803; 164 + /* spe 165 + * 10 - full stopped when over 96 degrees 166 + * 08 - dynamic throttling starts if over 80 degrees 167 + * 03 - dynamic throttling ceases if below 70 degrees 168 + */ 169 + tpr.spe = 0x100803; 170 + 171 + /* STR defaults */ 172 + /* str1 173 + * 10 - stop 16 of 32 cycles 174 + */ 175 + str1.val = 0x1010101010101010ull; 176 + /* str2 177 + * 10 - stop 16 of 32 cycles 178 + */ 179 + str2 = 0x10; 180 + 181 + /* CR defaults */ 182 + /* cr1 183 + * 4 - normal operation 184 + */ 185 + cr1.val = 0x0404040404040404ull; 186 + /* cr2 187 + * 4 - normal operation 188 + */ 189 + cr2 = 0x04; 190 + 191 + for_each_possible_cpu (cpu) { 192 + pr_debug("processing cpu %d\n", cpu); 193 + sysdev = get_cpu_sysdev(cpu); 194 + pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); 195 + 196 + out_be64(&pmd_regs->tm_str2, str2); 197 + out_be64(&pmd_regs->tm_str1.val, str1.val); 198 + out_be64(&pmd_regs->tm_tpr.val, tpr.val); 199 + out_be64(&pmd_regs->tm_cr1.val, cr1.val); 200 + out_be64(&pmd_regs->tm_cr2, cr2); 201 + } 202 + } 203 + 204 + 205 + static int __init thermal_init(void) 206 + { 207 + init_default_values(); 208 + 209 + spu_add_sysdev_attr_group(&spu_attribute_group); 210 + cpu_add_sysdev_attr_group(&ppe_attribute_group); 211 + 212 + return 0; 213 + } 214 + module_init(thermal_init); 215 + 216 + static void __exit thermal_exit(void) 217 + { 218 + spu_remove_sysdev_attr_group(&spu_attribute_group); 219 + cpu_remove_sysdev_attr_group(&ppe_attribute_group); 220 + } 221 + module_exit(thermal_exit); 222 + 223 + MODULE_LICENSE("GPL"); 224 + MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); 225 +