Re: [PATCH] hwmon: Add driver for VIA CPU core temperature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Dec 10, 2009 at 08:39:04PM +0100, Jean Delvare wrote:
> From: Harald Welte <HaraldWelte@xxxxxxxxxxx>
> Subject: hwmon: Add driver for VIA CPU core temperature
> 
> This is a driver for the on-die digital temperature sensor of
> VIA's recent CPU models.
> 
> [JD: Misc clean-ups.]
> 
> Signed-off-by: Harald Welte <HaraldWelte@xxxxxxxxxxx>
> Cc: Juerg Haefliger <juergh@xxxxxxxxx>
> Signed-off-by: Jean Delvare <khali@xxxxxxxxxxxx>
> ---
> Harald, Juerg, all:

Hi Jean,

this is the driver I intend to push to Linus for
> kernel 2.6.33. It is based on Harald's driver, to which I applied
> almost all the fixes I had suggested in my review back in June. I do
> not own a VIA-based system myself so I couldn't test it. I would
> appreciate if someone could test it and report, just to make sure I
> didn't accidentally break the driver with my clean-ups. Thanks.
> 
> I didn't pick Justin's modified driver because its indentation didn't
> match what the kernel wants, and I didn't want to waste my time
> re-indenting it.
> 
> Still missing in this driver are:
> * Warnings that should be printed for CPU models with known errata.
> * Support for Vcore (or is it VID?) reporting.
> Both can be added on top of the current driver, using incremental
> patches.
> 
>  drivers/hwmon/Kconfig       |    8 
>  drivers/hwmon/Makefile      |    1 
>  drivers/hwmon/via-cputemp.c |  356 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 365 insertions(+)
>  create mode 100644 drivers/hwmon/via-cputemp.c
> 
> --- linux-2.6.33-rc0.orig/drivers/hwmon/Kconfig	2009-12-10 18:57:39.000000000 +0100
> +++ linux-2.6.33-rc0/drivers/hwmon/Kconfig	2009-12-10 18:57:44.000000000 +0100
> @@ -822,6 +822,14 @@ config SENSORS_TMP421
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called tmp421.
>  
> +config SENSORS_VIA_CPUTEMP
> +	tristate "VIA CPU temperature sensor"
> +	depends on X86
> +	help
> +	  If you say yes here you get support for the temperature
> +	  sensor inside your CPU. Supported all are all known variants

There's a typo (all are all) since Harald's first version.

