Revision: 85 http://svn.sourceforge.net/mactel-linux/?rev=85&view=rev Author: nboichat Date: 2007-03-13 22:20:38 -0700 (Tue, 13 Mar 2007)
Log Message: ----------- Fix coretemp patch. Modified Paths: -------------- trunk/kernel/mactel-patches-2.6.21/coretemp.patch Modified: trunk/kernel/mactel-patches-2.6.21/coretemp.patch =================================================================== --- trunk/kernel/mactel-patches-2.6.21/coretemp.patch 2007-03-14 05:07:48 UTC (rev 84) +++ trunk/kernel/mactel-patches-2.6.21/coretemp.patch 2007-03-14 05:20:38 UTC (rev 85) @@ -5,12 +5,13 @@ --- - arch/i386/kernel/msr.c | 31 +++++++++++++++++-------------- - drivers/hwmon/Kconfig | 9 +++++++++ - drivers/hwmon/Makefile | 1 + - include/asm-i386/msr.h | 3 +++ - include/asm-x86_64/msr.h | 3 +++ - 5 files changed, 33 insertions(+), 14 deletions(-) + arch/i386/kernel/msr.c | 31 ++-- + drivers/hwmon/Kconfig | 9 + + drivers/hwmon/Makefile | 1 + drivers/hwmon/coretemp.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++ + include/asm-i386/msr.h | 3 + include/asm-x86_64/msr.h | 3 + 6 files changed, 433 insertions(+), 14 deletions(-) diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index bcaa6e9..c9a8f88 100644 @@ -152,6 +153,412 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_F71805F) += f71805f.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o +diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c +new file mode 100644 +index 0000000..f139b41 +--- /dev/null ++++ b/drivers/hwmon/coretemp.c +@@ -0,0 +1,400 @@ ++/* ++ * coretemp.c - Linux kernel module for hardware monitoring ++ * ++ * Copyright (C) 2006 Rudolf Marek <[EMAIL PROTECTED]> ++ * ++ * Inspired from many hwmon drivers ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301 USA. ++ */ ++ ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/jiffies.h> ++#include <linux/hwmon.h> ++#include <linux/sysfs.h> ++#include <linux/hwmon-sysfs.h> ++#include <linux/err.h> ++#include <linux/mutex.h> ++#include <linux/list.h> ++#include <linux/platform_device.h> ++#include <asm/msr.h> ++#include <linux/cpu.h> ++ ++#define DRVNAME "coretemp" ++ ++typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW; ++ ++/* ++ * Functions declaration ++ */ ++ ++static struct coretemp_data *coretemp_update_device(struct device *dev); ++ ++struct coretemp_data { ++ struct class_device *class_dev; ++ struct mutex update_lock; ++ const char *name; ++ u32 id; ++ char valid; /* zero until following fields are valid */ ++ unsigned long last_updated; /* in jiffies */ ++ int temp; ++ int tjmax; ++ /* registers values */ ++ u32 therm_status; ++}; ++ ++static struct coretemp_data *coretemp_update_device(struct device *dev); ++ ++/* ++ * Sysfs stuff ++ */ ++ ++ ++static ssize_t show_name(struct device *dev, struct device_attribute ++ *devattr, char *buf) ++{ ++ int ret; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct coretemp_data *data = dev_get_drvdata(dev); ++ ++ if (attr->index == SHOW_NAME) ++ ret = sprintf(buf, "%s\n", data->name); ++ else /* show label */ ++ ret = sprintf(buf, "Core %d\n", data->id); ++ return ret; ++} ++ ++static ssize_t show_alarm(struct device *dev, struct device_attribute ++ *devattr, char *buf) ++{ ++ struct coretemp_data *data = coretemp_update_device(dev); ++ /* read the Out-of-spec log, never clear */ ++ return sprintf(buf, "%d\n", (data->therm_status >> 5) & 1); ++} ++ ++static ssize_t show_temp(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct coretemp_data *data = coretemp_update_device(dev); ++ return sprintf(buf, "%d\n", ++ attr->index == ++ SHOW_TEMP ? data->temp : data->tjmax); ++} ++ ++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, ++ SHOW_TEMP); ++static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, ++ SHOW_TJMAX); ++static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL); ++static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL); ++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME); ++ ++static struct attribute *coretemp_attributes[] = { ++ &sensor_dev_attr_name.dev_attr.attr, ++ &sensor_dev_attr_temp1_label.dev_attr.attr, ++ &dev_attr_temp1_crit_alarm.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_crit.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group coretemp_group = { ++ .attrs = coretemp_attributes, ++}; ++ ++static struct coretemp_data *coretemp_update_device(struct device *dev) ++{ ++ struct coretemp_data *data = dev_get_drvdata(dev); ++ ++ mutex_lock(&data->update_lock); ++ ++ if (!data->valid || time_after(jiffies, data->last_updated + HZ)) { ++ u32 eax, edx; ++ ++ data->valid = 0; ++ msr_read(data->id, MSR_IA32_THERM_STATUS, &eax, &edx); ++ data->therm_status = eax; ++ ++ /* update only if data has been valid */ ++ if (eax & 0x80000000) { ++ data->temp = data->tjmax - (((data->therm_status >> 16) ++ & 0x7f) * 1000); ++ data->valid = 1; ++ } ++ data->last_updated = jiffies; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ return data; ++} ++ ++static int __devinit coretemp_probe(struct platform_device *pdev) ++{ ++ struct coretemp_data *data; ++ struct cpuinfo_x86 *c = &(cpu_data)[pdev->id]; ++ int err; ++ u32 eax, edx; ++ ++ if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ dev_err(&pdev->dev, "Out of memory\n"); ++ goto exit; ++ } ++ ++ data->id = pdev->id; ++ data->name = "coretemp"; ++ mutex_init(&data->update_lock); ++ /* Tjmax default is 100C */ ++ data->tjmax = 100000; ++ ++ /* Some processors have Tjmax 85 following magic should detect it */ ++ /* family is always 0x6 */ ++ ++ if (((c->x86_model == 0xf) && (c->x86_mask > 3 )) || ++ (c->x86_model == 0xe)) { ++ ++ err = msr_read(data->id, 0xee, &eax, &edx); ++ if (err) { ++ dev_warn(&pdev->dev, ++ "Unable to access MSR 0xEE, Tjmax left at %d\n", ++ data->tjmax); ++ } else if (eax & 0x40000000) { ++ data->tjmax = 85000; ++ } ++ } ++ ++ /* test if we can access the THERM_STATUS MSR */ ++ err = msr_read(data->id, MSR_IA32_THERM_STATUS, &eax, &edx); ++ ++ if (err) { ++ dev_err(&pdev->dev, ++ "Unable to access THERM_STATUS MSR, giving up\n"); ++ goto exit_free; ++ } ++ platform_set_drvdata(pdev, data); ++ ++ if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group))) ++ goto exit_free; ++ ++ data->class_dev = hwmon_device_register(&pdev->dev); ++ if (IS_ERR(data->class_dev)) { ++ err = PTR_ERR(data->class_dev); ++ dev_err(&pdev->dev, "Class registration failed (%d)\n", ++ err); ++ goto exit_class; ++ } ++ ++ return 0; ++ ++exit_class: ++ sysfs_remove_group(&pdev->dev.kobj, &coretemp_group); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int __devexit coretemp_remove(struct platform_device *pdev) ++{ ++ struct coretemp_data *data = platform_get_drvdata(pdev); ++ ++ hwmon_device_unregister(data->class_dev); ++ sysfs_remove_group(&pdev->dev.kobj, &coretemp_group); ++ platform_set_drvdata(pdev, NULL); ++ kfree(data); ++ return 0; ++} ++ ++static struct platform_driver coretemp_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRVNAME, ++ }, ++ .probe = coretemp_probe, ++ .remove = __devexit_p(coretemp_remove), ++}; ++ ++struct pdev_entry { ++ struct list_head list; ++ struct platform_device *pdev; ++ unsigned int cpu; ++}; ++ ++static LIST_HEAD(pdev_list); ++static DEFINE_MUTEX(pdev_list_mutex); ++ ++static int __cpuinit coretemp_devices_add(unsigned int cpu) ++{ ++ int err; ++ struct platform_device *pdev; ++ struct pdev_entry *pdev_entry; ++ ++ pdev = platform_device_alloc(DRVNAME, cpu); ++ if (!pdev) { ++ err = -ENOMEM; ++ printk(KERN_ERR DRVNAME ": Device allocation failed\n"); ++ goto exit; ++ ++ } ++ ++ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL); ++ ++ if (!pdev_entry) { ++ err = -ENOMEM; ++ goto exit_device_put; ++ } ++ ++ err = platform_device_add(pdev); ++ ++ if (err) { ++ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", ++ err); ++ goto exit_device_free; ++ } ++ ++ pdev_entry->pdev = pdev; ++ pdev_entry->cpu = cpu; ++ mutex_lock(&pdev_list_mutex); ++ list_add_tail(&pdev_entry->list, &pdev_list); ++ mutex_unlock(&pdev_list_mutex); ++ ++ return 0; ++ ++exit_device_free: ++ kfree(pdev_entry); ++exit_device_put: ++ platform_device_put(pdev); ++exit: ++ return err; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++void coretemp_devices_remove(unsigned int cpu) ++{ ++ struct pdev_entry *p, *n; ++ mutex_lock(&pdev_list_mutex); ++ list_for_each_entry_safe(p, n, &pdev_list, list) { ++ if (p->cpu == cpu) { ++ platform_device_unregister(p->pdev); ++ list_del(&p->list); ++ kfree(p); ++ } ++ } ++ mutex_unlock(&pdev_list_mutex); ++} ++ ++static int coretemp_cpu_callback(struct notifier_block *nfb, ++ unsigned long action, void *hcpu) ++{ ++ unsigned int cpu = (unsigned long) hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ coretemp_devices_add(cpu); ++ break; ++ case CPU_DEAD: ++ coretemp_devices_remove(cpu); ++ break; ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block __cpuinitdata coretemp_cpu_notifier = { ++ .notifier_call = coretemp_cpu_callback, ++}; ++#endif /* !CONFIG_HOTPLUG_CPU */ ++ ++static int __init coretemp_init(void) ++{ ++ int i, err = -ENODEV; ++ struct pdev_entry *p, *n; ++ ++ if (current_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ goto exit; ++ ++ err = platform_driver_register(&coretemp_driver); ++ if (err) ++ goto exit; ++ ++ for_each_online_cpu(i) { ++ struct cpuinfo_x86 *c = &(cpu_data)[i]; ++ ++ /* check if family 6, models e, f */ ++ if ((c->cpuid_level < 0) || (c->x86 != 0x6) || ++ !((c->x86_model == 0xe) || (c->x86_model == 0xf))) { ++ ++ /* supported CPU not found, but report the unknown ++ family 6 CPU */ ++ if ((c->x86 == 0x6) && (c->x86_model > 0xf)) ++ printk(KERN_WARNING DRVNAME ": Unknown CPU, please" ++ " report to the [EMAIL PROTECTED]"); ++ continue; ++ } ++ ++ err = coretemp_devices_add(i); ++ if (err) ++ goto exit_driver; ++ } ++ if (list_empty(&pdev_list)) { ++ err = -ENODEV; ++ goto exit_driver_unreg; ++ } ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ register_hotcpu_notifier(&coretemp_cpu_notifier); ++#endif ++ return 0; ++ ++exit_driver: ++ mutex_lock(&pdev_list_mutex); ++ list_for_each_entry_safe(p, n, &pdev_list, list) { ++ platform_device_unregister(p->pdev); ++ list_del(&p->list); ++ kfree(p); ++ } ++ mutex_unlock(&pdev_list_mutex); ++exit_driver_unreg: ++ platform_driver_unregister(&coretemp_driver); ++exit: ++ return err; ++} ++ ++static void __exit coretemp_exit(void) ++{ ++ struct pdev_entry *p, *n; ++#ifdef CONFIG_HOTPLUG_CPU ++ unregister_hotcpu_notifier(&coretemp_cpu_notifier); ++#endif ++ mutex_lock(&pdev_list_mutex); ++ list_for_each_entry_safe(p, n, &pdev_list, list) { ++ platform_device_unregister(p->pdev); ++ list_del(&p->list); ++ kfree(p); ++ } ++ mutex_unlock(&pdev_list_mutex); ++ platform_driver_unregister(&coretemp_driver); ++} ++ ++MODULE_AUTHOR("Rudolf Marek <[EMAIL PROTECTED]>"); ++MODULE_DESCRIPTION("Intel Core temperature monitor"); ++MODULE_LICENSE("GPL"); ++ ++module_init(coretemp_init) ++module_exit(coretemp_exit) diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h index ec3b680..ff73a99 100644 --- a/include/asm-i386/msr.h This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Mactel-linux-devel mailing list Mactel-linux-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mactel-linux-devel