/* sorted list of unique register banks */
u8 banks[ASUS_EC_MAX_BANK + 1];
/* in jiffies */
- unsigned long last_updated;
+ u64 next_update;
struct lock_data lock_data;
/* number of board EC sensors */
u8 nr_sensors;
}
for (ireg = 0; ireg < ec->nr_registers; ireg++) {
reg_bank = register_bank(ec->registers[ireg]);
- if (reg_bank < bank) {
+ if (reg_bank != bank) {
continue;
}
ec_read(register_index(ec->registers[ireg]),
int sensor_index,
struct ec_sensors_data *state, s32 *value)
{
- if (time_after(jiffies, state->last_updated + HZ)) {
+ if (time_after64(get_jiffies_64(), state->next_update)) {
if (update_ec_sensors(dev, state)) {
dev_err(dev, "update_ec_sensors() failure\n");
return -EIO;
}
-
- state->last_updated = jiffies;
+ state->next_update = get_jiffies_64() + HZ;
}
*value = state->sensors[sensor_index].cached_value;
if (!ec_data)
return -ENOMEM;
+ ec_data->next_update = INITIAL_JIFFIES;
dev_set_drvdata(dev, ec_data);
ec_data->board_info = pboard_info;
if (!nr_count[type])
continue;
- asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
- nr_count[type], type,
- hwmon_attributes[type]);
+ status = asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
+ nr_count[type], type,
+ hwmon_attributes[type]);
+ if (status)
+ return status;
*ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;
}
}
/* only need to do this once at startup, as OCC won't change sensors on us */
-static void occ_parse_poll_response(struct occ *occ)
+static int occ_parse_poll_response(struct occ *occ)
{
unsigned int i, old_offset, offset = 0, size = 0;
+ u16 data_length;
struct occ_sensor *sensor;
- struct occ_sensors *sensors = &occ->sensors;
+ struct occ_sensors parsed = {};
+ struct occ_sensors *sensors = &parsed;
struct occ_response *resp = &occ->resp;
struct occ_poll_response *poll =
(struct occ_poll_response *)&resp->data[0];
struct occ_poll_response_header *header = &poll->header;
struct occ_sensor_data_block *block = &poll->block;
+ data_length = get_unaligned_be16(&resp->data_length);
+ if (data_length < sizeof(*header) || data_length > OCC_RESP_DATA_BYTES) {
+ dev_err(occ->bus_dev, "invalid OCC poll response length %u\n",
+ data_length);
+ return -EMSGSIZE;
+ }
+
dev_info(occ->bus_dev, "OCC found, code level: %.16s\n",
header->occ_code_level);
for (i = 0; i < header->num_sensor_data_blocks; ++i) {
block = (struct occ_sensor_data_block *)((u8 *)block + offset);
+ if (size + sizeof(*header) + sizeof(block->header) >
+ data_length) {
+ dev_err(occ->bus_dev,
+ "truncated OCC sensor block header\n");
+ return -EMSGSIZE;
+ }
+
old_offset = offset;
offset = (block->header.num_sensors *
block->header.sensor_length) + sizeof(block->header);
- size += offset;
/* validate all the length/size fields */
- if ((size + sizeof(*header)) >= OCC_RESP_DATA_BYTES) {
- dev_warn(occ->bus_dev, "exceeded response buffer\n");
- return;
+ if (size + sizeof(*header) + offset > data_length) {
+ dev_err(occ->bus_dev,
+ "exceeded OCC poll response length\n");
+ return -EMSGSIZE;
}
+ size += offset;
dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n",
old_offset, offset - 1, block->header.eye_catcher,
dev_dbg(occ->bus_dev, "Max resp size: %u+%zd=%zd\n", size,
sizeof(*header), size + sizeof(*header));
+ occ->sensors = parsed;
+
+ return 0;
}
int occ_active(struct occ *occ, bool active)
goto unlock;
}
- occ->active = true;
occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
- occ_parse_poll_response(occ);
+ rc = occ_parse_poll_response(occ);
+ if (rc)
+ goto unlock;
+ occ->active = true;
rc = occ_setup_sensor_attrs(occ);
if (rc) {
dev_err(occ->bus_dev,
ret = pmbus_read_word_data(client, page, phase,
data->iout_oc_warn_limit);
break;
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_MFR_VIN_MIN:
+ case PMBUS_MFR_VIN_MAX:
+ case PMBUS_IIN_OC_WARN_LIMIT:
+ case PMBUS_IIN_OC_FAULT_LIMIT:
+ case PMBUS_MFR_IIN_MAX:
+ case PMBUS_MFR_VOUT_MIN:
+ case PMBUS_MFR_VOUT_MAX:
+ case PMBUS_IOUT_UC_FAULT_LIMIT:
+ case PMBUS_MFR_IOUT_MAX:
+ case PMBUS_UT_WARN_LIMIT:
+ case PMBUS_UT_FAULT_LIMIT:
+ case PMBUS_MFR_MAX_TEMP_1:
+ /*
+ * MAX34451/ADPM family do not support VIN/IIN limit registers,
+ * manufacturer-specific min/max registers, or undercurrent/
+ * undertemperature fault limits. Accessing these triggers CML
+ * error and asserts ALERT.
+ */
+ if (data->id == max34451 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250)
+ return -ENXIO;
+ ret = -ENODATA;
+ break;
case PMBUS_VIRT_READ_VOUT_MIN:
ret = pmbus_read_word_data(client, page, phase,
MAX34440_MFR_VOUT_MIN);
return ret;
}
+static int max34451_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct max34440_data *data = to_max34440_data(info);
+
+ switch (reg) {
+ case PMBUS_STATUS_BYTE:
+ case PMBUS_STATUS_OTHER:
+ /*
+ * MAX34451/ADPM family do not support STATUS_BYTE or
+ * STATUS_OTHER registers. Accessing them triggers CML
+ * error and asserts ALERT.
+ */
+ if (data->id == max34451 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250)
+ return -ENXIO;
+ return -ENODATA;
+ default:
+ return -ENODATA;
+ }
+}
+
+static int max34451_write_byte_data(struct i2c_client *client, int page,
+ int reg, u8 byte)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct max34440_data *data = to_max34440_data(info);
+
+ switch (reg) {
+ case PMBUS_STATUS_BYTE:
+ case PMBUS_STATUS_OTHER:
+ /*
+ * MAX34451/ADPM family do not support STATUS_BYTE or
+ * STATUS_OTHER registers. Writing to them triggers CML
+ * error and asserts ALERT.
+ */
+ if (data->id == max34451 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250)
+ return -ENXIO;
+ return -ENODATA;
+ default:
+ return -ENODATA;
+ }
+}
+
static int max34451_set_supported_funcs(struct i2c_client *client,
struct max34440_data *data)
{
.func[9] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT,
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
},
[adpm12200] = {
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
.func[14] = PMBUS_HAVE_IOUT,
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
},
[adpm12250] = {
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
.func[14] = PMBUS_HAVE_IOUT,
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
},
[max34440] = {
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
.page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
},