Re: [PATCH] asus_atk0110: add support for Asus P7P55D

Luca Tettamanti
2009-09-28T13:17:04Z

On Wed, Sep 23, 2009 at 09:18:45PM -0600, Robert Hancock wrote:
> On Wed, Sep 23, 2009 at 1:12 PM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> > With P7P55D (and newer) boards Asus extended the output buffer (ASBF)
> > making the driver unable to read the data from the sensors.
> > Change the driver to use dynamic buffers (allocated by ACPI core); the
> > return value is cached, so the number of memory allocations is very low.
> >
> > Signed-off-by: Luca Tettamanti <kronos.it@gmail.com>
> > Tested-by: Robert Hancock <hancockrwd@gmail.com>
>
> I just noticed a problem (either with this patch or some other issue
> with the driver on this board): The readings don't seem to be
> updating, I get the same values all the time. (Just now I started
> compiling a kernel and coretemp reports temperatures in the 60 degree
> plus range but atk0110-acpi still reports 35 degrees as it did
> before..)

Hi Robert,
I have a new patch for you :)
It contains the previous changes to handle the bigger ASBF buffer plus a new
method to enable the EC as suggested by Asus. Be sure to compile with
HWMON_DEBUG_CHIP enabled.

diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index fe4fa29..319618d 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -35,18 +35,21 @@
#define METHOD_OLD_ENUM_FAN "FSIF"

#define ATK_MUX_HWMON 0x00000006ULL
+#define ATK_MUX_EC 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 HWMON_SENSOR_ID_MASK 0x0000ffffULL
+#define ELEMENT_ID_MASK 0x0000ffffULL
+#define ATK_EC_ID 0x0004

