hwmon fixes for v7.2-rc2

- adm1275: Detect coefficient overflow, and prevent reading uninitialized
   stack
 
 - aspeed-g6-pwm-tach: Guard fan RPM calculation against divide-by-zero
 
 - asus_atk0110: Check package count before accessing element
 
 - ltc4283: fix malformed table docs build error
 
 - occ: Unregister sysfs devices outside occ lock to avoid lockdep warning
 
 - pmbus core: Fix passing events to regulator core, and honor vrm_version in
   pmbus_data2reg_vid()
 
 - w83627hf: Remove VID sysfs files on error and remove
 
 - w83793: remove vrm sysfs file on probe failure
 
 - Various: Add missing 'select REGMAP_I2C' to Kconfig
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmpGaa0ACgkQyx8mb86f
 mYGZAw/+JjAS7LyUalHftEL2FCoK+yrTHBE86JZxcf+WDLh52+WSjAeAjbAwmeSv
 2o6lWRPt0BaHSS0dTT5JZ7tCRn8swIdoCUQys8AFDTMNIaLnrgiS3qJLm0WP1I1U
 dLzC2L8DWajeWtyvFPJT0H7Bq7AX/hOpCwJICMu9bPCP1FwafrUgkRCqmWAb2AS9
 vmLrmqGphehRbB47qw0yuoDb1rttCWfWIYqyVyBzy4uJP5XtdJt9+DyQXysP3vCD
 8lAIVxLr8eSSYPjvL15mD7VT5JJwYpiN2VaI/ZwqPpAochvT4BvwirTVzUFe0OF8
 ZxlHX0zQG0EW2SU5hxQ1VlqFi38u4M5qlmf+FSWJyPaxde5PFFtrl6SONy5Dflvi
 IDVPFTm2MS3FWjzGYSswUcAshqI+AtQIhi/9QsO4kME8SSLRdnvTBneGpnVpZHQe
 V2RlnnnhwS2OJK+1yIe7lDyFN7alE+mREB8RnOHlr/yLX8fM3LzzhtnmSKpqo0Aq
 bTYsm+lwd3sefAuxmcrKJ5YLbv41clNQzoMMuhglKqF/HS1eX+WABOE8MVVfGL/V
 CBjFNBw9iIY7H9jTBR+3OMx1tanmUyf4dga/vggzXOhMVRGwUNkaIe+zS/d6iaTr
 GujoVJBXjd0RCHUxxYuvRa+CUkbuUARRUMOrSlYTFQkzaooTlAE=
 =wyCy
 -----END PGP SIGNATURE-----

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

Pull hwmon fixes from Guenter Roeck:

 - adm1275: Detect coefficient overflow, and prevent reading
   uninitialized stack

 - aspeed-g6-pwm-tach: Guard fan RPM calculation against divide-by-zero

 - asus_atk0110: Check package count before accessing element

 - ltc4283: fix malformed table docs build error

 - occ: Unregister sysfs devices outside occ lock to avoid lockdep
   warning

 - pmbus core: Fix passing events to regulator core, and honor
   vrm_version in pmbus_data2reg_vid()

 - w83627hf: Remove VID sysfs files on error and remove

 - w83793: remove vrm sysfs file on probe failure

 - Various: Add missing 'select REGMAP_I2C' to Kconfig

* tag 'hwmon-for-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (aspeed-g6-pwm-tach) Guard fan RPM calculation against divide-by-zero
  hwmon: (pmbus) Fix passing events to regulator core
  hwmon: adm1275: Detect coefficient overflow
  hwmon: adm1275: Prevent reading uninitialized stack
  hwmon: (max6697) add missing 'select REGMAP_I2C' to Kconfig
  hwmon: (ltc2992) add missing 'select REGMAP_I2C' to Kconfig
  hwmon: (max1619) add missing 'select REGMAP' to Kconfig
  hwmon: (w83627hf) remove VID sysfs files on error and remove
  hwmon: (w83793) remove vrm sysfs file on probe failure
  hwmon: (asus_atk0110) Check package count before accessing element
  docs: hwmon: ltc4283: fix malformed table docs build error
  hwmon: (pmbus/core) honor vrm_version in pmbus_data2reg_vid()
  hwmon: (occ) unregister sysfs devices outside occ lock
This commit is contained in:
Linus Torvalds 2026-07-02 05:58:35 -10:00
commit a9d4dd7424
10 changed files with 91 additions and 21 deletions

View File