> +	  of the VIA C7 and Nano.
> +
>  config SENSORS_VIA686A
>  	tristate "VIA686A"
>  	depends on PCI
> --- linux-2.6.33-rc0.orig/drivers/hwmon/Makefile	2009-12-10 18:57:39.000000000 +0100
> +++ linux-2.6.33-rc0/drivers/hwmon/Makefile	2009-12-10 18:57:44.000000000 +0100
> @@ -88,6 +88,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc4
>  obj-$(CONFIG_SENSORS_THMC50)	+= thmc50.o
>  obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
>  obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
> +obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
>  obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
>  obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
>  obj-$(CONFIG_SENSORS_VT8231)	+= vt8231.o
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.33-rc0/drivers/hwmon/via-cputemp.c	2009-12-10 19:54:27.000000000 +0100
> @@ -0,0 +1,356 @@
> +/*
> + * via-cputemp.c - Driver for VIA CPU core temperature monitoring
> + * Copyright (C) 2009 VIA Technologies, Inc.
> + *
> + * based on existing coretemp.c, which is
> + *
> + * Copyright (C) 2007 Rudolf Marek <r.marek@xxxxxxxxxxxx>
> + *
> + * 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; version 2 of the License.
> + *
> + * 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 <linux/cpu.h>
> +#include <asm/msr.h>
> +#include <asm/processor.h>
> +
> +#define DRVNAME	"via_cputemp"
> +
> +enum { SHOW_TEMP, SHOW_LABEL, SHOW_NAME } SHOW;
> +
> +/*
> + * Functions declaration
> + */
> +
> +struct via_cputemp_data {
> +	struct device *hwmon_dev;
> +	const char *name;
> +	u32 id;
> +	u32 msr;
> +};
> +
> +/*
> + * 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 via_cputemp_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_temp(struct device *dev,
> +			 struct device_attribute *devattr, char *buf)
> +{
> +	struct via_cputemp_data *data = dev_get_drvdata(dev);
> +	u32 eax, edx;
> +	int err;
> +
> +	err = rdmsr_safe_on_cpu(data->id, data->msr, &eax, &edx);
> +	if (err)
> +		return -EAGAIN;
> +
> +	return sprintf(buf, "%lu\n", ((unsigned long)eax & 0xffffff) * 1000);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
> +			  SHOW_TEMP);
> +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 *via_cputemp_attributes[] = {
> +	&sensor_dev_attr_name.dev_attr.attr,
> +	&sensor_dev_attr_temp1_label.dev_attr.attr,
> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group via_cputemp_group = {
> +	.attrs = via_cputemp_attributes,
> +};
> +
> +static int __devinit via_cputemp_probe(struct platform_device *pdev)
> +{
> +	struct via_cputemp_data *data;
> +	struct cpuinfo_x86 *c = &cpu_data(pdev->id);
> +	int err;
> +	u32 eax, edx;
> +
> +	data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL);
> +	if (!data) {
> +		err = -ENOMEM;
> +		dev_err(&pdev->dev, "Out of memory\n");
> +		goto exit;
> +	}
> +
> +	data->id = pdev->id;
> +	data->name = "via-cputemp";
> +
> +	switch (c->x86_model) {
> +	case 0xA:
> +		/* C7 A */
> +	case 0xD:
> +		/* C7 D */
> +		data->msr = 0x1169;
> +		break;
> +	case 0xF:
> +		/* Nano */
> +		data->msr = 0x1423;
> +		break;
> +	default:
> +		err = -ENODEV;
> +		goto exit_free;
> +	}
> +
> +	/* test if we can access the TEMPERATURE MSR */
> +	err = rdmsr_safe_on_cpu(data->id, data->msr, &eax, &edx);
> +	if (err) {
> +		dev_err(&pdev->dev,
> +			"Unable to access TEMPERATURE MSR, giving up\n");
> +		goto exit_free;
> +	}
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
> +	if (err)
> +		goto exit_free;
> +
> +	data->hwmon_dev = hwmon_device_register(&pdev->dev);
> +	if (IS_ERR(data->hwmon_dev)) {
> +		err = PTR_ERR(data->hwmon_dev);
> +		dev_err(&pdev->dev, "Class registration failed (%d)\n",
> +			err);
> +		goto exit_remove;
> +	}
> +
> +	return 0;
> +
> +exit_remove:
> +	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
> +exit_free:
> +	platform_set_drvdata(pdev, NULL);
> +	kfree(data);
> +exit:
> +	return err;
> +}
> +
> +static int __devexit via_cputemp_remove(struct platform_device *pdev)
> +{
> +	struct via_cputemp_data *data = platform_get_drvdata(pdev);
> +
> +	hwmon_device_unregister(data->hwmon_dev);
> +	sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
> +	platform_set_drvdata(pdev, NULL);
> +	kfree(data);
> +	return 0;
> +}
> +
> +static struct platform_driver via_cputemp_driver = {
> +	.driver = {
> +		.owner = THIS_MODULE,
> +		.name = DRVNAME,
> +	},
> +	.probe = via_cputemp_probe,
> +	.remove = __devexit_p(via_cputemp_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 via_cputemp_device_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
> +static void via_cputemp_device_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 __cpuinit via_cputemp_cpu_callback(struct notifier_block *nfb,
> +				 unsigned long action, void *hcpu)
> +{
> +	unsigned int cpu = (unsigned long) hcpu;
> +
> +	switch (action) {
> +	case CPU_ONLINE:
> +	case CPU_DOWN_FAILED:
> +		via_cputemp_device_add(cpu);
> +		break;
> +	case CPU_DOWN_PREPARE:
> +		via_cputemp_device_remove(cpu);
> +		break;
> +	}
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block via_cputemp_cpu_notifier __refdata = {
> +	.notifier_call = via_cputemp_cpu_callback,
> +};
> +#endif				/* !CONFIG_HOTPLUG_CPU */
> +
> +static int __init via_cputemp_init(void)
> +{
> +	int i, err;
> +	struct pdev_entry *p, *n;
> +
> +	if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) {
> +		printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n");
> +		err = -ENODEV;
> +		goto exit;
> +	}
> +
> +	err = platform_driver_register(&via_cputemp_driver);
> +	if (err)
> +		goto exit;
> +
> +	for_each_online_cpu(i) {
> +		struct cpuinfo_x86 *c = &cpu_data(i);
> +
> +		if (c->x86 != 6)
> +			continue;
> +
> +		if (c->x86_model < 0x0a)
> +			continue;
> +
> +		if (c->x86_model > 0x0f) {
> +			printk(KERN_WARNING DRVNAME ": Unknown CPU "
> +				"model 0x%x\n", c->x86_model);
> +			continue;
> +		}
> +
> +		err = via_cputemp_device_add(i);
> +		if (err)
> +			goto exit_devices_unreg;
> +	}
> +	if (list_empty(&pdev_list)) {
> +		err = -ENODEV;
> +		goto exit_driver_unreg;
> +	}
> +
> +#ifdef CONFIG_HOTPLUG_CPU
> +	register_hotcpu_notifier(&via_cputemp_cpu_notifier);
> +#endif
> +	return 0;
> +
> +exit_devices_unreg:
> +	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(&via_cputemp_driver);
> +exit:
> +	return err;
> +}
> +
> +static void __exit via_cputemp_exit(void)
> +{
> +	struct pdev_entry *p, *n;
> +#ifdef CONFIG_HOTPLUG_CPU
> +	unregister_hotcpu_notifier(&via_cputemp_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(&via_cputemp_driver);
> +}
> +
> +MODULE_AUTHOR("Harald Welte <HaraldWelte@xxxxxxxxxxx>");
> +MODULE_DESCRIPTION("VIA CPU temperature monitor");
> +MODULE_LICENSE("GPL");
> +
> +module_init(via_cputemp_init)
> +module_exit(via_cputemp_exit)
> 
> 
> -- 
> Jean Delvare

Regards,
Andre

_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux