Skip to content

Commit 2938b29

Browse files
paulfertsergroeck
authored andcommitted
hwmon: (tmp421) handle I2C errors
Function i2c_smbus_read_byte_data() can return a negative error number instead of the data read if I2C transaction failed for whatever reason. Lack of error checking can lead to serious issues on production hardware, e.g. errors treated as temperatures produce spurious critical temperature-crossed-threshold errors in BMC logs for OCP server hardware. The patch was tested with Mellanox OCP Mezzanine card emulating TMP421 protocol for temperature sensing which sometimes leads to I2C protocol error during early boot up stage. Fixes: 9410700 ("hwmon: Add driver for Texas Instruments TMP421/422/423 sensor chips") Cc: [email protected] Signed-off-by: Paul Fertser <[email protected]> Link: https://lore.kernel.org/r/[email protected] [groeck: dropped unnecessary line breaks] Signed-off-by: Guenter Roeck <[email protected]>
1 parent e6fab7a commit 2938b29

File tree

1 file changed

+28
-10
lines changed

1 file changed

+28
-10
lines changed

drivers/hwmon/tmp421.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,38 +119,56 @@ static int temp_from_u16(u16 reg)
119119
return (temp * 1000 + 128) / 256;
120120
}
121121

122-
static struct tmp421_data *tmp421_update_device(struct device *dev)
122+
static int tmp421_update_device(struct tmp421_data *data)
123123
{
124-
struct tmp421_data *data = dev_get_drvdata(dev);
125124
struct i2c_client *client = data->client;
125+
int ret = 0;
126126
int i;
127127

128128
mutex_lock(&data->update_lock);
129129

130130
if (time_after(jiffies, data->last_updated + (HZ / 2)) ||
131131
!data->valid) {
132-
data->config = i2c_smbus_read_byte_data(client,
133-
TMP421_CONFIG_REG_1);
132+
ret = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
133+
if (ret < 0)
134+
goto exit;
135+
data->config = ret;
134136

135137
for (i = 0; i < data->channels; i++) {
136-
data->temp[i] = i2c_smbus_read_byte_data(client,
137-
TMP421_TEMP_MSB[i]) << 8;
138-
data->temp[i] |= i2c_smbus_read_byte_data(client,
139-
TMP421_TEMP_LSB[i]);
138+
ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_MSB[i]);
139+
if (ret < 0)
140+
goto exit;
141+
data->temp[i] = ret << 8;
142+
143+
ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_LSB[i]);
144+
if (ret < 0)
145+
goto exit;
146+
data->temp[i] |= ret;
140147
}
141148
data->last_updated = jiffies;
142149
data->valid = 1;
143150
}
144151

152+
exit:
145153
mutex_unlock(&data->update_lock);
146154

147-
return data;
155+
if (ret < 0) {
156+
data->valid = 0;
157+
return ret;
158+
}
159+
160+
return 0;
148161
}
149162

150163
static int tmp421_read(struct device *dev, enum hwmon_sensor_types type,
151164
u32 attr, int channel, long *val)
152165
{
153-
struct tmp421_data *tmp421 = tmp421_update_device(dev);
166+
struct tmp421_data *tmp421 = dev_get_drvdata(dev);
167+
int ret = 0;
168+
169+
ret = tmp421_update_device(tmp421);
170+
if (ret)
171+
return ret;
154172

155173
switch (attr) {
156174
case hwmon_temp_input:

0 commit comments

Comments
 (0)