Message ID | 20240716230050.2049534-5-linux@roeck-us.net (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
Series | hwmon: Use multi-byte regmap operations | expand |
On Tue, Jul 16, 2024 at 04:00:48PM -0700, Guenter Roeck wrote: > @@ -147,11 +147,11 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val > { [...] > - mutex_lock(&data->update_lock); > - > switch (attr) { > case hwmon_temp_max_alarm: > err = regmap_read(regmap, TMP464_THERM_STATUS_REG, ®val); > @@ -172,26 +172,27 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val > * complete. That means we have to cache the value internally > * for one measurement cycle and report the cached value. > */ > + mutex_lock(&data->update_lock); > if (!data->valid || time_after(jiffies, data->last_updated + > msecs_to_jiffies(data->update_interval))) { > err = regmap_read(regmap, TMP464_REMOTE_OPEN_REG, ®val); > if (err < 0) > - break; > + goto unlock; > data->open_reg = regval; > data->last_updated = jiffies; > data->valid = true; > } > *val = !!(data->open_reg & BIT(channel + 7)); > +unlock: > + mutex_unlock(&data->update_lock); > break; I think the function can entirely drop the mutex. Only [1] needs it. [1]: https://elixir.bootlin.com/linux/v6.10/source/drivers/hwmon/tmp464.c#L313
On 7/17/24 06:35, Tzung-Bi Shih wrote: > On Tue, Jul 16, 2024 at 04:00:48PM -0700, Guenter Roeck wrote: >> @@ -147,11 +147,11 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val >> { > [...] >> - mutex_lock(&data->update_lock); >> - >> switch (attr) { >> case hwmon_temp_max_alarm: >> err = regmap_read(regmap, TMP464_THERM_STATUS_REG, ®val); >> @@ -172,26 +172,27 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val >> * complete. That means we have to cache the value internally >> * for one measurement cycle and report the cached value. >> */ >> + mutex_lock(&data->update_lock); >> if (!data->valid || time_after(jiffies, data->last_updated + >> msecs_to_jiffies(data->update_interval))) { >> err = regmap_read(regmap, TMP464_REMOTE_OPEN_REG, ®val); >> if (err < 0) >> - break; >> + goto unlock; >> data->open_reg = regval; >> data->last_updated = jiffies; >> data->valid = true; >> } >> *val = !!(data->open_reg & BIT(channel + 7)); >> +unlock: >> + mutex_unlock(&data->update_lock); >> break; > > I think the function can entirely drop the mutex. Only [1] needs it. > It is needed to protect updating open_reg. Otherwise a second process could enter the code and read the register again, which would then return different (cleared) values. As result open_reg might contain the temporarily "cleared" values. Process 1 Process 2 err = regmap_read(); data->open_reg = regval; err = regmap_read(); data->open_reg = regval; data->last_updated = jiffies; ... Thanks, Guenter
On Wed, Jul 17, 2024 at 07:37:10AM -0700, Guenter Roeck wrote: > On 7/17/24 06:35, Tzung-Bi Shih wrote: > > On Tue, Jul 16, 2024 at 04:00:48PM -0700, Guenter Roeck wrote: > > > @@ -147,11 +147,11 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val > > > { > > [...] > > > - mutex_lock(&data->update_lock); > > > - > > > switch (attr) { > > > case hwmon_temp_max_alarm: > > > err = regmap_read(regmap, TMP464_THERM_STATUS_REG, ®val); > > > @@ -172,26 +172,27 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val > > > * complete. That means we have to cache the value internally > > > * for one measurement cycle and report the cached value. > > > */ > > > + mutex_lock(&data->update_lock); > > > if (!data->valid || time_after(jiffies, data->last_updated + > > > msecs_to_jiffies(data->update_interval))) { > > > err = regmap_read(regmap, TMP464_REMOTE_OPEN_REG, ®val); > > > if (err < 0) > > > - break; > > > + goto unlock; > > > data->open_reg = regval; > > > data->last_updated = jiffies; > > > data->valid = true; > > > } > > > *val = !!(data->open_reg & BIT(channel + 7)); > > > +unlock: > > > + mutex_unlock(&data->update_lock); > > > break; > > > > I think the function can entirely drop the mutex. Only [1] needs it. > > > > It is needed to protect updating open_reg. Otherwise a second process > could enter the code and read the register again, which would then return > different (cleared) values. As result open_reg might contain the temporarily > "cleared" values. > > Process 1 Process 2 > err = regmap_read(); > data->open_reg = regval; > err = regmap_read(); > data->open_reg = regval; > data->last_updated = jiffies; > ... Ack. Reviewed-by: Tzung-Bi Shih <tzungbi@kernel.org>
diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c index 3ee1137533d6..0a7c0448835b 100644 --- a/drivers/hwmon/tmp464.c +++ b/drivers/hwmon/tmp464.c @@ -147,11 +147,11 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val { struct tmp464_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; - unsigned int regval, regval2; + unsigned int regs[2]; + unsigned int regval; + u16 regvals[2]; int err = 0; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_temp_max_alarm: err = regmap_read(regmap, TMP464_THERM_STATUS_REG, ®val); @@ -172,26 +172,27 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val * complete. That means we have to cache the value internally * for one measurement cycle and report the cached value. */ + mutex_lock(&data->update_lock); if (!data->valid || time_after(jiffies, data->last_updated + msecs_to_jiffies(data->update_interval))) { err = regmap_read(regmap, TMP464_REMOTE_OPEN_REG, ®val); if (err < 0) - break; + goto unlock; data->open_reg = regval; data->last_updated = jiffies; data->valid = true; } *val = !!(data->open_reg & BIT(channel + 7)); +unlock: + mutex_unlock(&data->update_lock); break; case hwmon_temp_max_hyst: - err = regmap_read(regmap, TMP464_THERM_LIMIT[channel], ®val); + regs[0] = TMP464_THERM_LIMIT[channel]; + regs[1] = TMP464_TEMP_HYST_REG; + err = regmap_multi_reg_read(regmap, regs, regvals, 2); if (err < 0) break; - err = regmap_read(regmap, TMP464_TEMP_HYST_REG, ®val2); - if (err < 0) - break; - regval -= regval2; - *val = temp_from_reg(regval); + *val = temp_from_reg(regvals[0] - regvals[1]); break; case hwmon_temp_max: err = regmap_read(regmap, TMP464_THERM_LIMIT[channel], ®val); @@ -200,14 +201,12 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val *val = temp_from_reg(regval); break; case hwmon_temp_crit_hyst: - err = regmap_read(regmap, TMP464_THERM2_LIMIT[channel], ®val); + regs[0] = TMP464_THERM2_LIMIT[channel]; + regs[1] = TMP464_TEMP_HYST_REG; + err = regmap_multi_reg_read(regmap, regs, regvals, 2); if (err < 0) break; - err = regmap_read(regmap, TMP464_TEMP_HYST_REG, ®val2); - if (err < 0) - break; - regval -= regval2; - *val = temp_from_reg(regval); + *val = temp_from_reg(regvals[0] - regvals[1]); break; case hwmon_temp_crit: err = regmap_read(regmap, TMP464_THERM2_LIMIT[channel], ®val); @@ -239,8 +238,6 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val break; } - mutex_unlock(&data->update_lock); - return err; }
Use multi-byte regmap operations where possible to reduce code size and the need for mutex protection. No functional changes. Signed-off-by: Guenter Roeck <linux@roeck-us.net> --- drivers/hwmon/tmp464.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-)