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@xxxxxxxxx> 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@xxxxxxxxx> > > Tested-by: Robert Hancock <hancockrwd@xxxxxxxxx> > > 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, ¶ms, &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, ¶ms, &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, ¶ms, + &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 _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors