Merge tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - asus-ec-sensors: Add missed handle for ENOMEM, fix EC read
   intervals, and fix looping over banks while reading from EC

 - occ: validate poll response sensor blocks

 - pmbus/max34440: Block unsupported VIN and IIN limit registers

 - nzxt-kraken3, nzxt-smart2: gigabyte_waterforce, corsair-cpro,
   corsair-psu: Stop device IO before calling hid_hw_stop

* tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: occ: validate poll response sensor blocks
  hwmon: (asus-ec-sensors) add missed handle for ENOMEM
  hwmon: (asus-ec-sensors) fix EC read intervals
  hwmon: (asus-ec-sensors) fix looping over banks while reading from EC
  hwmon: (pmbus/max34440) block unsupported VIN and IIN limit registers
  hwmon: (nzxt-kraken3) Stop device IO before calling hid_hw_stop
  hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop
  hwmon: (gigabyte_waterforce) Stop device IO before calling hid_hw_stop
  hwmon: (corsair-cpro) Stop device IO before calling hid_hw_stop
  hwmon: (corsair-psu) Stop device IO before calling hid_hw_stop
This commit is contained in:
Linus Torvalds
2026-07-21 08:34:39 -07:00
8 changed files with 130 additions and 20 deletions

View File

@@ -1009,7 +1009,7 @@ struct ec_sensors_data {
/* 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;
@@ -1189,7 +1189,7 @@ static int asus_ec_block_read(const struct device *dev,
}
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]),
@@ -1278,13 +1278,12 @@ static int get_cached_value_or_update(const struct device *dev,
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;
@@ -1402,6 +1401,7 @@ static int asus_ec_probe(struct platform_device *pdev)
if (!ec_data)
return -ENOMEM;
ec_data->next_update = INITIAL_JIFFIES;
dev_set_drvdata(dev, ec_data);
ec_data->board_info = pboard_info;
@@ -1495,9 +1495,11 @@ static int asus_ec_probe(struct platform_device *pdev)
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++;
}

View File

@@ -645,6 +645,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
out_hw_close:
hid_hw_close(hdev);
hid_device_io_stop(hdev);
out_hw_stop:
hid_hw_stop(hdev);
return ret;

View File

@@ -822,6 +822,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
fail_and_close:
hid_hw_close(hdev);
hid_device_io_stop(hdev);
fail_and_stop:
hid_hw_stop(hdev);
return ret;

View File

@@ -371,13 +371,15 @@ static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
hid_err(hdev, "hwmon registration failed with %d\n", ret);
goto fail_and_close;
goto fail_and_io_stop;
}
waterforce_debugfs_init(priv);
return 0;
fail_and_io_stop:
hid_device_io_stop(hdev);
fail_and_close:
hid_hw_close(hdev);
fail_and_stop:

View File

@@ -948,7 +948,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
ret = kraken3_init_device(hdev);
if (ret < 0) {
hid_err(hdev, "device init failed with %d\n", ret);
goto fail_and_close;
goto fail_and_stop_io;
}
ret = kraken3_get_fw_ver(hdev);
@@ -960,13 +960,15 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
hid_err(hdev, "hwmon registration failed with %d\n", ret);
goto fail_and_close;
goto fail_and_stop_io;
}
kraken3_debugfs_init(priv, device_name);
return 0;
fail_and_stop_io:
hid_device_io_stop(hdev);
fail_and_close:
hid_hw_close(hdev);
fail_and_stop:

View File

@@ -768,7 +768,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
out_hw_close:
hid_hw_close(hdev);
hid_device_io_stop(hdev);
out_hw_stop:
hid_hw_stop(hdev);
return ret;

View File

@@ -1052,32 +1052,49 @@ static int occ_setup_sensor_attrs(struct occ *occ)
}
/* 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,
@@ -1107,6 +1124,9 @@ static void occ_parse_poll_response(struct occ *occ)
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)
@@ -1138,10 +1158,12 @@ 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,

View File

@@ -88,6 +88,33 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
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);
@@ -244,6 +271,51 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
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)
{
@@ -363,7 +435,9 @@ static struct pmbus_driver_info max34440_info[] = {
.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] = {
@@ -399,7 +473,9 @@ static struct pmbus_driver_info max34440_info[] = {
.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] = {
@@ -433,7 +509,9 @@ static struct pmbus_driver_info max34440_info[] = {
.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] = {
@@ -581,7 +659,9 @@ static struct pmbus_driver_info max34440_info[] = {
.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,
},