@ -256,7 +256,7 @@ these logs can be cleared by writing in the proper reset_history attribute.
``/sys/kernel/debug/i2c/i2c-[X]/[X]-addr/``
contains the following attributes:
======================= ==========================================
============================== ==========================================================
power1_failed_fault_log Set to 1 by a power1 fault occurring.
power1_good_input_fault_log Set to 1 by a power1 good input fault occurring at PGIO3.
in11_fet_short_fault_log Set to 1 when a FET-short fault occurs.
@ -264,4 +264,4 @@ in11_fet_bad_fault_log Set to 1 when a FET-BAD fault occurs.
in0_lcrit_fault_log Set to 1 by a VIN undervoltage fault occurring.
in0_crit_fault_log Set to 1 by a VIN overvoltage fault occurring.
curr1_crit_fault_log Set to 1 by an overcurrent fault occurring.
======================= ==========================================
============================== ==========================================================

View File

@ -1098,6 +1098,7 @@ config SENSORS_LTC2992
tristate "Linear Technology LTC2992"
depends on I2C
depends on GPIOLIB
select REGMAP_I2C
help
If you say yes here you get support for Linear Technology LTC2992
I2C System Monitor. The LTC2992 measures current, voltage, and
@ -1248,6 +1249,7 @@ config SENSORS_MAX16065
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C
select REGMAP
help
If you say yes here you get support for MAX1619 sensor chip.
@ -1366,6 +1368,7 @@ config SENSORS_MAX6650
config SENSORS_MAX6697
tristate "Maxim MAX6697 and compatibles"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for MAX6581, MAX6602, MAX6622,
MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699

View File

@ -293,7 +293,10 @@ static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, u32 tach_va
priv->clk_rate, tach_val, tach_div);
rpm = (u64)priv->clk_rate * 60;
do_div(rpm, tach_div);
if (tach_div)
do_div(rpm, tach_div);
else
rpm = 0;
return (int)rpm;
}

View File

@ -1037,6 +1037,9 @@ static int atk_ec_present(struct atk_data *data)
if (obj->type != ACPI_TYPE_PACKAGE)
continue;
if (!obj->package.count)
continue;
id = &obj->package.elements[0];
if (id->type != ACPI_TYPE_INTEGER)
continue;

View File

@ -214,6 +214,11 @@ int occ_update_response(struct occ *occ)
if (rc)
return rc;
if (!occ->active) {
rc = -ENODEV;
goto unlock;
}
/* limit the maximum rate of polling the OCC */
if (time_after(jiffies, occ->next_update)) {
rc = occ_poll(occ);
@ -222,6 +227,7 @@ int occ_update_response(struct occ *occ)
rc = occ->last_error;
}
unlock:
mutex_unlock(&occ->lock);
return rc;
}
@ -1105,11 +1111,16 @@ static void occ_parse_poll_response(struct occ *occ)
int occ_active(struct occ *occ, bool active)
{
int rc = mutex_lock_interruptible(&occ->lock);
struct device *hwmon = NULL;
int rc = mutex_lock_interruptible(&occ->hwmon_lock);
if (rc)
return rc;
rc = mutex_lock_interruptible(&occ->lock);
if (rc)
goto unlock_hwmon;
if (active) {
if (occ->active) {
rc = -EALREADY;
@ -1154,14 +1165,17 @@ int occ_active(struct occ *occ, bool active)
goto unlock;
}
if (occ->hwmon)
hwmon_device_unregister(occ->hwmon);
hwmon = occ->hwmon;
occ->active = false;
occ->hwmon = NULL;
}
unlock:
mutex_unlock(&occ->lock);
if (hwmon)
hwmon_device_unregister(hwmon);
unlock_hwmon:
mutex_unlock(&occ->hwmon_lock);
return rc;
}
@ -1170,6 +1184,7 @@ int occ_setup(struct occ *occ)
int rc;
mutex_init(&occ->lock);
mutex_init(&occ->hwmon_lock);
occ->groups[0] = &occ->group;
rc = occ_setup_sysfs(occ);
@ -1190,15 +1205,22 @@ EXPORT_SYMBOL_GPL(occ_setup);
void occ_shutdown(struct occ *occ)
{
mutex_lock(&occ->lock);
struct device *hwmon;
occ_shutdown_sysfs(occ);
if (occ->hwmon)
hwmon_device_unregister(occ->hwmon);
mutex_lock(&occ->hwmon_lock);
mutex_lock(&occ->lock);
hwmon = occ->hwmon;
occ->active = false;
occ->hwmon = NULL;
mutex_unlock(&occ->lock);
if (hwmon)
hwmon_device_unregister(hwmon);
mutex_unlock(&occ->hwmon_lock);
}
EXPORT_SYMBOL_GPL(occ_shutdown);

