* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
@ 2011-01-05 11:35 ` Luca Tettamanti
2011-01-05 13:45 ` Joris Creyghton
` (17 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-05 11:35 UTC (permalink / raw)
To: lm-sensors
On Mon, Jan 3, 2011 at 12:07 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> Dear reader,
>
> Problem:
> The sensors command reports 0C for the MCH temp., while the BIOS gives a
> reasonable value of about 40C.
>
> Output of sensors command:
>
> joris@Asus5:~$ sensors
> atk0110-acpi-0
[...]
> MCH Temperature: +0.0°C (high = +60.0°C, crit = +95.0°C)
Is it always 0 or does it jump up and down?
Please send a copy of /sys/firmware/acpi/tables/DSDT
Luca
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
2011-01-05 11:35 ` Luca Tettamanti
@ 2011-01-05 13:45 ` Joris Creyghton
2011-01-05 14:08 ` Luca Tettamanti
` (16 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-05 13:45 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 796 bytes --]
On Wed, 2011-01-05 at 12:35 +0100, Luca Tettamanti wrote:
> On Mon, Jan 3, 2011 at 12:07 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> > Dear reader,
> >
> > Problem:
> > The sensors command reports 0C for the MCH temp., while the BIOS gives a
> > reasonable value of about 40C.
> >
> > Output of sensors command:
> >
> > joris@Asus5:~$ sensors
> > atk0110-acpi-0
> [...]
> > MCH Temperature: +0.0°C (high = +60.0°C, crit = +95.0°C)
>
> Is it always 0 or does it jump up and down?
>
> Please send a copy of /sys/firmware/acpi/tables/DSDT
>
> Luca
Dear Luca,
The MCH temp. is always 0 en never jumps.
Attached you'll find the file /sys/firmware/acpi/tables/DSDT
Thank you for paying attention to my problem,
kind regards,
Joris Creyghton
[-- Attachment #1.2: Type: text/html, Size: 1202 bytes --]
[-- Attachment #2: Type: application/octet-stream, Size: 50281 bytes --]
[-- Attachment #3: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
2011-01-05 11:35 ` Luca Tettamanti
2011-01-05 13:45 ` Joris Creyghton
@ 2011-01-05 14:08 ` Luca Tettamanti
2011-01-05 14:35 ` Joris Creyghton
` (15 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-05 14:08 UTC (permalink / raw)
To: lm-sensors
On Wed, Jan 5, 2011 at 2:45 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> The MCH temp. is always 0 en never jumps.
>
> Attached you'll find the file /sys/firmware/acpi/tables/DSDT
Hum, it appears to be a bug in the ACPI code, the method that reads
the temperature does not know how to read the MCH temperature which
would be HWT2 (the entry is present in the enumeration though):
Method (TGET, 1, NotSerialized)
{
If (LEqual (Arg0, Zero))
{
Return (^^SIOR.HWT1 ())
}
If (LEqual (Arg0, One))
{
Return (^^SIOR.HWT0 ())
}
}
To complicate things the firmware provides both the old and the new
ATK0110 interfaces, and the driver selects the old one. The new one
seems to have the code to read all the sensors. I'll see what I can
do.
Luca
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (2 preceding siblings ...)
2011-01-05 14:08 ` Luca Tettamanti
@ 2011-01-05 14:35 ` Joris Creyghton
2011-01-06 21:01 ` Jean Delvare
` (14 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-05 14:35 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 756 bytes --]
On Wed, 2011-01-05 at 15:08 +0100, Luca Tettamanti wrote:
> Hum, it appears to be a bug in the ACPI code, the method that reads
> the temperature does not know how to read the MCH temperature which
> would be HWT2 (the entry is present in the enumeration though):
>
> Method (TGET, 1, NotSerialized)
> {
> If (LEqual (Arg0, Zero))
> {
> Return (^^SIOR.HWT1 ())
> }
>
> If (LEqual (Arg0, One))
> {
> Return (^^SIOR.HWT0 ())
> }
> }
>
> To complicate things the firmware provides both the old and the new
> ATK0110 interfaces, and the driver selects the old one. The new one
> seems to have the code to read all the sensors. I'll see what I can
> do.
>
> Luca
Looking forward to your further findings.
Joris
[-- Attachment #1.2: Type: text/html, Size: 1015 bytes --]
[-- Attachment #2: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (3 preceding siblings ...)
2011-01-05 14:35 ` Joris Creyghton
@ 2011-01-06 21:01 ` Jean Delvare
2011-01-07 13:14 ` Luca Tettamanti
` (13 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jean Delvare @ 2011-01-06 21:01 UTC (permalink / raw)
To: lm-sensors
Hi Luca,
On Wed, 5 Jan 2011 15:08:44 +0100, Luca Tettamanti wrote:
> On Wed, Jan 5, 2011 at 2:45 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> > The MCH temp. is always 0 en never jumps.
> >
> > Attached you'll find the file /sys/firmware/acpi/tables/DSDT
>
> Hum, it appears to be a bug in the ACPI code, the method that reads
> the temperature does not know how to read the MCH temperature which
> would be HWT2 (the entry is present in the enumeration though):
>
> Method (TGET, 1, NotSerialized)
> {
> If (LEqual (Arg0, Zero))
> {
> Return (^^SIOR.HWT1 ())
> }
>
> If (LEqual (Arg0, One))
> {
> Return (^^SIOR.HWT0 ())
> }
> }
>
> To complicate things the firmware provides both the old and the new
> ATK0110 interfaces, and the driver selects the old one. The new one
> seems to have the code to read all the sensors. I'll see what I can
> do.
Would it make sense to add a module parameter to asus_atk0110 to let
the user force the interface when both are present? So that the user
can test the other one and report easily.
--
Jean Delvare
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (4 preceding siblings ...)
2011-01-06 21:01 ` Jean Delvare
@ 2011-01-07 13:14 ` Luca Tettamanti
2011-01-10 15:25 ` Luca Tettamanti
` (12 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-07 13:14 UTC (permalink / raw)
To: lm-sensors
On Thu, Jan 6, 2011 at 10:01 PM, Jean Delvare <khali@linux-fr.org> wrote:
[...]
>> To complicate things the firmware provides both the old and the new
>> ATK0110 interfaces, and the driver selects the old one. The new one
>> seems to have the code to read all the sensors. I'll see what I can
>> do.
>
> Would it make sense to add a module parameter to asus_atk0110 to let
> the user force the interface when both are present? So that the user
> can test the other one and report easily.
Yes, I'm planning to do that. Plus maybe a DMI table to automatically
override the default logic.
Luca
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (5 preceding siblings ...)
2011-01-07 13:14 ` Luca Tettamanti
@ 2011-01-10 15:25 ` Luca Tettamanti
2011-01-10 18:48 ` Joris Creyghton
` (11 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-10 15:25 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1: Type: text/plain, Size: 442 bytes --]
On Wed, Jan 5, 2011 at 3:08 PM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> To complicate things the firmware provides both the old and the new
> ATK0110 interfaces, and the driver selects the old one. The new one
> seems to have the code to read all the sensors. I'll see what I can
> do.
I'm attaching a modified version of the driver; I've added a parameter
to override the default detection logic, to test load it with new_if=1
Luca
[-- Attachment #2: asus_atk0110.c --]
[-- Type: text/x-csrc, Size: 33575 bytes --]
/*
* Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
*
* This file is released under the GPLv2
* See COPYING in the top level directory of the kernel tree.
*/
#define DEBUG
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <acpi/acpi.h>
#include <acpi/acpixf.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#define ATK_HID "ATK0110"
static bool new_if;
module_param(new_if, bool, 0);
MODULE_PARM_DESC(new_if, "Override detection heuristic and for the use of the new ATK0110 interface");
/* Minimum time between readings, enforced in order to avoid
* hogging the CPU.
*/
#define CACHE_TIME HZ
#define BOARD_ID "MBIF"
#define METHOD_ENUMERATE "GGRP"
#define METHOD_READ "GITM"
#define METHOD_WRITE "SITM"
#define METHOD_OLD_READ_TMP "RTMP"
#define METHOD_OLD_READ_VLT "RVLT"
#define METHOD_OLD_READ_FAN "RFAN"
#define METHOD_OLD_ENUM_TMP "TSIF"
#define METHOD_OLD_ENUM_VLT "VSIF"
#define METHOD_OLD_ENUM_FAN "FSIF"
#define ATK_MUX_HWMON 0x00000006ULL
#define ATK_MUX_MGMT 0x00000011ULL
#define ATK_CLASS_MASK 0xff000000ULL
#define ATK_CLASS_FREQ_CTL 0x03000000ULL
#define ATK_CLASS_FAN_CTL 0x04000000ULL
#define ATK_CLASS_HWMON 0x06000000ULL
#define ATK_CLASS_MGMT 0x11000000ULL
#define ATK_TYPE_MASK 0x00ff0000ULL
#define HWMON_TYPE_VOLT 0x00020000ULL
#define HWMON_TYPE_TEMP 0x00030000ULL
#define HWMON_TYPE_FAN 0x00040000ULL
#define ATK_ELEMENT_ID_MASK 0x0000ffffULL
#define ATK_EC_ID 0x11060004ULL
enum atk_pack_member {
HWMON_PACK_FLAGS,
HWMON_PACK_NAME,
HWMON_PACK_LIMIT1,
HWMON_PACK_LIMIT2,
HWMON_PACK_ENABLE
};
/* New package format */
#define _HWMON_NEW_PACK_SIZE 7
#define _HWMON_NEW_PACK_FLAGS 0
#define _HWMON_NEW_PACK_NAME 1
#define _HWMON_NEW_PACK_UNK1 2
#define _HWMON_NEW_PACK_UNK2 3
#define _HWMON_NEW_PACK_LIMIT1 4
#define _HWMON_NEW_PACK_LIMIT2 5
#define _HWMON_NEW_PACK_ENABLE 6
/* Old package format */
#define _HWMON_OLD_PACK_SIZE 5
#define _HWMON_OLD_PACK_FLAGS 0
#define _HWMON_OLD_PACK_NAME 1
#define _HWMON_OLD_PACK_LIMIT1 2
#define _HWMON_OLD_PACK_LIMIT2 3
#define _HWMON_OLD_PACK_ENABLE 4
struct atk_data {
struct device *hwmon_dev;
acpi_handle atk_handle;
struct acpi_device *acpi_dev;
bool old_interface;
/* old interface */
acpi_handle rtmp_handle;
acpi_handle rvlt_handle;
acpi_handle rfan_handle;
/* new inteface */
acpi_handle enumerate_handle;
acpi_handle read_handle;
acpi_handle write_handle;
bool disable_ec;
int voltage_count;
int temperature_count;
int fan_count;
struct list_head sensor_list;
struct {
struct dentry *root;
u32 id;
} debugfs;
};
typedef ssize_t (*sysfs_show_func)(struct device *dev,
struct device_attribute *attr, char *buf);
static const struct acpi_device_id atk_ids[] = {
{ATK_HID, 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, atk_ids);
#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
struct atk_sensor_data {
struct list_head list;
struct atk_data *data;
struct device_attribute label_attr;
struct device_attribute input_attr;
struct device_attribute limit1_attr;
struct device_attribute limit2_attr;
char label_attr_name[ATTR_NAME_SIZE];
char input_attr_name[ATTR_NAME_SIZE];
char limit1_attr_name[ATTR_NAME_SIZE];
char limit2_attr_name[ATTR_NAME_SIZE];
u64 id;
u64 type;
u64 limit1;
u64 limit2;
u64 cached_value;
unsigned long last_updated; /* in jiffies */
bool is_valid;
char const *acpi_name;
};
/* Return buffer format:
* [0-3] "value" is valid flag
* [4-7] value
* [8- ] unknown stuff on newer mobos
*/
struct atk_acpi_ret_buffer {
u32 flags;
u32 value;
u8 data[];
};
/* Input buffer used for GITM and SITM methods */
struct atk_acpi_input_buf {
u32 id;
u32 param1;
u32 param2;
};
static int atk_add(struct acpi_device *device);
static int atk_remove(struct acpi_device *device, int type);
static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
static void atk_free_sensors(struct atk_data *data);
static struct acpi_driver atk_driver = {
.name = ATK_HID,
.class = "hwmon",
.ids = atk_ids,
.ops = {
.add = atk_add,
.remove = atk_remove,
},
};
#define input_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, input_attr)
#define label_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, label_attr)
#define limit1_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, limit1_attr)
#define limit2_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, limit2_attr)
static ssize_t atk_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = input_to_atk_sensor(attr);
u64 value;
int err;
err = atk_read_value(s, &value);
if (err)
return err;
if (s->type == HWMON_TYPE_TEMP)
/* ACPI returns decidegree */
value *= 100;
return sprintf(buf, "%llu\n", value);
}
static ssize_t atk_label_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = label_to_atk_sensor(attr);
return sprintf(buf, "%s\n", s->acpi_name);
}
static ssize_t atk_limit1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
u64 value = s->limit1;
if (s->type == HWMON_TYPE_TEMP)
value *= 100;
return sprintf(buf, "%lld\n", value);
}
static ssize_t atk_limit2_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
u64 value = s->limit2;
if (s->type == HWMON_TYPE_TEMP)
value *= 100;
return sprintf(buf, "%lld\n", value);
}
static ssize_t atk_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "atk0110\n");
}
static struct device_attribute atk_name_attr =
__ATTR(name, 0444, atk_name_show, NULL);
static void atk_init_attribute(struct device_attribute *attr, char *name,
sysfs_show_func show)
{
attr->attr.name = name;
attr->attr.mode = 0444;
attr->show = show;
attr->store = NULL;
}
static union acpi_object *atk_get_pack_member(struct atk_data *data,
union acpi_object *pack,
enum atk_pack_member m)
{
bool old_if = data->old_interface;
int offset;
switch (m) {
case HWMON_PACK_FLAGS:
offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
break;
case HWMON_PACK_NAME:
offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
break;
case HWMON_PACK_LIMIT1:
offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
_HWMON_NEW_PACK_LIMIT1;
break;
case HWMON_PACK_LIMIT2:
offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
_HWMON_NEW_PACK_LIMIT2;
break;
case HWMON_PACK_ENABLE:
offset = old_if ? _HWMON_OLD_PACK_ENABLE :
_HWMON_NEW_PACK_ENABLE;
break;
default:
return NULL;
}
return &pack->package.elements[offset];
}
/* New package format is:
* - flag (int)
* class - used for de-muxing the request to the correct GITn
* type (volt, temp, fan)
* sensor id |
* sensor id - used for de-muxing the request _inside_ the GITn
* - name (str)
* - unknown (int)
* - unknown (int)
* - limit1 (int)
* - limit2 (int)
* - enable (int)
*
* The old package has the same format but it's missing the two unknown fields.
*/
static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *tmp;
bool old_if = data->old_interface;
int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
_HWMON_NEW_PACK_SIZE;
if (obj->type != ACPI_TYPE_PACKAGE) {
dev_warn(dev, "Invalid type: %d\n", obj->type);
return -EINVAL;
}
if (obj->package.count != expected_size) {
dev_warn(dev, "Invalid package size: %d, expected: %d\n",
obj->package.count, expected_size);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
if (tmp->type != ACPI_TYPE_STRING) {
dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
return -EINVAL;
}
/* Don't check... we don't know what they're useful for anyway */
#if 0
tmp = &obj->package.elements[HWMON_PACK_UNK1];
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
return -EINVAL;
}
tmp = &obj->package.elements[HWMON_PACK_UNK2];
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
return -EINVAL;
}
#endif
tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
return -EINVAL;
}
atk_print_sensor(data, obj);
return 0;
}
#ifdef DEBUG
static char const *atk_sensor_type(union acpi_object *flags)
{
u64 type = flags->integer.value & ATK_TYPE_MASK;
char const *what;
switch (type) {
case HWMON_TYPE_VOLT:
what = "voltage";
break;
case HWMON_TYPE_TEMP:
what = "temperature";
break;
case HWMON_TYPE_FAN:
what = "fan";
break;
default:
what = "unknown";
break;
}
return what;
}
#endif
static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
{
#ifdef DEBUG
struct device *dev = &data->acpi_dev->dev;
union acpi_object *flags;
union acpi_object *name;
union acpi_object *limit1;
union acpi_object *limit2;
union acpi_object *enable;
char const *what;
flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
what = atk_sensor_type(flags);
dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
flags->integer.value,
name->string.pointer,
limit1->integer.value, limit2->integer.value,
enable->integer.value ? "enabled" : "disabled");
#endif
}
static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
{
struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev;
struct acpi_object_list params;
union acpi_object id;
acpi_status status;
acpi_handle method;
switch (sensor->type) {
case HWMON_TYPE_VOLT:
method = data->rvlt_handle;
break;
case HWMON_TYPE_TEMP:
method = data->rtmp_handle;
break;
case HWMON_TYPE_FAN:
method = data->rfan_handle;
break;
default:
return -EINVAL;
}
id.type = ACPI_TYPE_INTEGER;
id.integer.value = sensor->id;
params.count = 1;
params.pointer = &id;
status = acpi_evaluate_integer(method, NULL, ¶ms, value);
if (status != AE_OK) {
dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
acpi_format_exception(status));
return -EIO;
}
return 0;
}
static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
{
struct device *dev = &data->acpi_dev->dev;
struct acpi_buffer buf;
acpi_status ret;
struct acpi_object_list params;
union acpi_object id;
union acpi_object *pack;
id.type = ACPI_TYPE_INTEGER;
id.integer.value = mux;
params.count = 1;
params.pointer = &id;
buf.length = ACPI_ALLOCATE_BUFFER;
ret = acpi_evaluate_object(data->enumerate_handle, NULL, ¶ms, &buf);
if (ret != AE_OK) {
dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
acpi_format_exception(ret));
return ERR_PTR(-EIO);
}
pack = buf.pointer;
if (pack->type != ACPI_TYPE_PACKAGE) {
/* Execution was successful, but the id was not found */
ACPI_FREE(pack);
return ERR_PTR(-ENOENT);
}
if (pack->package.count < 1) {
dev_err(dev, "GGRP[%#x] package is too small\n", mux);
ACPI_FREE(pack);
return ERR_PTR(-EIO);
}
return pack;
}
static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
{
struct device *dev = &data->acpi_dev->dev;
struct atk_acpi_input_buf buf;
union acpi_object tmp;
struct acpi_object_list params;
struct acpi_buffer ret;
union acpi_object *obj;
acpi_status status;
buf.id = id;
buf.param1 = 0;
buf.param2 = 0;
tmp.type = ACPI_TYPE_BUFFER;
tmp.buffer.pointer = (u8 *)&buf;
tmp.buffer.length = sizeof(buf);
params.count = 1;
params.pointer = (void *)&tmp;
ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms,
&ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) {
dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
acpi_format_exception(status));
return ERR_PTR(-EIO);
}
obj = ret.pointer;
/* Sanity check */
if (obj->buffer.length < 8) {
dev_warn(dev, "Unexpected ASBF length: %u\n",
obj->buffer.length);
ACPI_FREE(obj);
return ERR_PTR(-EIO);
}
return obj;
}
static union acpi_object *atk_sitm(struct atk_data *data,
struct atk_acpi_input_buf *buf)
{
struct device *dev = &data->acpi_dev->dev;
struct acpi_object_list params;
union acpi_object tmp;
struct acpi_buffer ret;
union acpi_object *obj;
acpi_status status;
tmp.type = ACPI_TYPE_BUFFER;
tmp.buffer.pointer = (u8 *)buf;
tmp.buffer.length = sizeof(*buf);
params.count = 1;
params.pointer = &tmp;
ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->write_handle, NULL, ¶ms,
&ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) {
dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
acpi_format_exception(status));
return ERR_PTR(-EIO);
}
obj = ret.pointer;
/* Sanity check */
if (obj->buffer.length < 8) {
dev_warn(dev, "Unexpected ASBF length: %u\n",
obj->buffer.length);
ACPI_FREE(obj);
return ERR_PTR(-EIO);
}
return obj;
}
static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
{
struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_ret_buffer *buf;
int err = 0;
obj = atk_gitm(data, sensor->id);
if (IS_ERR(obj))
return PTR_ERR(obj);
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (buf->flags == 0) {
/* The reading is not valid, possible causes:
* - sensor failure
* - enumeration was FUBAR (and we didn't notice)
*/
dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
err = -EIO;
goto out;
}
*value = buf->value;
out:
ACPI_FREE(obj);
return err;
}
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
{
int err;
if (!sensor->is_valid ||
time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
if (sensor->data->old_interface)
err = atk_read_value_old(sensor, value);
else
err = atk_read_value_new(sensor, value);
sensor->is_valid = true;
sensor->last_updated = jiffies;
sensor->cached_value = *value;
} else {
*value = sensor->cached_value;
err = 0;
}
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,
.llseek = no_llseek,
};
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;
union acpi_object *flags;
union acpi_object *name;
union acpi_object *limit1;
union acpi_object *limit2;
union acpi_object *enable;
struct atk_sensor_data *sensor;
char const *base_name;
char const *limit1_name;
char const *limit2_name;
u64 type;
int err;
int *num;
int start;
if (obj->type != ACPI_TYPE_PACKAGE) {
/* wft is this? */
dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
obj->type);
return -EINVAL;
}
err = validate_hwmon_pack(data, obj);
if (err)
return err;
/* Ok, we have a valid hwmon package */
type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
& ATK_TYPE_MASK;
switch (type) {
case HWMON_TYPE_VOLT:
base_name = "in";
limit1_name = "min";
limit2_name = "max";
num = &data->voltage_count;
start = 0;
break;
case HWMON_TYPE_TEMP:
base_name = "temp";
limit1_name = "max";
limit2_name = "crit";
num = &data->temperature_count;
start = 1;
break;
case HWMON_TYPE_FAN:
base_name = "fan";
limit1_name = "min";
limit2_name = "max";
num = &data->fan_count;
start = 1;
break;
default:
dev_warn(dev, "Unknown sensor type: %#llx\n", type);
return -EINVAL;
}
enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
if (!enable->integer.value)
/* sensor is disabled */
return 0;
flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return -ENOMEM;
sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
if (!sensor->acpi_name) {
err = -ENOMEM;
goto out;
}
INIT_LIST_HEAD(&sensor->list);
sensor->type = type;
sensor->data = data;
sensor->id = flags->integer.value;
sensor->limit1 = limit1->integer.value;
if (data->old_interface)
sensor->limit2 = limit2->integer.value;
else
/* The upper limit is expressed as delta from lower limit */
sensor->limit2 = sensor->limit1 + limit2->integer.value;
snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
"%s%d_input", base_name, start + *num);
atk_init_attribute(&sensor->input_attr,
sensor->input_attr_name,
atk_input_show);
snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
"%s%d_label", base_name, start + *num);
atk_init_attribute(&sensor->label_attr,
sensor->label_attr_name,
atk_label_show);
snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
"%s%d_%s", base_name, start + *num, limit1_name);
atk_init_attribute(&sensor->limit1_attr,
sensor->limit1_attr_name,
atk_limit1_show);
snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
"%s%d_%s", base_name, start + *num, limit2_name);
atk_init_attribute(&sensor->limit2_attr,
sensor->limit2_attr_name,
atk_limit2_show);
list_add(&sensor->list, &data->sensor_list);
(*num)++;
return 1;
out:
kfree(sensor->acpi_name);
kfree(sensor);
return err;
}
static int atk_enumerate_old_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
struct acpi_buffer buf;
union acpi_object *pack;
acpi_status status;
int i, ret;
int count = 0;
/* Voltages */
buf.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->atk_handle,
METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
if (status != AE_OK) {
dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
pack = buf.pointer;
for (i = 1; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_add_sensor(data, obj);
if (ret > 0)
count++;
}
ACPI_FREE(buf.pointer);
/* Temperatures */
buf.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->atk_handle,
METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
if (status != AE_OK) {
dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
acpi_format_exception(status));
ret = -ENODEV;
goto cleanup;
}
pack = buf.pointer;
for (i = 1; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_add_sensor(data, obj);
if (ret > 0)
count++;
}
ACPI_FREE(buf.pointer);
/* Fans */
buf.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->atk_handle,
METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
if (status != AE_OK) {
dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
acpi_format_exception(status));
ret = -ENODEV;
goto cleanup;
}
pack = buf.pointer;
for (i = 1; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_add_sensor(data, obj);
if (ret > 0)
count++;
}
ACPI_FREE(buf.pointer);
return count;
cleanup:
atk_free_sensors(data);
return ret;
}
static int atk_ec_present(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *pack;
union acpi_object *ec;
int ret;
int i;
pack = atk_ggrp(data, ATK_MUX_MGMT);
if (IS_ERR(pack)) {
if (PTR_ERR(pack) == -ENOENT) {
/* The MGMT class does not exists - that's ok */
dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
return 0;
}
return PTR_ERR(pack);
}
/* Search the EC */
ec = NULL;
for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
union acpi_object *id;
if (obj->type != ACPI_TYPE_PACKAGE)
continue;
id = &obj->package.elements[0];
if (id->type != ACPI_TYPE_INTEGER)
continue;
if (id->integer.value == ATK_EC_ID) {
ec = obj;
break;
}
}
ret = (ec != NULL);
if (!ret)
/* The system has no EC */
dev_dbg(dev, "EC not found\n");
ACPI_FREE(pack);
return ret;
}
static int atk_ec_enabled(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_ret_buffer *buf;
int err;
obj = atk_gitm(data, ATK_EC_ID);
if (IS_ERR(obj)) {
dev_err(dev, "Unable to query EC status\n");
return PTR_ERR(obj);
}
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (buf->flags == 0) {
dev_err(dev, "Unable to query EC status\n");
err = -EIO;
} else {
err = (buf->value != 0);
dev_dbg(dev, "EC is %sabled\n",
err ? "en" : "dis");
}
ACPI_FREE(obj);
return err;
}
static int atk_ec_ctl(struct atk_data *data, int enable)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_input_buf sitm;
struct atk_acpi_ret_buffer *ec_ret;
int err = 0;
sitm.id = ATK_EC_ID;
sitm.param1 = enable;
sitm.param2 = 0;
obj = atk_sitm(data, &sitm);
if (IS_ERR(obj)) {
dev_err(dev, "Failed to %sable the EC\n",
enable ? "en" : "dis");
return PTR_ERR(obj);
}
ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (ec_ret->flags == 0) {
dev_err(dev, "Failed to %sable the EC\n",
enable ? "en" : "dis");
err = -EIO;
} else {
dev_info(dev, "EC %sabled\n",
enable ? "en" : "dis");
}
ACPI_FREE(obj);
return err;
}
static int atk_enumerate_new_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *pack;
int err;
int i;
err = atk_ec_present(data);
if (err < 0)
return err;
if (err) {
err = atk_ec_enabled(data);
if (err < 0)
return err;
/* If the EC was disabled we will disable it again on unload */
data->disable_ec = err;
err = atk_ec_ctl(data, 1);
if (err) {
data->disable_ec = false;
return err;
}
}
dev_dbg(dev, "Enumerating hwmon sensors\n");
pack = atk_ggrp(data, ATK_MUX_HWMON);
if (IS_ERR(pack))
return PTR_ERR(pack);
for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
atk_add_sensor(data, obj);
}
err = data->voltage_count + data->temperature_count + data->fan_count;
ACPI_FREE(pack);
return err;
}
static int atk_create_files(struct atk_data *data)
{
struct atk_sensor_data *s;
int err;
list_for_each_entry(s, &data->sensor_list, list) {
sysfs_attr_init(&s->input_attr.attr);
err = device_create_file(data->hwmon_dev, &s->input_attr);
if (err)
return err;
sysfs_attr_init(&s->label_attr.attr);
err = device_create_file(data->hwmon_dev, &s->label_attr);
if (err)
return err;
sysfs_attr_init(&s->limit1_attr.attr);
err = device_create_file(data->hwmon_dev, &s->limit1_attr);
if (err)
return err;
sysfs_attr_init(&s->limit2_attr.attr);
err = device_create_file(data->hwmon_dev, &s->limit2_attr);
if (err)
return err;
}
err = device_create_file(data->hwmon_dev, &atk_name_attr);
return err;
}
static void atk_remove_files(struct atk_data *data)
{
struct atk_sensor_data *s;
list_for_each_entry(s, &data->sensor_list, list) {
device_remove_file(data->hwmon_dev, &s->input_attr);
device_remove_file(data->hwmon_dev, &s->label_attr);
device_remove_file(data->hwmon_dev, &s->limit1_attr);
device_remove_file(data->hwmon_dev, &s->limit2_attr);
}
device_remove_file(data->hwmon_dev, &atk_name_attr);
}
static void atk_free_sensors(struct atk_data *data)
{
struct list_head *head = &data->sensor_list;
struct atk_sensor_data *s, *tmp;
list_for_each_entry_safe(s, tmp, head, list) {
kfree(s->acpi_name);
kfree(s);
}
}
static int atk_register_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
int err;
dev_dbg(dev, "registering hwmon device\n");
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev))
return PTR_ERR(data->hwmon_dev);
dev_dbg(dev, "populating sysfs directory\n");
err = atk_create_files(data);
if (err)
goto remove;
return 0;
remove:
/* Cleanup the registered files */
atk_remove_files(data);
hwmon_device_unregister(data->hwmon_dev);
return err;
}
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 (ACPI_SUCCESS(status))
data->rtmp_handle = ret;
else
dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
acpi_format_exception(status));
/* RVLT: read voltage */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
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));
/* RFAN: read fan status */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
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));
/* Enumeration */
status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
if (ACPI_SUCCESS(status))
data->enumerate_handle = ret;
else
dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
acpi_format_exception(status));
/* De-multiplexer (read) */
status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
if (ACPI_SUCCESS(status))
data->read_handle = ret;
else
dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
acpi_format_exception(status));
/* De-multiplexer (write) */
status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
if (ACPI_SUCCESS(status))
data->write_handle = ret;
else
dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
acpi_format_exception(status));
/* 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 (new_if)
dev_info(dev, "Overriding interface detection\n");
if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if)
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)
{
acpi_status ret;
int err;
struct acpi_buffer buf;
union acpi_object *obj;
struct atk_data *data;
dev_dbg(&device->dev, "adding...\n");
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->acpi_dev = device;
data->atk_handle = device->handle;
INIT_LIST_HEAD(&data->sensor_list);
data->disable_ec = false;
buf.length = ACPI_ALLOCATE_BUFFER;
ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
&buf, ACPI_TYPE_PACKAGE);
if (ret != AE_OK) {
dev_dbg(&device->dev, "atk: method MBIF not found\n");
} else {
obj = buf.pointer;
if (obj->package.count >= 2) {
union acpi_object *id = &obj->package.elements[1];
if (id->type == ACPI_TYPE_STRING)
dev_dbg(&device->dev, "board ID = %s\n",
id->string.pointer);
}
ACPI_FREE(buf.pointer);
}
err = atk_probe_if(data);
if (err) {
dev_err(&device->dev, "No usable hwmon interface detected\n");
goto out;
}
if (data->old_interface) {
dev_dbg(&device->dev, "Using old hwmon interface\n");
err = atk_enumerate_old_hwmon(data);
} else {
dev_dbg(&device->dev, "Using new hwmon interface\n");
err = atk_enumerate_new_hwmon(data);
}
if (err < 0)
goto out;
if (err == 0) {
dev_info(&device->dev,
"No usable sensor detected, bailing out\n");
err = -ENODEV;
goto out;
}
err = atk_register_hwmon(data);
if (err)
goto cleanup;
atk_debugfs_init(data);
device->driver_data = data;
return 0;
cleanup:
atk_free_sensors(data);
out:
if (data->disable_ec)
atk_ec_ctl(data, 0);
kfree(data);
return err;
}
static int atk_remove(struct acpi_device *device, int type)
{
struct atk_data *data = device->driver_data;
dev_dbg(&device->dev, "removing...\n");
device->driver_data = NULL;
atk_debugfs_cleanup(data);
atk_remove_files(data);
atk_free_sensors(data);
hwmon_device_unregister(data->hwmon_dev);
if (data->disable_ec) {
if (atk_ec_ctl(data, 0))
dev_err(&device->dev, "Failed to disable EC\n");
}
kfree(data);
return 0;
}
static int __init atk0110_init(void)
{
int ret;
/* Make sure it's safe to access the device through ACPI */
if (!acpi_resources_are_enforced()) {
pr_err("atk: Resources not safely usable due to "
"acpi_enforce_resources kernel parameter\n");
return -EBUSY;
}
ret = acpi_bus_register_driver(&atk_driver);
if (ret)
pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
return ret;
}
static void __exit atk0110_exit(void)
{
acpi_bus_unregister_driver(&atk_driver);
}
module_init(atk0110_init);
module_exit(atk0110_exit);
MODULE_LICENSE("GPL");
[-- Attachment #3: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (6 preceding siblings ...)
2011-01-10 15:25 ` Luca Tettamanti
@ 2011-01-10 18:48 ` Joris Creyghton
2011-01-10 18:56 ` Jean Delvare
` (10 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-10 18:48 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 1108 bytes --]
On Mon, 2011-01-10 at 16:25 +0100, Luca Tettamanti wrote:
> On Wed, Jan 5, 2011 at 3:08 PM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> > To complicate things the firmware provides both the old and the new
> > ATK0110 interfaces, and the driver selects the old one. The new one
> > seems to have the code to read all the sensors. I'll see what I can
> > do.
>
> I'm attaching a modified version of the driver; I've added a parameter
> to override the default detection logic, to test load it with new_if=1
>
> Luca
Hello Luca,
Thank you for your work on the driver.
I really would like to test it ASAP, but I don't know how.
I'm a Linux newbie so I'm afraid I must ask you a recipe for this task.
Maybe you can point me to some links where the necessary steps are
explained.
I'm familiar with the process of compiling and linking to obtain
executable code but have no experience in testing drivers in Linux.
I'm planning to add an empty disc to my system and install a fresh
Ubuntu 10.10 64 bit desktop on it just for test purposes and to make
sure that I won't blow up my regular system.
Joris
[-- Attachment #1.2: Type: text/html, Size: 1480 bytes --]
[-- Attachment #2: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (7 preceding siblings ...)
2011-01-10 18:48 ` Joris Creyghton
@ 2011-01-10 18:56 ` Jean Delvare
2011-01-10 20:01 ` Joris Creyghton
` (9 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jean Delvare @ 2011-01-10 18:56 UTC (permalink / raw)
To: lm-sensors
Hi Joris,
On Mon, 10 Jan 2011 19:48:38 +0100, Joris Creyghton wrote:
> Thank you for your work on the driver.
> I really would like to test it ASAP, but I don't know how.
> I'm a Linux newbie so I'm afraid I must ask you a recipe for this task.
> Maybe you can point me to some links where the necessary steps are
> explained.
> I'm familiar with the process of compiling and linking to obtain
> executable code but have no experience in testing drivers in Linux.
>
> I'm planning to add an empty disc to my system and install a fresh
> Ubuntu 10.10 64 bit desktop on it just for test purposes and to make
> sure that I won't blow up my regular system.
You can pick any example Makefile on my site, e.g.:
http://khali.linux-fr.org/devel/misc/w83795/Makefile
Change
DRIVER := w83795
to
DRIVER := asus_atk0110
put both files in a temporary directory, then type "make". You'll need
make, gcc and configured kernel headers installed. When the build is
successful, you can test the module as root with:
# rmmod asus_atk0110
# insmod ./asus_atk0110.ko
Hope that helps,
--
Jean Delvare
http://khali.linux-fr.org/wishlist.html
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (8 preceding siblings ...)
2011-01-10 18:56 ` Jean Delvare
@ 2011-01-10 20:01 ` Joris Creyghton
2011-01-11 14:07 ` Joris Creyghton
` (8 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-10 20:01 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 1395 bytes --]
On Mon, 2011-01-10 at 19:56 +0100, Jean Delvare wrote:
> Hi Joris,
>
> On Mon, 10 Jan 2011 19:48:38 +0100, Joris Creyghton wrote:
> > Thank you for your work on the driver.
> > I really would like to test it ASAP, but I don't know how.
> > I'm a Linux newbie so I'm afraid I must ask you a recipe for this task.
> > Maybe you can point me to some links where the necessary steps are
> > explained.
> > I'm familiar with the process of compiling and linking to obtain
> > executable code but have no experience in testing drivers in Linux.
> >
> > I'm planning to add an empty disc to my system and install a fresh
> > Ubuntu 10.10 64 bit desktop on it just for test purposes and to make
> > sure that I won't blow up my regular system.
>
> You can pick any example Makefile on my site, e.g.:
> http://khali.linux-fr.org/devel/misc/w83795/Makefile
>
> Change
> DRIVER := w83795
> to
> DRIVER := asus_atk0110
>
> put both files in a temporary directory, then type "make". You'll need
> make, gcc and configured kernel headers installed. When the build is
> successful, you can test the module as root with:
>
> # rmmod asus_atk0110
> # insmod ./asus_atk0110.ko
>
> Hope that helps,
Bon soir Jean,
Thank you for your suggestions!
I'll install the new disk and dummy system tomorrow morning and then try
your recipe.
I'll report the results or return with some more questions.
Joris
[-- Attachment #1.2: Type: text/html, Size: 1748 bytes --]
[-- Attachment #2: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (9 preceding siblings ...)
2011-01-10 20:01 ` Joris Creyghton
@ 2011-01-11 14:07 ` Joris Creyghton
2011-01-11 14:23 ` Luca Tettamanti
` (7 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-11 14:07 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 899 bytes --]
Hello Luca,
With your modified version of the driver I have been able to test the
new ATK0110 interface and it indeed delivers a proper value of the MCH
temperature! The recipe of Jean Delvare was invaluable for me.
I have attached the output of the sensors command in both the old and
the new situations.
Now there remains the point of incorporating things properly, so that
one doesn't have to manually re-make the object with every new version
of the kernel headers.
Another point that drew my attention is that the two ATK0110 interfaces
don't agree on the naming of the fan sensors as you can tell from the
two attachments.
Both display 4 fan's, they agree about the CPU fan, but the new
interface assigns one value to a NB fan (North Bridge =? Memory Control
Hub (MCH)). There is no such fan on the Sabertooth board. There are 2
chassis fans and a power fan though.
Thanks so far,
Joris
[-- Attachment #1.2: Type: text/html, Size: 1184 bytes --]
[-- Attachment #2: sensors_new.txt --]
[-- Type: text/plain, Size: 734 bytes --]
atk0110-acpi-0
Adapter: ACPI interface
Vcore Voltage: +0.93 V (min = +0.80 V, max = +1.60 V)
+3.3V Voltage: +3.31 V (min = +2.97 V, max = +3.63 V)
+5V Voltage: +5.12 V (min = +4.50 V, max = +5.50 V)
+12V Voltage: +12.25 V (min = +10.20 V, max = +13.80 V)
CPU Fan Speed: 1028 RPM (min = 600 RPM)
Chassis1 Fan Speed: 680 RPM (min = 600 RPM)
Chassis2 Fan Speed: 496 RPM (min = 600 RPM)
NB Fan Speed: 777 RPM (min = 600 RPM)
Power Fan Speed: 0 RPM (min = 0 RPM)
CPU Temperature: +35.0°C (high = +60.0°C, crit = +95.0°C)
MB Temperature: +32.0°C (high = +45.0°C, crit = +75.0°C)
NB Temperature: +44.5°C (high = +60.0°C, crit = +95.0°C)
[-- Attachment #3: sensors_old.txt --]
[-- Type: text/plain, Size: 734 bytes --]
atk0110-acpi-0
Adapter: ACPI interface
Vcore Voltage: +0.93 V (min = +0.80 V, max = +1.60 V)
+3.3 Voltage: +3.31 V (min = +2.97 V, max = +3.63 V)
+5 Voltage: +5.12 V (min = +4.50 V, max = +5.50 V)
+12 Voltage: +12.25 V (min = +10.20 V, max = +13.80 V)
CPU FAN Speed: 948 RPM (min = 600 RPM)
CHASSIS1 FAN Speed: 680 RPM (min = 600 RPM)
CHASSIS2 FAN Speed: 496 RPM (min = 600 RPM)
CHASSIS3 FAN Speed: 0 RPM (min = 600 RPM)
POWER FAN Speed: 774 RPM (min = 0 RPM)
CPU Temperature: +35.5°C (high = +60.0°C, crit = +75.0°C)
MB Temperature: +32.0°C (high = +45.0°C, crit = +75.0°C)
MCH Temperature: +0.0°C (high = +60.0°C, crit = +95.0°C)
[-- Attachment #4: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (10 preceding siblings ...)
2011-01-11 14:07 ` Joris Creyghton
@ 2011-01-11 14:23 ` Luca Tettamanti
2011-01-12 14:03 ` Luca Tettamanti
` (6 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-11 14:23 UTC (permalink / raw)
To: lm-sensors
On Tue, Jan 11, 2011 at 3:07 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> Another point that drew my attention is that the two ATK0110 interfaces
> don't agree on the naming of the fan sensors as you can tell from the two
> attachments.
Sigh.
> Both display 4 fan's, they agree about the CPU fan, but the new interface
> assigns one value to a NB fan (North Bridge =? Memory Control Hub (MCH)).
> There is no such fan on the Sabertooth board. There are 2 chassis fans and a
> power fan though.
The names are supplied by the BIOS, so this is another bug.
HWF2 is named "CHASSIS3" in the old interface and "Power" in the new.
HWF4 is "POWER" in the old interface but "NB" in the new one.
They probably swapped the labels... you can try and raise the issue with Asus.
Luca
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (11 preceding siblings ...)
2011-01-11 14:23 ` Luca Tettamanti
@ 2011-01-12 14:03 ` Luca Tettamanti
2011-01-12 14:15 ` Jean Delvare
` (5 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-12 14:03 UTC (permalink / raw)
To: lm-sensors
On Tue, Jan 11, 2011 at 3:23 PM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> On Tue, Jan 11, 2011 at 3:07 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
>> Both display 4 fan's, they agree about the CPU fan, but the new interface
>> assigns one value to a NB fan (North Bridge =? Memory Control Hub (MCH)).
>> There is no such fan on the Sabertooth board. There are 2 chassis fans and a
>> power fan though.
>
> The names are supplied by the BIOS, so this is another bug.
> HWF2 is named "CHASSIS3" in the old interface and "Power" in the new.
> HWF4 is "POWER" in the old interface but "NB" in the new one.
> They probably swapped the labels... you can try and raise the issue with Asus.
Oh, BTW: is there an updated BIOS for the board? This issue should be
visible also under Windows... I guess someone should have noticed.
It might make sense to let the user override the labels, Jean what do you think?
Joris, can you also send me the output of dmidecode?
L
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (12 preceding siblings ...)
2011-01-12 14:03 ` Luca Tettamanti
@ 2011-01-12 14:15 ` Jean Delvare
2011-01-12 14:30 ` Luca Tettamanti
` (4 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jean Delvare @ 2011-01-12 14:15 UTC (permalink / raw)
To: lm-sensors
On Wed, 12 Jan 2011 15:03:31 +0100, Luca Tettamanti wrote:
> On Tue, Jan 11, 2011 at 3:23 PM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> > On Tue, Jan 11, 2011 at 3:07 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> >> Both display 4 fan's, they agree about the CPU fan, but the new interface
> >> assigns one value to a NB fan (North Bridge =? Memory Control Hub (MCH)).
> >> There is no such fan on the Sabertooth board. There are 2 chassis fans and a
> >> power fan though.
> >
> > The names are supplied by the BIOS, so this is another bug.
> > HWF2 is named "CHASSIS3" in the old interface and "Power" in the new.
> > HWF4 is "POWER" in the old interface but "NB" in the new one.
> > They probably swapped the labels... you can try and raise the issue with Asus.
>
> Oh, BTW: is there an updated BIOS for the board? This issue should be
> visible also under Windows... I guess someone should have noticed.
> It might make sense to let the user override the labels, Jean what do you think?
It is already possible. Driver-provided labels are only a hint and a
bonus, it is still possible to specify labels in the traditional way
with a sensors3.conf file, for example:
chip "asus_atk0110-*"
label fan4 "Chassis Fan 3"
Such definitions take precedence over driver-provided labels.
> Joris, can you also send me the output of dmidecode?
--
Jean Delvare
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (13 preceding siblings ...)
2011-01-12 14:15 ` Jean Delvare
@ 2011-01-12 14:30 ` Luca Tettamanti
2011-01-12 15:01 ` Joris Creyghton
` (3 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-12 14:30 UTC (permalink / raw)
To: lm-sensors
On Wed, Jan 12, 2011 at 3:15 PM, Jean Delvare <khali@linux-fr.org> wrote:
> On Wed, 12 Jan 2011 15:03:31 +0100, Luca Tettamanti wrote:
>> It might make sense to let the user override the labels, Jean what do you think?
>
> It is already possible. Driver-provided labels are only a hint and a
> bonus, it is still possible to specify labels in the traditional way
> with a sensors3.conf file, for example:
[cut]
Ah, of course :) I was thinking about overwriting directly the sysfs
entry, but it's unnecessary.
Luca
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (14 preceding siblings ...)
2011-01-12 14:30 ` Luca Tettamanti
@ 2011-01-12 15:01 ` Joris Creyghton
2011-01-17 12:49 ` Luca Tettamanti
` (2 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-12 15:01 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 1804 bytes --]
On Wed, 2011-01-12 at 15:03 +0100, Luca Tettamanti wrote:
> On Tue, Jan 11, 2011 at 3:23 PM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> > On Tue, Jan 11, 2011 at 3:07 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> >> Both display 4 fan's, they agree about the CPU fan, but the new interface
> >> assigns one value to a NB fan (North Bridge =? Memory Control Hub (MCH)).
> >> There is no such fan on the Sabertooth board. There are 2 chassis fans and a
> >> power fan though.
> >
> > The names are supplied by the BIOS, so this is another bug.
> > HWF2 is named "CHASSIS3" in the old interface and "Power" in the new.
> > HWF4 is "POWER" in the old interface but "NB" in the new one.
> > They probably swapped the labels... you can try and raise the issue with Asus.
>
> Oh, BTW: is there an updated BIOS for the board? This issue should be
> visible also under Windows... I guess someone should have noticed.
> It might make sense to let the user override the labels, Jean what do you think?
>
> Joris, can you also send me the output of dmidecode?
>
> L
Hi Luca,
I have attached the output of dmidecode of the unmodified system.
I have also looked into the BIOS output, and the assignment of the fans
corresponds with the output of the sensors command on the system with
the new driver.
I read them from the BIOS screen output:
CPU fan 927
Chassis fan 1 629
Chassis fan 2 484
Power fan [N/A]
NB fan 760
I have the latest BIOS version (0603) for the Sabertooth X58 board.
However, the Asus site has a 2010/11/09 update with the same version
number, while mine says build date 10/29/10.
I don't know if there is any difference between the two.
I'm prepaired to look into that, if you think that makes sense.
[-- Attachment #1.2: Type: text/html, Size: 2484 bytes --]
[-- Attachment #2: dmidecode.txt --]
[-- Type: text/plain, Size: 23042 bytes --]
# dmidecode 2.9
SMBIOS 2.5 present.
80 structures occupying 3027 bytes.
Table at 0x000F0700.
Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
Vendor: American Megatrends Inc.
Version: 0603
Release Date: 10/29/2010
Address: 0xF0000
Runtime Size: 64 kB
ROM Size: 2048 kB
Characteristics:
ISA is supported
PCI is supported
PNP is supported
APM is supported
BIOS is upgradeable
BIOS shadowing is allowed
ESCD support is available
Boot from CD is supported
Selectable boot is supported
BIOS ROM is socketed
EDD is supported
5.25"/1.2 MB floppy services are supported (int 13h)
3.5"/720 KB floppy services are supported (int 13h)
3.5"/2.88 MB floppy services are supported (int 13h)
Print screen service is supported (int 5h)
8042 keyboard services are supported (int 9h)
Serial services are supported (int 14h)
Printer services are supported (int 17h)
CGA/mono video services are supported (int 10h)
ACPI is supported
USB legacy is supported
LS-120 boot is supported
ATAPI Zip drive boot is supported
BIOS boot specification is supported
Targeted content distribution is supported
BIOS Revision: 8.15
Handle 0x0001, DMI type 1, 27 bytes
System Information
Manufacturer: System manufacturer
Product Name: System Product Name
Version: System Version
Serial Number: System Serial Number
UUID: C0A1001F-C600-0007-10D5-BCAEC519E749
Wake-up Type: Power Switch
SKU Number: To Be Filled By O.E.M.
Family: To Be Filled By O.E.M.
Handle 0x0002, DMI type 2, 15 bytes
Base Board Information
Manufacturer: ASUSTeK Computer INC.
Product Name: SABERTOOTH X58
Version: Rev 1.xx
Serial Number: 107765870002617
Asset Tag: To Be Filled By O.E.M.
Features:
Board is a hosting board
Board is replaceable
Location In Chassis: To Be Filled By O.E.M.
Chassis Handle: 0x0003
Type: Motherboard
Contained Object Handles: 0
Handle 0x0003, DMI type 3, 21 bytes
Chassis Information
Manufacturer: Chassis Manufacture
Type: Desktop
Lock: Not Present
Version: Chassis Version
Serial Number: Chassis Serial Number
Asset Tag: Asset-1234567890
Boot-up State: Safe
Power Supply State: Safe
Thermal State: Safe
Security Status: None
OEM Information: 0x00000001
Height: Unspecified
Number Of Power Cords: 1
Contained Elements: 0
Handle 0x0004, DMI type 4, 40 bytes
Processor Information
Socket Designation: LGA1366
Type: Central Processor
Family: <OUT OF SPEC>
Manufacturer: Intel
ID: A5 06 01 00 FF FB EB BF
Version: Intel(R) Core(TM) i7 CPU 950 @ 3.07GHz
Voltage: 1.2 V
External Clock: 133 MHz
Max Speed: 3066 MHz
Current Speed: 3066 MHz
Status: Populated, Enabled
Upgrade: Other
L1 Cache Handle: 0x0005
L2 Cache Handle: 0x0006
L3 Cache Handle: 0x0007
Serial Number: To Be Filled By O.E.M.
Asset Tag: To Be Filled By O.E.M.
Part Number: To Be Filled By O.E.M.
Core Count: 4
Core Enabled: 4
Thread Count: 8
Characteristics:
64-bit capable
Handle 0x0005, DMI type 7, 19 bytes
Cache Information
Socket Designation: L1-Cache
Configuration: Enabled, Not Socketed, Level 1
Operational Mode: Write Through
Location: Internal
Installed Size: 256 KB
Maximum Size: 256 KB
Supported SRAM Types:
Other
Installed SRAM Type: Other
Speed: Unknown
Error Correction Type: Parity
System Type: Instruction
Associativity: 4-way Set-associative
Handle 0x0006, DMI type 7, 19 bytes
Cache Information
Socket Designation: L2-Cache
Configuration: Enabled, Not Socketed, Level 2
Operational Mode: Write Through
Location: Internal
Installed Size: 1024 KB
Maximum Size: 1024 KB
Supported SRAM Types:
Other
Installed SRAM Type: Other
Speed: Unknown
Error Correction Type: Single-bit ECC
System Type: Unified
Associativity: 8-way Set-associative
Handle 0x0007, DMI type 7, 19 bytes
Cache Information
Socket Designation: L3-Cache
Configuration: Enabled, Not Socketed, Level 3
Operational Mode: Write Back
Location: Internal
Installed Size: 8192 KB
Maximum Size: 8192 KB
Supported SRAM Types:
Other
Installed SRAM Type: Other
Speed: Unknown
Error Correction Type: Single-bit ECC
System Type: Unified
Associativity: 16-way Set-associative
Handle 0x0008, DMI type 5, 28 bytes
Memory Controller Information
Error Detecting Method: 64-bit ECC
Error Correcting Capabilities:
None
Supported Interleave: One-way Interleave
Current Interleave: One-way Interleave
Maximum Memory Module Size: 4096 MB
Maximum Total Memory Size: 24576 MB
Supported Speeds:
70 ns
60 ns
Supported Memory Types:
DIMM
SDRAM
Memory Module Voltage: 3.3 V
Associated Memory Slots: 6
0x0009
0x000A
0x000B
0x000C
0x000D
0x000E
Enabled Error Correcting Capabilities:
None
Handle 0x0009, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: DIMM0
Bank Connections: 1
Current Speed: 1 ns
Type: DIMM
Installed Size: 2048 MB (Single-bank Connection)
Enabled Size: 2048 MB (Single-bank Connection)
Error Status: OK
Handle 0x000A, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: DIMM1
Bank Connections: 2
Current Speed: 1 ns
Type: DIMM
Installed Size: 2048 MB (Single-bank Connection)
Enabled Size: 2048 MB (Single-bank Connection)
Error Status: OK
Handle 0x000B, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: DIMM2
Bank Connections: 3
Current Speed: 1 ns
Type: DIMM
Installed Size: 2048 MB (Single-bank Connection)
Enabled Size: 2048 MB (Single-bank Connection)
Error Status: OK
Handle 0x000C, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: DIMM3
Bank Connections: 4
Current Speed: 1 ns
Type: DIMM
Installed Size: 2048 MB (Single-bank Connection)
Enabled Size: 2048 MB (Single-bank Connection)
Error Status: OK
Handle 0x000D, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: DIMM4
Bank Connections: 5
Current Speed: 1 ns
Type: DIMM
Installed Size: 2048 MB (Single-bank Connection)
Enabled Size: 2048 MB (Single-bank Connection)
Error Status: OK
Handle 0x000E, DMI type 6, 12 bytes
Memory Module Information
Socket Designation: DIMM5
Bank Connections: 6
Current Speed: 1 ns
Type: DIMM
Installed Size: 2048 MB (Single-bank Connection)
Enabled Size: 2048 MB (Single-bank Connection)
Error Status: OK
Handle 0x000F, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: PS/2 Keyboard
Internal Connector Type: None
External Reference Designator: PS/2 Keyboard
External Connector Type: PS/2
Port Type: Keyboard Port
Handle 0x0010, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: PS/2 Mouse
Internal Connector Type: None
External Reference Designator: PS/2 Mouse
External Connector Type: PS/2
Port Type: Mouse Port
Handle 0x0011, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB12
Internal Connector Type: None
External Reference Designator: USB12
External Connector Type: Access Bus (USB)
Port Type: USB
Handle 0x0012, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB34
Internal Connector Type: None
External Reference Designator: USB34
External Connector Type: Access Bus (USB)
Port Type: USB
Handle 0x0013, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB_3_12
Internal Connector Type: None
External Reference Designator: USB56
External Connector Type: Access Bus (USB)
Port Type: USB
Handle 0x0014, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: IE1394_1
Internal Connector Type: None
External Reference Designator: IEEE1394 1
External Connector Type: IEEE 1394
Port Type: Firewire (IEEE P1394)
Handle 0x0015, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: LAN1
Internal Connector Type: None
External Reference Designator: GbE LAN 1
External Connector Type: RJ-45
Port Type: Network Port
Handle 0x0016, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: AUDIO
Internal Connector Type: None
External Reference Designator: AUDIO
External Connector Type: Other
Port Type: Audio Port
Handle 0x0017, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: Audio Line Out1
Internal Connector Type: None
External Reference Designator: Audio Line Out1
External Connector Type: Mini Jack (headphones)
Port Type: Audio Port
Handle 0x0018, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: Audio Line Out2
Internal Connector Type: None
External Reference Designator: Audio Line Out2
External Connector Type: Mini Jack (headphones)
Port Type: Audio Port
Handle 0x0019, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: Audio Line Out3
Internal Connector Type: None
External Reference Designator: Audio Line Out3
External Connector Type: Mini Jack (headphones)
Port Type: Audio Port
Handle 0x001A, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: Audio Line Out4
Internal Connector Type: None
External Reference Designator: Audio Line Out4
External Connector Type: Mini Jack (headphones)
Port Type: Audio Port
Handle 0x001B, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: Audio Line Out5
Internal Connector Type: None
External Reference Designator: Audio Line Out5
External Connector Type: Mini Jack (headphones)
Port Type: Audio Port
Handle 0x001C, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: Audio Line Out6
Internal Connector Type: None
External Reference Designator: Audio Line Out6
External Connector Type: Mini Jack (headphones)
Port Type: Audio Port
Handle 0x001D, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: F_ESATA
Internal Connector Type: None
External Reference Designator: F_ESATA
External Connector Type: SAS/SATA Plug Receptacle
Port Type: SATA
Handle 0x001E, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: ESATA
Internal Connector Type: None
External Reference Designator: ESATA
External Connector Type: SAS/SATA Plug Receptacle
Port Type: SATA
Handle 0x001F, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA1
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0020, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA2
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0021, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA3
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0022, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA4
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0023, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA5
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0024, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA6
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0025, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA_6G_1
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0026, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SATA_6G_2
Internal Connector Type: SAS/SATA Plug Receptacle
External Reference Designator: Not Specified
External Connector Type: None
Port Type: SATA
Handle 0x0027, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB56
Internal Connector Type: Access Bus (USB)
External Reference Designator: Not Specified
External Connector Type: None
Port Type: USB
Handle 0x0028, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB78
Internal Connector Type: Access Bus (USB)
External Reference Designator: Not Specified
External Connector Type: None
Port Type: USB
Handle 0x0029, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB910
Internal Connector Type: Access Bus (USB)
External Reference Designator: Not Specified
External Connector Type: None
Port Type: USB
Handle 0x002A, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: USB1112
Internal Connector Type: Access Bus (USB)
External Reference Designator: Not Specified
External Connector Type: None
Port Type: USB
Handle 0x002B, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: IE1394_2
Internal Connector Type: IEEE 1394
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Firewire (IEEE P1394)
Handle 0x002C, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: AAFP
Internal Connector Type: Mini Jack (headphones)
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Audio Port
Handle 0x002D, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: CPU_FAN
Internal Connector Type: Other
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Other
Handle 0x002E, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: PWR_FAN
Internal Connector Type: Other
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Other
Handle 0x002F, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: CHA_FAN1
Internal Connector Type: Other
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Other
Handle 0x0030, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: CHA_FAN2
Internal Connector Type: Other
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Other
Handle 0x0031, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: CHA_FAN3
Internal Connector Type: Other
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Other
Handle 0x0032, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: NB_FAN
Internal Connector Type: Other
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Other
Handle 0x0033, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: SPDIF_OUT
Internal Connector Type: On Board Sound Input From CD-ROM
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Audio Port
Handle 0x0034, DMI type 8, 9 bytes
Port Connector Information
Internal Reference Designator: FP_AUDIO
Internal Connector Type: On Board Sound Input From CD-ROM
External Reference Designator: Not Specified
External Connector Type: None
Port Type: Audio Port
Handle 0x0035, DMI type 9, 13 bytes
System Slot Information
Designation: PCIEX1_1
Type: 64-bit PCI Express
Current Usage: In Use
Length: Short
ID: 1
Characteristics:
3.3 V is provided
Opening is shared
PME signal is supported
Handle 0x0036, DMI type 9, 13 bytes
System Slot Information
Designation: PCIEX1_2
Type: 32-bit PCI Express
Current Usage: In Use
Length: Short
ID: 2
Characteristics:
3.3 V is provided
Opening is shared
PME signal is supported
Handle 0x0037, DMI type 9, 13 bytes
System Slot Information
Designation: PCI1
Type: 32-bit PCI
Current Usage: Available
Length: Short
ID: 3
Characteristics:
3.3 V is provided
Opening is shared
PME signal is supported
Handle 0x0038, DMI type 9, 13 bytes
System Slot Information
Designation: PCIEX16_1
Type: 32-bit PCI
Current Usage: Available
Length: Short
ID: 4
Characteristics:
3.3 V is provided
Opening is shared
PME signal is supported
Handle 0x0039, DMI type 9, 13 bytes
System Slot Information
Designation: PCIEX16_2
Type: 32-bit PCI Express
Current Usage: Available
Length: Short
ID: 5
Characteristics:
3.3 V is provided
Opening is shared
PME signal is supported
Handle 0x003A, DMI type 9, 13 bytes
System Slot Information
Designation: PCIEX16_3
Type: 32-bit PCI Express
Current Usage: Available
Length: Short
ID: 6
Characteristics:
3.3 V is provided
Opening is shared
PME signal is supported
Handle 0x003B, DMI type 10, 6 bytes
On Board Device Information
Type: Ethernet
Status: Enabled
Description: Onboard Ethernet
Handle 0x003C, DMI type 11, 5 bytes
OEM Strings
String 1: To Be Filled By O.E.M.
String 2: To Be Filled By O.E.M.
String 3: To Be Filled By O.E.M.
String 4: To Be Filled By O.E.M.
Handle 0x003D, DMI type 13, 22 bytes
BIOS Language Information
Installable Languages: 6
en|US|iso8859-1
zh|ZH|iso8859-1
de|DE|iso8859-1
cn|CN|iso8859-1
fr|FR|iso8859-1
ja|JP|unicode-1
Currently Installed Language: en|US|iso8859-1
Handle 0x003E, DMI type 15, 55 bytes
System Event Log
Area Length: 1008 bytes
Header Start Offset: 0x2010
Data Start Offset: 0x2010
Access Method: OEM-specific
Access Address: Unknown
Status: Valid, Not Full
Change Token: 0x00000000
Header Format: No Header
Supported Log Type Descriptors: 1
Descriptor 1: OEM-specific
Data Format 1: POST results bitmap
Handle 0x003F, DMI type 16, 15 bytes
Physical Memory Array
Location: System Board Or Motherboard
Use: System Memory
Error Correction Type: Multi-bit ECC
Maximum Capacity: 24 GB
Error Information Handle: Not Provided
Number Of Devices: 6
Handle 0x0040, DMI type 19, 15 bytes
Memory Array Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Array Handle: 0x003F
Partition Width: 0
Handle 0x0041, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x003F
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM0
Bank Locator: BANK0
Type: Other
Type Detail: Other
Speed: 1066 MHz (0.9 ns)
Manufacturer: Manufacturer00
Serial Number: SerNum00
Asset Tag: AssetTagNum0
Part Number: ModulePartNumber00
Handle 0x0042, DMI type 20, 19 bytes
Memory Device Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Device Handle: 0x0041
Memory Array Mapped Address Handle: 0x0040
Partition Row Position: 1
Interleave Position: Unknown
Interleaved Data Depth: 2
Handle 0x0043, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x003F
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM1
Bank Locator: BANK1
Type: Other
Type Detail: Other
Speed: 1066 MHz (0.9 ns)
Manufacturer: Manufacturer01
Serial Number: SerNum01
Asset Tag: AssetTagNum1
Part Number: ModulePartNumber01
Handle 0x0044, DMI type 20, 19 bytes
Memory Device Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Device Handle: 0x0043
Memory Array Mapped Address Handle: 0x0040
Partition Row Position: 1
Interleave Position: Unknown
Interleaved Data Depth: 2
Handle 0x0045, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x003F
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM2
Bank Locator: BANK2
Type: Other
Type Detail: Other
Speed: 1066 MHz (0.9 ns)
Manufacturer: Manufacturer02
Serial Number: SerNum02
Asset Tag: AssetTagNum2
Part Number: ModulePartNumber02
Handle 0x0046, DMI type 20, 19 bytes
Memory Device Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Device Handle: 0x0045
Memory Array Mapped Address Handle: 0x0040
Partition Row Position: 1
Interleave Position: Unknown
Interleaved Data Depth: 2
Handle 0x0047, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x003F
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM3
Bank Locator: BANK3
Type: Other
Type Detail: Other
Speed: 1066 MHz (0.9 ns)
Manufacturer: Manufacturer03
Serial Number: SerNum03
Asset Tag: AssetTagNum3
Part Number: ModulePartNumber03
Handle 0x0048, DMI type 20, 19 bytes
Memory Device Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Device Handle: 0x0047
Memory Array Mapped Address Handle: 0x0040
Partition Row Position: 1
Interleave Position: Unknown
Interleaved Data Depth: 2
Handle 0x0049, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x003F
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM4
Bank Locator: BANK4
Type: Other
Type Detail: Other
Speed: 1066 MHz (0.9 ns)
Manufacturer: Manufacturer04
Serial Number: SerNum04
Asset Tag: AssetTagNum4
Part Number: ModulePartNumber04
Handle 0x004A, DMI type 20, 19 bytes
Memory Device Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Device Handle: 0x0049
Memory Array Mapped Address Handle: 0x0040
Partition Row Position: 1
Interleave Position: Unknown
Interleaved Data Depth: 2
Handle 0x004B, DMI type 17, 27 bytes
Memory Device
Array Handle: 0x003F
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM5
Bank Locator: BANK5
Type: Other
Type Detail: Other
Speed: 1066 MHz (0.9 ns)
Manufacturer: Manufacturer05
Serial Number: SerNum05
Asset Tag: AssetTagNum5
Part Number: ModulePartNumber05
Handle 0x004C, DMI type 20, 19 bytes
Memory Device Mapped Address
Starting Address: 0x00000000000
Ending Address: 0x000000003FF
Range Size: 1 kB
Physical Device Handle: 0x004B
Memory Array Mapped Address Handle: 0x0040
Partition Row Position: 1
Interleave Position: Unknown
Interleaved Data Depth: 2
Handle 0x004D, DMI type 32, 20 bytes
System Boot Information
Status: No errors detected
Handle 0x004E, DMI type 139, 54 bytes
OEM-specific Type
Header and Data:
8B 36 4E 00 00 1F C6 00 00 07 10 D5 04 04 32 55
F8 00 A2 02 A1 00 40 63 43 10 FE 81 03 DF 40 B2
00 20 00 73 3C 10 08 00 00 00 00 00 00 00 00 00
00 00 00 00 00 01
Strings:
V1394GUID
Handle 0x004F, DMI type 127, 4 bytes
End Of Table
[-- Attachment #3: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (15 preceding siblings ...)
2011-01-12 15:01 ` Joris Creyghton
@ 2011-01-17 12:49 ` Luca Tettamanti
2011-01-17 20:17 ` Joris Creyghton
2011-01-18 14:40 ` Luca Tettamanti
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-17 12:49 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1: Type: text/plain, Size: 593 bytes --]
On Wed, Jan 12, 2011 at 4:01 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> I have attached the output of dmidecode of the unmodified system.
Sorry for the delay :)
I've updated the driver to automatically select the correct interface
on your board.
Compile and load it without any additional parameter.
> I have the latest BIOS version (0603) for the Sabertooth X58 board.
> However, the Asus site has a 2010/11/09 update with the same version number,
> while mine says build date 10/29/10.
> I don't know if there is any difference between the two.
Nah, they should be the same.
Luca
[-- Attachment #2: asus_atk0110.c --]
[-- Type: text/x-csrc, Size: 33916 bytes --]
/*
* Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
*
* This file is released under the GPLv2
* See COPYING in the top level directory of the kernel tree.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define DEBUG
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include <acpi/acpi.h>
#include <acpi/acpixf.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#define ATK_HID "ATK0110"
static bool new_if;
module_param(new_if, bool, 0);
MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
static const struct dmi_system_id __initconst atk_force_new_if[] = {
{
/* Old interface has broken fan monitoring */
.ident = "Asus Sabertooth X58",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
}
},
{ }
};
/* Minimum time between readings, enforced in order to avoid
* hogging the CPU.
*/
#define CACHE_TIME HZ
#define BOARD_ID "MBIF"
#define METHOD_ENUMERATE "GGRP"
#define METHOD_READ "GITM"
#define METHOD_WRITE "SITM"
#define METHOD_OLD_READ_TMP "RTMP"
#define METHOD_OLD_READ_VLT "RVLT"
#define METHOD_OLD_READ_FAN "RFAN"
#define METHOD_OLD_ENUM_TMP "TSIF"
#define METHOD_OLD_ENUM_VLT "VSIF"
#define METHOD_OLD_ENUM_FAN "FSIF"
#define ATK_MUX_HWMON 0x00000006ULL
#define ATK_MUX_MGMT 0x00000011ULL
#define ATK_CLASS_MASK 0xff000000ULL
#define ATK_CLASS_FREQ_CTL 0x03000000ULL
#define ATK_CLASS_FAN_CTL 0x04000000ULL
#define ATK_CLASS_HWMON 0x06000000ULL
#define ATK_CLASS_MGMT 0x11000000ULL
#define ATK_TYPE_MASK 0x00ff0000ULL
#define HWMON_TYPE_VOLT 0x00020000ULL
#define HWMON_TYPE_TEMP 0x00030000ULL
#define HWMON_TYPE_FAN 0x00040000ULL
#define ATK_ELEMENT_ID_MASK 0x0000ffffULL
#define ATK_EC_ID 0x11060004ULL
enum atk_pack_member {
HWMON_PACK_FLAGS,
HWMON_PACK_NAME,
HWMON_PACK_LIMIT1,
HWMON_PACK_LIMIT2,
HWMON_PACK_ENABLE
};
/* New package format */
#define _HWMON_NEW_PACK_SIZE 7
#define _HWMON_NEW_PACK_FLAGS 0
#define _HWMON_NEW_PACK_NAME 1
#define _HWMON_NEW_PACK_UNK1 2
#define _HWMON_NEW_PACK_UNK2 3
#define _HWMON_NEW_PACK_LIMIT1 4
#define _HWMON_NEW_PACK_LIMIT2 5
#define _HWMON_NEW_PACK_ENABLE 6
/* Old package format */
#define _HWMON_OLD_PACK_SIZE 5
#define _HWMON_OLD_PACK_FLAGS 0
#define _HWMON_OLD_PACK_NAME 1
#define _HWMON_OLD_PACK_LIMIT1 2
#define _HWMON_OLD_PACK_LIMIT2 3
#define _HWMON_OLD_PACK_ENABLE 4
struct atk_data {
struct device *hwmon_dev;
acpi_handle atk_handle;
struct acpi_device *acpi_dev;
bool old_interface;
/* old interface */
acpi_handle rtmp_handle;
acpi_handle rvlt_handle;
acpi_handle rfan_handle;
/* new inteface */
acpi_handle enumerate_handle;
acpi_handle read_handle;
acpi_handle write_handle;
bool disable_ec;
int voltage_count;
int temperature_count;
int fan_count;
struct list_head sensor_list;
struct {
struct dentry *root;
u32 id;
} debugfs;
};
typedef ssize_t (*sysfs_show_func)(struct device *dev,
struct device_attribute *attr, char *buf);
static const struct acpi_device_id atk_ids[] = {
{ATK_HID, 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, atk_ids);
#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
struct atk_sensor_data {
struct list_head list;
struct atk_data *data;
struct device_attribute label_attr;
struct device_attribute input_attr;
struct device_attribute limit1_attr;
struct device_attribute limit2_attr;
char label_attr_name[ATTR_NAME_SIZE];
char input_attr_name[ATTR_NAME_SIZE];
char limit1_attr_name[ATTR_NAME_SIZE];
char limit2_attr_name[ATTR_NAME_SIZE];
u64 id;
u64 type;
u64 limit1;
u64 limit2;
u64 cached_value;
unsigned long last_updated; /* in jiffies */
bool is_valid;
char const *acpi_name;
};
/* Return buffer format:
* [0-3] "value" is valid flag
* [4-7] value
* [8- ] unknown stuff on newer mobos
*/
struct atk_acpi_ret_buffer {
u32 flags;
u32 value;
u8 data[];
};
/* Input buffer used for GITM and SITM methods */
struct atk_acpi_input_buf {
u32 id;
u32 param1;
u32 param2;
};
static int atk_add(struct acpi_device *device);
static int atk_remove(struct acpi_device *device, int type);
static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
static void atk_free_sensors(struct atk_data *data);
static struct acpi_driver atk_driver = {
.name = ATK_HID,
.class = "hwmon",
.ids = atk_ids,
.ops = {
.add = atk_add,
.remove = atk_remove,
},
};
#define input_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, input_attr)
#define label_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, label_attr)
#define limit1_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, limit1_attr)
#define limit2_to_atk_sensor(attr) \
container_of(attr, struct atk_sensor_data, limit2_attr)
static ssize_t atk_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = input_to_atk_sensor(attr);
u64 value;
int err;
err = atk_read_value(s, &value);
if (err)
return err;
if (s->type == HWMON_TYPE_TEMP)
/* ACPI returns decidegree */
value *= 100;
return sprintf(buf, "%llu\n", value);
}
static ssize_t atk_label_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = label_to_atk_sensor(attr);
return sprintf(buf, "%s\n", s->acpi_name);
}
static ssize_t atk_limit1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
u64 value = s->limit1;
if (s->type == HWMON_TYPE_TEMP)
value *= 100;
return sprintf(buf, "%lld\n", value);
}
static ssize_t atk_limit2_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
u64 value = s->limit2;
if (s->type == HWMON_TYPE_TEMP)
value *= 100;
return sprintf(buf, "%lld\n", value);
}
static ssize_t atk_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "atk0110\n");
}
static struct device_attribute atk_name_attr =
__ATTR(name, 0444, atk_name_show, NULL);
static void atk_init_attribute(struct device_attribute *attr, char *name,
sysfs_show_func show)
{
attr->attr.name = name;
attr->attr.mode = 0444;
attr->show = show;
attr->store = NULL;
}
static union acpi_object *atk_get_pack_member(struct atk_data *data,
union acpi_object *pack,
enum atk_pack_member m)
{
bool old_if = data->old_interface;
int offset;
switch (m) {
case HWMON_PACK_FLAGS:
offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
break;
case HWMON_PACK_NAME:
offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
break;
case HWMON_PACK_LIMIT1:
offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
_HWMON_NEW_PACK_LIMIT1;
break;
case HWMON_PACK_LIMIT2:
offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
_HWMON_NEW_PACK_LIMIT2;
break;
case HWMON_PACK_ENABLE:
offset = old_if ? _HWMON_OLD_PACK_ENABLE :
_HWMON_NEW_PACK_ENABLE;
break;
default:
return NULL;
}
return &pack->package.elements[offset];
}
/* New package format is:
* - flag (int)
* class - used for de-muxing the request to the correct GITn
* type (volt, temp, fan)
* sensor id |
* sensor id - used for de-muxing the request _inside_ the GITn
* - name (str)
* - unknown (int)
* - unknown (int)
* - limit1 (int)
* - limit2 (int)
* - enable (int)
*
* The old package has the same format but it's missing the two unknown fields.
*/
static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *tmp;
bool old_if = data->old_interface;
int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
_HWMON_NEW_PACK_SIZE;
if (obj->type != ACPI_TYPE_PACKAGE) {
dev_warn(dev, "Invalid type: %d\n", obj->type);
return -EINVAL;
}
if (obj->package.count != expected_size) {
dev_warn(dev, "Invalid package size: %d, expected: %d\n",
obj->package.count, expected_size);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
if (tmp->type != ACPI_TYPE_STRING) {
dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
return -EINVAL;
}
/* Don't check... we don't know what they're useful for anyway */
#if 0
tmp = &obj->package.elements[HWMON_PACK_UNK1];
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
return -EINVAL;
}
tmp = &obj->package.elements[HWMON_PACK_UNK2];
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
return -EINVAL;
}
#endif
tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
return -EINVAL;
}
tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
if (tmp->type != ACPI_TYPE_INTEGER) {
dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
return -EINVAL;
}
atk_print_sensor(data, obj);
return 0;
}
#ifdef DEBUG
static char const *atk_sensor_type(union acpi_object *flags)
{
u64 type = flags->integer.value & ATK_TYPE_MASK;
char const *what;
switch (type) {
case HWMON_TYPE_VOLT:
what = "voltage";
break;
case HWMON_TYPE_TEMP:
what = "temperature";
break;
case HWMON_TYPE_FAN:
what = "fan";
break;
default:
what = "unknown";
break;
}
return what;
}
#endif
static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
{
#ifdef DEBUG
struct device *dev = &data->acpi_dev->dev;
union acpi_object *flags;
union acpi_object *name;
union acpi_object *limit1;
union acpi_object *limit2;
union acpi_object *enable;
char const *what;
flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
what = atk_sensor_type(flags);
dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
flags->integer.value,
name->string.pointer,
limit1->integer.value, limit2->integer.value,
enable->integer.value ? "enabled" : "disabled");
#endif
}
static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
{
struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev;
struct acpi_object_list params;
union acpi_object id;
acpi_status status;
acpi_handle method;
switch (sensor->type) {
case HWMON_TYPE_VOLT:
method = data->rvlt_handle;
break;
case HWMON_TYPE_TEMP:
method = data->rtmp_handle;
break;
case HWMON_TYPE_FAN:
method = data->rfan_handle;
break;
default:
return -EINVAL;
}
id.type = ACPI_TYPE_INTEGER;
id.integer.value = sensor->id;
params.count = 1;
params.pointer = &id;
status = acpi_evaluate_integer(method, NULL, ¶ms, value);
if (status != AE_OK) {
dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
acpi_format_exception(status));
return -EIO;
}
return 0;
}
static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
{
struct device *dev = &data->acpi_dev->dev;
struct acpi_buffer buf;
acpi_status ret;
struct acpi_object_list params;
union acpi_object id;
union acpi_object *pack;
id.type = ACPI_TYPE_INTEGER;
id.integer.value = mux;
params.count = 1;
params.pointer = &id;
buf.length = ACPI_ALLOCATE_BUFFER;
ret = acpi_evaluate_object(data->enumerate_handle, NULL, ¶ms, &buf);
if (ret != AE_OK) {
dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
acpi_format_exception(ret));
return ERR_PTR(-EIO);
}
pack = buf.pointer;
if (pack->type != ACPI_TYPE_PACKAGE) {
/* Execution was successful, but the id was not found */
ACPI_FREE(pack);
return ERR_PTR(-ENOENT);
}
if (pack->package.count < 1) {
dev_err(dev, "GGRP[%#x] package is too small\n", mux);
ACPI_FREE(pack);
return ERR_PTR(-EIO);
}
return pack;
}
static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
{
struct device *dev = &data->acpi_dev->dev;
struct atk_acpi_input_buf buf;
union acpi_object tmp;
struct acpi_object_list params;
struct acpi_buffer ret;
union acpi_object *obj;
acpi_status status;
buf.id = id;
buf.param1 = 0;
buf.param2 = 0;
tmp.type = ACPI_TYPE_BUFFER;
tmp.buffer.pointer = (u8 *)&buf;
tmp.buffer.length = sizeof(buf);
params.count = 1;
params.pointer = (void *)&tmp;
ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms,
&ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) {
dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
acpi_format_exception(status));
return ERR_PTR(-EIO);
}
obj = ret.pointer;
/* Sanity check */
if (obj->buffer.length < 8) {
dev_warn(dev, "Unexpected ASBF length: %u\n",
obj->buffer.length);
ACPI_FREE(obj);
return ERR_PTR(-EIO);
}
return obj;
}
static union acpi_object *atk_sitm(struct atk_data *data,
struct atk_acpi_input_buf *buf)
{
struct device *dev = &data->acpi_dev->dev;
struct acpi_object_list params;
union acpi_object tmp;
struct acpi_buffer ret;
union acpi_object *obj;
acpi_status status;
tmp.type = ACPI_TYPE_BUFFER;
tmp.buffer.pointer = (u8 *)buf;
tmp.buffer.length = sizeof(*buf);
params.count = 1;
params.pointer = &tmp;
ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->write_handle, NULL, ¶ms,
&ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) {
dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
acpi_format_exception(status));
return ERR_PTR(-EIO);
}
obj = ret.pointer;
/* Sanity check */
if (obj->buffer.length < 8) {
dev_warn(dev, "Unexpected ASBF length: %u\n",
obj->buffer.length);
ACPI_FREE(obj);
return ERR_PTR(-EIO);
}
return obj;
}
static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
{
struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_ret_buffer *buf;
int err = 0;
obj = atk_gitm(data, sensor->id);
if (IS_ERR(obj))
return PTR_ERR(obj);
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (buf->flags == 0) {
/* The reading is not valid, possible causes:
* - sensor failure
* - enumeration was FUBAR (and we didn't notice)
*/
dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
err = -EIO;
goto out;
}
*value = buf->value;
out:
ACPI_FREE(obj);
return err;
}
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
{
int err;
if (!sensor->is_valid ||
time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
if (sensor->data->old_interface)
err = atk_read_value_old(sensor, value);
else
err = atk_read_value_new(sensor, value);
sensor->is_valid = true;
sensor->last_updated = jiffies;
sensor->cached_value = *value;
} else {
*value = sensor->cached_value;
err = 0;
}
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,
.llseek = no_llseek,
};
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;
union acpi_object *flags;
union acpi_object *name;
union acpi_object *limit1;
union acpi_object *limit2;
union acpi_object *enable;
struct atk_sensor_data *sensor;
char const *base_name;
char const *limit1_name;
char const *limit2_name;
u64 type;
int err;
int *num;
int start;
if (obj->type != ACPI_TYPE_PACKAGE) {
/* wft is this? */
dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
obj->type);
return -EINVAL;
}
err = validate_hwmon_pack(data, obj);
if (err)
return err;
/* Ok, we have a valid hwmon package */
type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
& ATK_TYPE_MASK;
switch (type) {
case HWMON_TYPE_VOLT:
base_name = "in";
limit1_name = "min";
limit2_name = "max";
num = &data->voltage_count;
start = 0;
break;
case HWMON_TYPE_TEMP:
base_name = "temp";
limit1_name = "max";
limit2_name = "crit";
num = &data->temperature_count;
start = 1;
break;
case HWMON_TYPE_FAN:
base_name = "fan";
limit1_name = "min";
limit2_name = "max";
num = &data->fan_count;
start = 1;
break;
default:
dev_warn(dev, "Unknown sensor type: %#llx\n", type);
return -EINVAL;
}
enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
if (!enable->integer.value)
/* sensor is disabled */
return 0;
flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return -ENOMEM;
sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
if (!sensor->acpi_name) {
err = -ENOMEM;
goto out;
}
INIT_LIST_HEAD(&sensor->list);
sensor->type = type;
sensor->data = data;
sensor->id = flags->integer.value;
sensor->limit1 = limit1->integer.value;
if (data->old_interface)
sensor->limit2 = limit2->integer.value;
else
/* The upper limit is expressed as delta from lower limit */
sensor->limit2 = sensor->limit1 + limit2->integer.value;
snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
"%s%d_input", base_name, start + *num);
atk_init_attribute(&sensor->input_attr,
sensor->input_attr_name,
atk_input_show);
snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
"%s%d_label", base_name, start + *num);
atk_init_attribute(&sensor->label_attr,
sensor->label_attr_name,
atk_label_show);
snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
"%s%d_%s", base_name, start + *num, limit1_name);
atk_init_attribute(&sensor->limit1_attr,
sensor->limit1_attr_name,
atk_limit1_show);
snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
"%s%d_%s", base_name, start + *num, limit2_name);
atk_init_attribute(&sensor->limit2_attr,
sensor->limit2_attr_name,
atk_limit2_show);
list_add(&sensor->list, &data->sensor_list);
(*num)++;
return 1;
out:
kfree(sensor->acpi_name);
kfree(sensor);
return err;
}
static int atk_enumerate_old_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
struct acpi_buffer buf;
union acpi_object *pack;
acpi_status status;
int i, ret;
int count = 0;
/* Voltages */
buf.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->atk_handle,
METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
if (status != AE_OK) {
dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
acpi_format_exception(status));
return -ENODEV;
}
pack = buf.pointer;
for (i = 1; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_add_sensor(data, obj);
if (ret > 0)
count++;
}
ACPI_FREE(buf.pointer);
/* Temperatures */
buf.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->atk_handle,
METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
if (status != AE_OK) {
dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
acpi_format_exception(status));
ret = -ENODEV;
goto cleanup;
}
pack = buf.pointer;
for (i = 1; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_add_sensor(data, obj);
if (ret > 0)
count++;
}
ACPI_FREE(buf.pointer);
/* Fans */
buf.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->atk_handle,
METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
if (status != AE_OK) {
dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
acpi_format_exception(status));
ret = -ENODEV;
goto cleanup;
}
pack = buf.pointer;
for (i = 1; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
ret = atk_add_sensor(data, obj);
if (ret > 0)
count++;
}
ACPI_FREE(buf.pointer);
return count;
cleanup:
atk_free_sensors(data);
return ret;
}
static int atk_ec_present(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *pack;
union acpi_object *ec;
int ret;
int i;
pack = atk_ggrp(data, ATK_MUX_MGMT);
if (IS_ERR(pack)) {
if (PTR_ERR(pack) == -ENOENT) {
/* The MGMT class does not exists - that's ok */
dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
return 0;
}
return PTR_ERR(pack);
}
/* Search the EC */
ec = NULL;
for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
union acpi_object *id;
if (obj->type != ACPI_TYPE_PACKAGE)
continue;
id = &obj->package.elements[0];
if (id->type != ACPI_TYPE_INTEGER)
continue;
if (id->integer.value == ATK_EC_ID) {
ec = obj;
break;
}
}
ret = (ec != NULL);
if (!ret)
/* The system has no EC */
dev_dbg(dev, "EC not found\n");
ACPI_FREE(pack);
return ret;
}
static int atk_ec_enabled(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_ret_buffer *buf;
int err;
obj = atk_gitm(data, ATK_EC_ID);
if (IS_ERR(obj)) {
dev_err(dev, "Unable to query EC status\n");
return PTR_ERR(obj);
}
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (buf->flags == 0) {
dev_err(dev, "Unable to query EC status\n");
err = -EIO;
} else {
err = (buf->value != 0);
dev_dbg(dev, "EC is %sabled\n",
err ? "en" : "dis");
}
ACPI_FREE(obj);
return err;
}
static int atk_ec_ctl(struct atk_data *data, int enable)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *obj;
struct atk_acpi_input_buf sitm;
struct atk_acpi_ret_buffer *ec_ret;
int err = 0;
sitm.id = ATK_EC_ID;
sitm.param1 = enable;
sitm.param2 = 0;
obj = atk_sitm(data, &sitm);
if (IS_ERR(obj)) {
dev_err(dev, "Failed to %sable the EC\n",
enable ? "en" : "dis");
return PTR_ERR(obj);
}
ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (ec_ret->flags == 0) {
dev_err(dev, "Failed to %sable the EC\n",
enable ? "en" : "dis");
err = -EIO;
} else {
dev_info(dev, "EC %sabled\n",
enable ? "en" : "dis");
}
ACPI_FREE(obj);
return err;
}
static int atk_enumerate_new_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
union acpi_object *pack;
int err;
int i;
err = atk_ec_present(data);
if (err < 0)
return err;
if (err) {
err = atk_ec_enabled(data);
if (err < 0)
return err;
/* If the EC was disabled we will disable it again on unload */
data->disable_ec = err;
err = atk_ec_ctl(data, 1);
if (err) {
data->disable_ec = false;
return err;
}
}
dev_dbg(dev, "Enumerating hwmon sensors\n");
pack = atk_ggrp(data, ATK_MUX_HWMON);
if (IS_ERR(pack))
return PTR_ERR(pack);
for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
atk_add_sensor(data, obj);
}
err = data->voltage_count + data->temperature_count + data->fan_count;
ACPI_FREE(pack);
return err;
}
static int atk_create_files(struct atk_data *data)
{
struct atk_sensor_data *s;
int err;
list_for_each_entry(s, &data->sensor_list, list) {
sysfs_attr_init(&s->input_attr.attr);
err = device_create_file(data->hwmon_dev, &s->input_attr);
if (err)
return err;
sysfs_attr_init(&s->label_attr.attr);
err = device_create_file(data->hwmon_dev, &s->label_attr);
if (err)
return err;
sysfs_attr_init(&s->limit1_attr.attr);
err = device_create_file(data->hwmon_dev, &s->limit1_attr);
if (err)
return err;
sysfs_attr_init(&s->limit2_attr.attr);
err = device_create_file(data->hwmon_dev, &s->limit2_attr);
if (err)
return err;
}
err = device_create_file(data->hwmon_dev, &atk_name_attr);
return err;
}
static void atk_remove_files(struct atk_data *data)
{
struct atk_sensor_data *s;
list_for_each_entry(s, &data->sensor_list, list) {
device_remove_file(data->hwmon_dev, &s->input_attr);
device_remove_file(data->hwmon_dev, &s->label_attr);
device_remove_file(data->hwmon_dev, &s->limit1_attr);
device_remove_file(data->hwmon_dev, &s->limit2_attr);
}
device_remove_file(data->hwmon_dev, &atk_name_attr);
}
static void atk_free_sensors(struct atk_data *data)
{
struct list_head *head = &data->sensor_list;
struct atk_sensor_data *s, *tmp;
list_for_each_entry_safe(s, tmp, head, list) {
kfree(s->acpi_name);
kfree(s);
}
}
static int atk_register_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
int err;
dev_dbg(dev, "registering hwmon device\n");
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev))
return PTR_ERR(data->hwmon_dev);
dev_dbg(dev, "populating sysfs directory\n");
err = atk_create_files(data);
if (err)
goto remove;
return 0;
remove:
/* Cleanup the registered files */
atk_remove_files(data);
hwmon_device_unregister(data->hwmon_dev);
return err;
}
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 (ACPI_SUCCESS(status))
data->rtmp_handle = ret;
else
dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
acpi_format_exception(status));
/* RVLT: read voltage */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
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));
/* RFAN: read fan status */
status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
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));
/* Enumeration */
status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
if (ACPI_SUCCESS(status))
data->enumerate_handle = ret;
else
dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
acpi_format_exception(status));
/* De-multiplexer (read) */
status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
if (ACPI_SUCCESS(status))
data->read_handle = ret;
else
dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
acpi_format_exception(status));
/* De-multiplexer (write) */
status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
if (ACPI_SUCCESS(status))
data->write_handle = ret;
else
dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
acpi_format_exception(status));
/* 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 (new_if)
dev_info(dev, "Overriding interface detection\n");
if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if)
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)
{
acpi_status ret;
int err;
struct acpi_buffer buf;
union acpi_object *obj;
struct atk_data *data;
dev_dbg(&device->dev, "adding...\n");
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->acpi_dev = device;
data->atk_handle = device->handle;
INIT_LIST_HEAD(&data->sensor_list);
data->disable_ec = false;
buf.length = ACPI_ALLOCATE_BUFFER;
ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
&buf, ACPI_TYPE_PACKAGE);
if (ret != AE_OK) {
dev_dbg(&device->dev, "atk: method MBIF not found\n");
} else {
obj = buf.pointer;
if (obj->package.count >= 2) {
union acpi_object *id = &obj->package.elements[1];
if (id->type == ACPI_TYPE_STRING)
dev_dbg(&device->dev, "board ID = %s\n",
id->string.pointer);
}
ACPI_FREE(buf.pointer);
}
err = atk_probe_if(data);
if (err) {
dev_err(&device->dev, "No usable hwmon interface detected\n");
goto out;
}
if (data->old_interface) {
dev_dbg(&device->dev, "Using old hwmon interface\n");
err = atk_enumerate_old_hwmon(data);
} else {
dev_dbg(&device->dev, "Using new hwmon interface\n");
err = atk_enumerate_new_hwmon(data);
}
if (err < 0)
goto out;
if (err == 0) {
dev_info(&device->dev,
"No usable sensor detected, bailing out\n");
err = -ENODEV;
goto out;
}
err = atk_register_hwmon(data);
if (err)
goto cleanup;
atk_debugfs_init(data);
device->driver_data = data;
return 0;
cleanup:
atk_free_sensors(data);
out:
if (data->disable_ec)
atk_ec_ctl(data, 0);
kfree(data);
return err;
}
static int atk_remove(struct acpi_device *device, int type)
{
struct atk_data *data = device->driver_data;
dev_dbg(&device->dev, "removing...\n");
device->driver_data = NULL;
atk_debugfs_cleanup(data);
atk_remove_files(data);
atk_free_sensors(data);
hwmon_device_unregister(data->hwmon_dev);
if (data->disable_ec) {
if (atk_ec_ctl(data, 0))
dev_err(&device->dev, "Failed to disable EC\n");
}
kfree(data);
return 0;
}
static int __init atk0110_init(void)
{
int ret;
/* Make sure it's safe to access the device through ACPI */
if (!acpi_resources_are_enforced()) {
pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
return -EBUSY;
}
if (dmi_check_system(atk_force_new_if))
new_if = true;
ret = acpi_bus_register_driver(&atk_driver);
if (ret)
pr_info("acpi_bus_register_driver failed: %d\n", ret);
return ret;
}
static void __exit atk0110_exit(void)
{
acpi_bus_unregister_driver(&atk_driver);
}
module_init(atk0110_init);
module_exit(atk0110_exit);
MODULE_LICENSE("GPL");
[-- Attachment #3: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (16 preceding siblings ...)
2011-01-17 12:49 ` Luca Tettamanti
@ 2011-01-17 20:17 ` Joris Creyghton
2011-01-18 14:40 ` Luca Tettamanti
18 siblings, 0 replies; 20+ messages in thread
From: Joris Creyghton @ 2011-01-17 20:17 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 1237 bytes --]
Hi Luca,
On Mon, 2011-01-17 at 13:49 +0100, Luca Tettamanti wrote:
> Sorry for the delay :)
No problem :-)
> I've updated the driver to automatically select the correct interface
> on your board.
> Compile and load it without any additional parameter.
It's working fine.
I have looked into your source and would like to suggest to change the
comment in line 33, which reads:
/* Old interface has broken fan monitoring */
The main problem with the old interface was that it didn't communicate
the MCH temperature. The MCH happens to be the hottest component on this
MB, so I want to keep an eye on it.
The confusion about the labeling of the different fans is rather
trivial.
There are 6 fan connectors on the MB, all properly labeled. One of them
has the label NB_fan, although there is no North Bridge fan on this
board. That's just careless of Asus. I think I connected one of the
chassis fans to this connector.
So I would suggest that you change the comment in line 33 to:
/* Old interface has broken MCH temperature monitoring */
When you think it is usefull I can verify whether the different fan
connector labels are properly displayed in the BIOS output and in the
output of the sensors command.
Joris
[-- Attachment #1.2: Type: text/html, Size: 1688 bytes --]
[-- Attachment #2: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [lm-sensors] Erratic value of MCH temp. (0C),
2011-01-03 11:07 [lm-sensors] Erratic value of MCH temp. (0C), Joris Creyghton
` (17 preceding siblings ...)
2011-01-17 20:17 ` Joris Creyghton
@ 2011-01-18 14:40 ` Luca Tettamanti
18 siblings, 0 replies; 20+ messages in thread
From: Luca Tettamanti @ 2011-01-18 14:40 UTC (permalink / raw)
To: lm-sensors
On Mon, Jan 17, 2011 at 9:17 PM, Joris Creyghton <jorisctn@gmail.com> wrote:
> It's working fine.
Excellent :) I'll send a patch upstream.
>
> I have looked into your source and would like to suggest to change the
> comment in line 33, which reads:
>
> /* Old interface has broken fan monitoring */
>
> The main problem with the old interface was that it didn't communicate the
> MCH temperature.
Yes, it was a thinko on my part :-)
Luca
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 20+ messages in thread