Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: Make PCI device ids constant
  hwmon: (coretemp) Fix TjMax for Atom N450/D410/D510 CPUs
  hwmon: (k10temp) Blacklist more family 10h processors
  hwmon: (asus_atk0110) Add debugfs interface
  hwmon: (asus_atk0110) Refactor interface probe code
  hwmon: (adt7462) Fix pin 28 monitoring
This commit is contained in:
Linus Torvalds 2010-01-11 09:45:55 -08:00
commit 6102c315d8
10 changed files with 299 additions and 75 deletions

View file

@ -3,8 +3,8 @@ Kernel driver k10temp
Supported chips:
* AMD Family 10h processors:
Socket F: Quad-Core/Six-Core/Embedded Opteron
Socket AM2+: Opteron, Phenom (II) X3/X4
Socket F: Quad-Core/Six-Core/Embedded Opteron (but see below)
Socket AM2+: Quad-Core Opteron, Phenom (II) X3/X4, Athlon X2 (but see below)
Socket AM3: Quad-Core Opteron, Athlon/Phenom II X2/X3/X4, Sempron II
Socket S1G3: Athlon II, Sempron, Turion II
* AMD Family 11h processors:
@ -36,10 +36,15 @@ Description
This driver permits reading of the internal temperature sensor of AMD
Family 10h and 11h processors.
All these processors have a sensor, but on older revisions of Family 10h
processors, the sensor may return inconsistent values (erratum 319). The
driver will refuse to load on these revisions unless you specify the
"force=1" module parameter.
All these processors have a sensor, but on those for Socket F or AM2+,
the sensor may return inconsistent values (erratum 319). The driver
will refuse to load on these revisions unless you specify the "force=1"
module parameter.
Due to technical reasons, the driver can detect only the mainboard's
socket type, not the processor's actual capabilities. Therefore, if you
are using an AM3 processor on an AM2+ mainboard, you can safely use the
"force=1" parameter.
There is one temperature measurement value, available as temp1_input in
sysfs. It is measured in degrees Celsius with a resolution of 1/8th degree.

View file

@ -392,7 +392,7 @@ config SENSORS_GL520SM
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
depends on X86 && EXPERIMENTAL
depends on X86 && PCI && EXPERIMENTAL
help
If you say yes here you get support for the temperature
sensor inside your CPU. Most of the family 6 CPUs

View file

@ -94,7 +94,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
#define ADT7462_PIN24_SHIFT 6
#define ADT7462_PIN26_VOLT_INPUT 0x08
#define ADT7462_PIN25_VOLT_INPUT 0x20
#define ADT7462_PIN28_SHIFT 6 /* cfg3 */
#define ADT7462_PIN28_SHIFT 4 /* cfg3 */
#define ADT7462_PIN28_VOLT 0x5
#define ADT7462_REG_ALARM1 0xB8

View file