View File

@ -101,6 +101,7 @@ struct occ {
unsigned long next_update;
struct mutex lock; /* lock OCC access */
struct mutex hwmon_lock; /* serialize hwmon registration/removal */
struct device *hwmon;
struct occ_attribute *attrs;

View File

@ -512,7 +512,7 @@ static int adm1275_enable_vout_temp(struct adm1275_data *data,
static int adm1275_probe(struct i2c_client *client)
{
s32 (*config_read_fn)(const struct i2c_client *client, u8 reg);
u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1] = {0};
int config, device_config;
int ret;
struct pmbus_driver_info *info;
@ -839,15 +839,25 @@ static int adm1275_probe(struct i2c_client *client)
info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R;
}
if (cindex >= 0) {
u32 m;
/* Scale current with sense resistor value */
info->m[PSC_CURRENT_OUT] =
coefficients[cindex].m * shunt / 1000;
if (unlikely(check_mul_overflow(coefficients[cindex].m, shunt, &m))) {
dev_err(&client->dev, "Current coefficient overflow\n");
return -EOVERFLOW;
}
info->m[PSC_CURRENT_OUT] = m / 1000;
info->b[PSC_CURRENT_OUT] = coefficients[cindex].b;
info->R[PSC_CURRENT_OUT] = coefficients[cindex].R;
}
if (pindex >= 0) {
info->m[PSC_POWER] =
coefficients[pindex].m * shunt / 1000;
u32 m;
if (unlikely(check_mul_overflow(coefficients[pindex].m, shunt, &m))) {
dev_err(&client->dev, "Power coefficient overflow\n");
return -EOVERFLOW;
}
info->m[PSC_POWER] = m / 1000;
info->b[PSC_POWER] = coefficients[pindex].b;
info->R[PSC_POWER] = coefficients[pindex].R;
}

View File

@ -1095,9 +1095,27 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
static u16 pmbus_data2reg_vid(struct pmbus_data *data,
struct pmbus_sensor *sensor, s64 val)
{
val = clamp_val(val, 500, 1600);
return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
switch (data->info->vrm_version[sensor->page]) {
case vr12:
val = clamp_val(val, 250, 1520);
return 1 + DIV_ROUND_CLOSEST_ULL(val - 250, 5);
case vr13:
val = clamp_val(val, 500, 3040);
return 1 + DIV_ROUND_CLOSEST_ULL(val - 500, 10);
case imvp9:
val = clamp_val(val, 200, 2740);
return 1 + DIV_ROUND_CLOSEST_ULL(val - 200, 10);
case amd625mv:
val = clamp_val(val, 200, 1550);
return DIV_ROUND_CLOSEST_ULL((1550LL - val) * 100LL, 625);
case nvidia195mv:
val = clamp_val(val, 195, 1465);
return 1 + DIV_ROUND_CLOSEST_ULL(val - 195, 5);
case vr11:
default:
val = clamp_val(val, 500, 1600);
return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
}
}
static u16 pmbus_data2reg(struct pmbus_data *data,
@ -3329,18 +3347,23 @@ static void pmbus_regulator_notify_worker(struct work_struct *work)
int i, j;
for (i = 0; i < data->info->pages; i++) {
int event;
unsigned int event;
event = atomic_xchg(&data->regulator_events[i], 0);
if (!event)
continue;
for (j = 0; j < data->info->num_regulators; j++) {
if (i == rdev_get_id(data->rdevs[j])) {
if (i != rdev_get_id(data->rdevs[j]))
continue;
while (event) {
unsigned int _event = BIT(__ffs(event));
regulator_notifier_call_chain(data->rdevs[j],
event, NULL);
break;
_event, NULL);
event &= ~_event;
}
break;
}
}
}

View File

@ -1823,6 +1823,8 @@ static int w83627hf_probe(struct platform_device *pdev)
return 0;
error:
device_remove_file(dev, &dev_attr_vrm);
device_remove_file(dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&dev->kobj, &w83627hf_group);
sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
return err;
@ -1834,6 +1836,8 @@ static void w83627hf_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev, &dev_attr_vrm);
device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
}

View File

@ -1917,6 +1917,7 @@ static int w83793_probe(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
device_remove_file(dev, &w83793_vid[i].dev_attr);
device_remove_file(dev, &dev_attr_vrm);
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
device_remove_file(dev, &w83793_left_fan[i].dev_attr);