Subject: Cell: add support for the two additional temperature sensors The temperature can be read from /sys/devices/system/cpu/cpuX/temperatureX. The file temperature0 is belonging to the sensor near the linear thermal diode on the PPE, temperature1 is the other sensor. Signed-off-by: Christian Krafft Index: linux-2.6/arch/powerpc/platforms/cell/thermal.c =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/thermal.c +++ linux-2.6/arch/powerpc/platforms/cell/thermal.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -54,17 +55,74 @@ static ssize_t spu_show_temp(struct sys_ return sprintf(buf, "%d\n", (int) value); } -static SYSDEV_ATTR(temperature, 0400, spu_show_temp, NULL); + +static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos) +{ + struct cbe_pmd_regs *pmd_regs; + u64 value; + + pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); + value = in_be64(&pmd_regs->ts_ctsr2); + + /* access the corresponding byte */ + value >>= pos; + /* clear all other bits */ + value &= 0x3F; + /* temp is stored in steps of 2 degrees */ + value *= 2; + /* base temp is 65 degrees */ + value += 65; + + return sprintf(buf, "%d\n", (int) value); +} + + +/* shows the temperature of the DTS on the PPE, + * located near the linear thermal sensor */ +static ssize_t ppe_show_temp0(struct sys_device *sysdev, char *buf) +{ + return ppe_show_temp(sysdev, buf, 32); +} + +/* shows the temperature of the second DTS on the PPE */ +static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf) +{ + return ppe_show_temp(sysdev, buf, 0); +} + +static struct sysdev_attribute attr_spu_temperature = { + .attr = {.name = "temperature", .mode = 0400 }, + .show = spu_show_temp, + .store = NULL, +}; + +static struct sysdev_attribute attr_ppe_temperature0 = { + .attr = {.name = "temperature0", .mode = 0400 }, + .show = ppe_show_temp0, + .store = NULL, +}; + + +static struct sysdev_attribute attr_ppe_temperature1 = { + .attr = {.name = "temperature1", .mode = 0400 }, + .show = ppe_show_temp1, + .store = NULL, +}; static int __init thermal_init(void) { - return spu_add_sysdev_attr(&attr_temperature); + spu_add_sysdev_attr(&attr_spu_temperature); + cpu_add_sysdev_attr(&attr_ppe_temperature0); + cpu_add_sysdev_attr(&attr_ppe_temperature1); + return 0; } module_init(thermal_init); static void __exit thermal_exit(void) { - spu_remove_sysdev_attr(&attr_temperature); + spu_remove_sysdev_attr(&attr_spu_temperature); + cpu_remove_sysdev_attr(&attr_ppe_temperature0); + cpu_remove_sysdev_attr(&attr_ppe_temperature1); } module_exit(thermal_exit); Index: linux-2.6/include/linux/cpu.h =================================================================== --- linux-2.6.orig/include/linux/cpu.h +++ linux-2.6/include/linux/cpu.h @@ -33,6 +33,10 @@ struct cpu { extern int register_cpu(struct cpu *cpu, int num); extern struct sys_device *get_cpu_sysdev(unsigned cpu); + +extern int cpu_add_sysdev_attr(struct sysdev_attribute *attr); +extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr); + #ifdef CONFIG_HOTPLUG_CPU extern void unregister_cpu(struct cpu *cpu); #endif Index: linux-2.6/arch/powerpc/kernel/sysfs.c =================================================================== --- linux-2.6.orig/arch/powerpc/kernel/sysfs.c +++ linux-2.6/arch/powerpc/kernel/sysfs.c @@ -300,6 +300,37 @@ static struct notifier_block __devinitda .notifier_call = sysfs_cpu_notify, }; +static DEFINE_MUTEX(cpu_mutex); + +int cpu_add_sysdev_attr(struct sysdev_attribute *attr) +{ + int cpu; + + mutex_lock(&cpu_mutex); + + for_each_possible_cpu(cpu) { + sysdev_create_file(get_cpu_sysdev(cpu), attr); + } + + mutex_unlock(&cpu_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr); + +void cpu_remove_sysdev_attr(struct sysdev_attribute *attr) +{ + int cpu; + + mutex_lock(&cpu_mutex); + + for_each_possible_cpu(cpu) { + sysdev_remove_file(get_cpu_sysdev(cpu), attr); + } + + mutex_unlock(&cpu_mutex); +} +EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr); + /* NUMA stuff */ #ifdef CONFIG_NUMA