@ -5,6 +5,7 @@
* See COPYING in the top level directory of the kernel tree.
*/
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>
#include <linux/list.h>
@ -101,6 +102,11 @@ struct atk_data {
int temperature_count;
int fan_count;
struct list_head sensor_list;
struct {
struct dentry *root;
u32 id;
} debugfs;
};
@ -624,6 +630,187 @@ static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
return err;
}
#ifdef CONFIG_DEBUG_FS
static int atk_debugfs_gitm_get(void *p, u64 *val)
{
struct atk_data *data = p;
union acpi_object *ret;
struct atk_acpi_ret_buffer *buf;
int err = 0;
if (!data->read_handle)
return -ENODEV;
if (!data->debugfs.id)
return -EINVAL;
ret = atk_gitm(data, data->debugfs.id);
if (IS_ERR(ret))
return PTR_ERR(ret);
buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
if (buf->flags)
*val = buf->value;
else
err = -EIO;
return err;
}
DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm,
atk_debugfs_gitm_get,
NULL,
"0x%08llx\n")
static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
{
int ret = 0;
switch (obj->type) {
case ACPI_TYPE_INTEGER:
ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
break;
case ACPI_TYPE_STRING:
ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
break;
}
return ret;
}
static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
{
int ret;
int i;
for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_acpi_print(buf, sz, obj);
if (ret >= sz)
break;
buf += ret;
sz -= ret;
}
}
static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
{
struct atk_data *data = inode->i_private;
char *buf = NULL;
union acpi_object *ret;
u8 cls;
int i;
if (!data->enumerate_handle)
return -ENODEV;
if (!data->debugfs.id)
return -EINVAL;
cls = (data->debugfs.id & 0xff000000) >> 24;
ret = atk_ggrp(data, cls);
if (IS_ERR(ret))
return PTR_ERR(ret);
for (i = 0; i < ret->package.count; i++) {
union acpi_object *pack = &ret->package.elements[i];
union acpi_object *id;
if (pack->type != ACPI_TYPE_PACKAGE)
continue;
if (!pack->package.count)
continue;
id = &pack->package.elements[0];
if (id->integer.value == data->debugfs.id) {
/* Print the package */
buf = kzalloc(512, GFP_KERNEL);
if (!buf) {
ACPI_FREE(ret);
return -ENOMEM;
}
atk_pack_print(buf, 512, pack);
break;
}
}
ACPI_FREE(ret);
if (!buf)
return -EINVAL;
file->private_data = buf;
return nonseekable_open(inode, file);
}
static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
char *str = file->private_data;
size_t len = strlen(str);
return simple_read_from_buffer(buf, count, pos, str, len);
}
static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
return 0;
}
static const struct file_operations atk_debugfs_ggrp_fops = {
.read = atk_debugfs_ggrp_read,
.open = atk_debugfs_ggrp_open,
.release = atk_debugfs_ggrp_release,
};
static void atk_debugfs_init(struct atk_data *data)
{
struct dentry *d;
struct dentry *f;
data->debugfs.id = 0;
d = debugfs_create_dir("asus_atk0110", NULL);
if (!d || IS_ERR(d))
return;
f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id);
if (!f || IS_ERR(f))
goto cleanup;
f = debugfs_create_file("gitm", S_IRUSR, d, data,
&atk_debugfs_gitm);
if (!f || IS_ERR(f))
goto cleanup;
f = debugfs_create_file("ggrp", S_IRUSR, d, data,
&atk_debugfs_ggrp_fops);
if (!f || IS_ERR(f))
goto cleanup;
data->debugfs.root = d;
return;
cleanup:
debugfs_remove_recursive(d);
}
static void atk_debugfs_cleanup(struct atk_data *data)
{
debugfs_remove_recursive(data->debugfs.root);
}
#else /* CONFIG_DEBUG_FS */
static void atk_debugfs_init(struct atk_data *data)
{
}
static void atk_debugfs_cleanup(struct atk_data *data)
{
}
#endif
static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
{
struct device *dev = &data->acpi_dev->dev;
@ -1047,76 +1234,75 @@ static int atk_register_hwmon(struct atk_data *data)
return err;
}
static int atk_check_old_if(struct atk_data *data)
static int atk_probe_if(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
acpi_handle ret;
acpi_status status;
int err = 0;
/* RTMP: read temperature */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
if (status != AE_OK) {
if (ACPI_SUCCESS(status))
data->rtmp_handle = ret;
else
dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
data->rtmp_handle = ret;
/* RVLT: read voltage */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
if (status != AE_OK) {
if (ACPI_SUCCESS(status))
data->rvlt_handle = ret;
else
dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
data->rvlt_handle = ret;
/* RFAN: read fan status */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
if (status != AE_OK) {
if (ACPI_SUCCESS(status))
data->rfan_handle = ret;
else
dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
data->rfan_handle = ret;
return 0;
}
static int atk_check_new_if(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
acpi_handle ret;
acpi_status status;
/* Enumeration */
status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
if (status != AE_OK) {
if (ACPI_SUCCESS(status))
data->enumerate_handle = ret;
else
dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
data->enumerate_handle = ret;
/* De-multiplexer (read) */
status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
if (status != AE_OK) {
if (ACPI_SUCCESS(status))
data->read_handle = ret;
else
dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
data->read_handle = ret;
/* De-multiplexer (write) */
status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
if (status != AE_OK) {
dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
if (ACPI_SUCCESS(status))
data->write_handle = ret;
else
dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
data->write_handle = ret;
return 0;
/* Check for hwmon methods: first check "old" style methods; note that
* both may be present: in this case we stick to the old interface;
* analysis of multiple DSDTs indicates that when both interfaces
* are present the new one (GGRP/GITM) is not functional.
*/
if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle)
data->old_interface = true;
else if (data->enumerate_handle && data->read_handle &&
data->write_handle)
data->old_interface = false;
else
err = -ENODEV;
return err;
}
static int atk_add(struct acpi_device *device)
@ -1155,28 +1341,19 @@ static int atk_add(struct acpi_device *device)
}
ACPI_FREE(buf.pointer);
/* Check for hwmon methods: first check "old" style methods; note that
* both may be present: in this case we stick to the old interface;
* analysis of multiple DSDTs indicates that when both interfaces
* are present the new one (GGRP/GITM) is not functional.
*/
err = atk_check_old_if(data);
if (!err) {
dev_dbg(&device->dev, "Using old hwmon interface\n");
data->old_interface = true;
} else {
err = atk_check_new_if(data);
if (err)
goto out;
dev_dbg(&device->dev, "Using new hwmon interface\n");
data->old_interface = false;
err = atk_probe_if(data);
if (err) {
dev_err(&device->dev, "No usable hwmon interface detected\n");
goto out;
}
if (data->old_interface)
if (data->old_interface) {
dev_dbg(&device->dev, "Using old hwmon interface\n");
err = atk_enumerate_old_hwmon(data);
else
} else {
dev_dbg(&device->dev, "Using new hwmon interface\n");
err = atk_enumerate_new_hwmon(data);
}
if (err < 0)
goto out;
if (err == 0) {
@ -1190,6 +1367,8 @@ static int atk_add(struct acpi_device *device)
if (err)
goto cleanup;
atk_debugfs_init(data);
device->driver_data = data;
return 0;
cleanup:
@ -1208,6 +1387,8 @@ static int atk_remove(struct acpi_device *device, int type)
device->driver_data = NULL;
atk_debugfs_cleanup(data);
atk_remove_files(data);
atk_free_sensors(data);
hwmon_device_unregister(data->hwmon_dev);

View file

@ -33,6 +33,7 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/cpu.h>
#include <linux/pci.h>
#include <asm/msr.h>
#include <asm/processor.h>
@ -161,6 +162,7 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
int usemsr_ee = 1;
int err;
u32 eax, edx;
struct pci_dev *host_bridge;
/* Early chips have no MSR for TjMax */
@ -168,11 +170,21 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
usemsr_ee = 0;
}
/* Atoms seems to have TjMax at 90C */
/* Atom CPUs */
if (c->x86_model == 0x1c) {
usemsr_ee = 0;
tjmax = 90000;
host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL
&& (host_bridge->device == 0xa000 /* NM10 based nettop */
|| host_bridge->device == 0xa010)) /* NM10 based netbook */
tjmax = 100000;
else
tjmax = 90000;
pci_dev_put(host_bridge);
}
if ((c->x86_model > 0xe) && (usemsr_ee)) {

View file

@ -33,6 +33,16 @@ static bool force;
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
/* CPUID function 0x80000001, ebx */
#define CPUID_PKGTYPE_MASK 0xf0000000
#define CPUID_PKGTYPE_F 0x00000000
#define CPUID_PKGTYPE_AM2R2_AM3 0x10000000
/* DRAM controller (PCI function 2) */
#define REG_DCT0_CONFIG_HIGH 0x094
#define DDR3_MODE 0x00000100
/* miscellaneous (PCI function 3) */
#define REG_HARDWARE_THERMAL_CONTROL 0x64
#define HTC_ENABLE 0x00000001
@ -85,13 +95,28 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1);
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static bool __devinit has_erratum_319(void)
static bool __devinit has_erratum_319(struct pci_dev *pdev)
{
u32 pkg_type, reg_dram_cfg;
if (boot_cpu_data.x86 != 0x10)
return false;
/*
* Erratum 319: The thermal sensor of older Family 10h processors
* (B steppings) may be unreliable.
* Erratum 319: The thermal sensor of Socket F/AM2+ processors
* may be unreliable.
*/
return boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model <= 2;
pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK;
if (pkg_type == CPUID_PKGTYPE_F)
return true;
if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3)
return false;
/* Differentiate between AM2+ (bad) and AM3 (good) */
pci_bus_read_config_dword(pdev->bus,
PCI_DEVFN(PCI_SLOT(pdev->devfn), 2),
REG_DCT0_CONFIG_HIGH, &reg_dram_cfg);
return !(reg_dram_cfg & DDR3_MODE);
}
static int __devinit k10temp_probe(struct pci_dev *pdev,
@ -99,9 +124,10 @@ static int __devinit k10temp_probe(struct pci_dev *pdev,
{
struct device *hwmon_dev;
u32 reg_caps, reg_htc;
int unreliable = has_erratum_319(pdev);
int err;
if (has_erratum_319() && !force) {
if (unreliable && !force) {
dev_err(&pdev->dev,
"unreliable CPU thermal sensor; monitoring disabled\n");
err = -ENODEV;
@ -139,7 +165,7 @@ static int __devinit k10temp_probe(struct pci_dev *pdev,
}
dev_set_drvdata(&pdev->dev, hwmon_dev);
if (has_erratum_319() && force)
if (unreliable && force)
dev_warn(&pdev->dev,
"unreliable CPU thermal sensor; check erratum 319\n");
return 0;
@ -169,7 +195,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
dev_set_drvdata(&pdev->dev, NULL);
}
static struct pci_device_id k10temp_id_table[] = {
static const struct pci_device_id k10temp_id_table[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
{}

View file

@ -136,7 +136,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct pci_device_id k8temp_ids[] = {
static const struct pci_device_id k8temp_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
{ 0 },
};

View file

@ -697,7 +697,7 @@ static struct sis5595_data *sis5595_update_device(struct device *dev)
return data;
}
static struct pci_device_id sis5595_pci_ids[] = {
static const struct pci_device_id sis5595_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ 0, }
};

View file

@ -767,7 +767,7 @@ static struct via686a_data *via686a_update_device(struct device *dev)
return data;
}
static struct pci_device_id via686a_pci_ids[] = {
static const struct pci_device_id via686a_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
{ 0, }
};

View file

@ -697,7 +697,7 @@ static struct platform_driver vt8231_driver = {
.remove = __devexit_p(vt8231_remove),
};
static struct pci_device_id vt8231_pci_ids[] = {
static const struct pci_device_id vt8231_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) },
{ 0, }
};