enum atk_pack_member {
HWMON_PACK_FLAGS,
@@ -89,6 +92,7 @@ struct atk_data {
/* new inteface */
acpi_handle enumerate_handle;
acpi_handle read_handle;
+ acpi_handle write_handle;

int voltage_count;
int temperature_count;
@@ -129,9 +133,21 @@ struct atk_sensor_data {
char const *acpi_name;
};

-struct atk_acpi_buffer_u64 {
- union acpi_object buf;
- u64 value;
+/* 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[];
+};
+
+struct atk_sitm_buffer {
+ u32 id;
+ u32 value1;
+ u32 value2;
};

static int atk_add(struct acpi_device *device);
@@ -446,8 +462,10 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
struct acpi_object_list params;
struct acpi_buffer ret;
union acpi_object id;
- struct atk_acpi_buffer_u64 tmp;
+ union acpi_object *obj;
+ struct atk_acpi_ret_buffer *buf;
acpi_status status;
+ int err = 0;

id.type = ACPI_TYPE_INTEGER;
id.integer.value = sensor->id;
@@ -455,11 +473,7 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
params.count = 1;
params.pointer = &id;

- tmp.buf.type = ACPI_TYPE_BUFFER;
- tmp.buf.buffer.pointer = (u8 *)&tmp.value;
- tmp.buf.buffer.length = sizeof(u64);
- ret.length = sizeof(tmp);
- ret.pointer = &tmp;
+ ret.length = ACPI_ALLOCATE_BUFFER;

status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
&ret, ACPI_TYPE_BUFFER);
@@ -468,23 +482,31 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
acpi_format_exception(status));
return -EIO;
}
+ obj = ret.pointer;

- /* Return buffer format:
- * [0-3] "value" is valid flag
- * [4-7] value
- */
- if (!(tmp.value & 0xffffffff)) {
+ /* Sanity check */
+ if (obj->buffer.length < 8) {
+ dev_warn(dev, "Unexpected ASBF length: %u\n",
+ obj->buffer.length);
+ err = -EIO;
+ goto out;
+ }
+ buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+
+ if (!buf->flags) {
/* The reading is not valid, possible causes:
* - sensor failure
* - enumeration was FUBAR (and we didn't notice)
*/
- dev_info(dev, "Failure: %#llx\n", tmp.value);
- return -EIO;
+ dev_warn(dev, "Failure: %#x\n", buf->flags);
+ err = -EIO;
+ goto out;
}

- *value = (tmp.value & 0xffffffff00000000ULL) >> 32;
-
- return 0;
+ *value = buf->value;
+out:
+ ACPI_FREE(ret.pointer);
+ return err;
}

static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
@@ -713,6 +735,96 @@ cleanup:
return ret;
}

+static int atk_enable_ec(struct atk_data *data)
+{
+ 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;
+ union acpi_object *ec;
+ struct atk_sitm_buffer sitm;
+ int err = 0;
+ u32 ec_ret;
+ int i;
+
+ id.type = ACPI_TYPE_INTEGER;
+ id.integer.value = ATK_MUX_EC;
+ params.count = 1;
+ params.pointer = &id;
+
+ buf.length = ACPI_ALLOCATE_BUFFER;
+ ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
+ if (ret != AE_OK) {
+ dev_warn(dev, METHOD_ENUMERATE ": ACPI exception: %s\n",
+ acpi_format_exception(ret));
+ return -ENODEV;
+ }
+
+ pack = buf.pointer;
+ if (pack->type != ACPI_TYPE_PACKAGE) {
+ /* EC not present in the enumeration - that's ok */
+ dev_dbg(dev, "GGRP: %#llx not found\n", ATK_MUX_EC);
+ goto out;
+ }
+
+ /* Search the EC */
+ ec = NULL;
+ for (i = 0; i < pack->package.count; i++) {
+ union acpi_object *id;
+ union acpi_object *obj = &pack->package.elements[i];
+ if (obj->type != ACPI_TYPE_PACKAGE)
+ continue;
+
+ id = &obj->package.elements[0];
+ if (id->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ if ((id->integer.value & ELEMENT_ID_MASK) == ATK_EC_ID) {
+ ec = obj;
+ break;
+ }
+ }
+ if (ec == NULL) {
+ /* EC not present */
+ dev_dbg(dev, "EC not found\n");
+ goto out;
+ }
+
+ ACPI_FREE(buf.pointer);
+
+ /* Enable */
+ sitm.id = ec->package.elements[0].integer.value & 0xffffffff;
+ sitm.value1 = 1;
+ sitm.value2 = 0;
+ id.type = ACPI_TYPE_BUFFER;
+ id.buffer.pointer = (u8 *)&sitm;
+ id.buffer.length = sizeof(sitm);
+
+ buf.length = ACPI_ALLOCATE_BUFFER;
+
+ ret = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
+ &buf, ACPI_TYPE_BUFFER);
+ if (ret != AE_OK) {
+ /* Failed to enable the EC */
+ dev_warn(dev, "Failed to enable EC: %s\n",
+ acpi_format_exception(ret));
+ err = -ENODEV;
+ goto out;
+ }
+ ec_ret = *(u32 *)(((union acpi_object *)buf.pointer)->buffer.pointer);
+ if (ec_ret == 0) {
+ dev_warn(dev, "Failed to enable EC\n");
+ err = -ENODEV;
+ } else {
+ dev_info(dev, "EC enabled\n");
+ }
+out:
+ ACPI_FREE(buf.pointer);
+ return err;
+}
+
static int atk_enumerate_new_hwmon(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
@@ -724,6 +836,10 @@ static int atk_enumerate_new_hwmon(struct atk_data *data)
int err;
int i;

+ err = atk_enable_ec(data);
+ if (err)
+ return err;
+
dev_dbg(dev, "Enumerating hwmon sensors\n");

id.type = ACPI_TYPE_INTEGER;
@@ -895,6 +1011,15 @@ static int atk_check_new_if(struct atk_data *data)
}
data->read_handle = ret;

+ /* De-multiplexer (write) */
+ status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
+ if (status != AE_OK) {
+ dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
+ acpi_format_exception(status));
+ return -ENODEV;
+ }
+ data->write_handle = ret;
+
return 0;
}

Luca