From: Wilken Gottwalt <wilken.gottwalt@posteo.net>
To: Guenter Roeck <linux@roeck-us.net>
Cc: Hardware Monitoring <linux-hwmon@vger.kernel.org>,
Sashiko <sashiko-bot@kernel.org>
Subject: Re: [PATCH v2] hwmon: (corsair-psu) Fix linear11 calculation
Date: Thu, 06 Aug 2026 15:56:45 +0000 [thread overview]
Message-ID: <20260806175645.5e50b70c@posteo.net> (raw)
In-Reply-To: <deb3db39-e8da-40d2-af9e-bdaf73b9bf3c@roeck-us.net>
On Thu, 6 Aug 2026 08:52:41 -0700
Guenter Roeck <linux@roeck-us.net> wrote:
> On 8/6/26 08:34, Wilken Gottwalt wrote:
> > On Mon, 3 Aug 2026 20:48:11 -0700
> > Guenter Roeck <linux@roeck-us.net> wrote:
> >
> >> In corsairpsu_linear11_to_int(), the mantissa is extracted using bitwise
> >> operations and cast to s16 before being shifted left:
> >>
> >> static int corsairpsu_linear11_to_int(const u16 val, const int scale)
> >> {
> >> ...
> >> const int mant = (((s16)(val & 0x7ff)) << 5) >> 5;
> >> ...
> >> }
> >>
> >> Due to C integer promotion rules, the masked value (which is always
> >> positive) is promoted to a 32-bit integer before the left shift. As a
> >> result, the sign bit is never extended to bit 31 of the promoted integer.
> >>
> >> When the device hardware reports a negative temperature in Linear11 format
> >> (such as an ambient temperature probe reporting sub-zero), the negative
> >> mantissa is parsed incorrectly as a massive positive value. For example,
> >> -1 becomes 2047, which scales to 2047 degrees Celsius.
> >>
> >> Fix the problem by type casting the result of the left shift operation
> >> to s16.
> >>
> >> Another problem is left-shifting of negative values. In C, the result of
> >> left-shifting negative values is undefined. Use a multiplication instead
> >> to avoid the problem.
> >>
> >> Also use a local s64 variable to store temporary results, change
> >> the return value type from int to long, and clamp the final value
> >> to LONG_MIN and LONG_MAX to avoid under- and overflow issues while
> >> retaining as much information as possible.
> >>
> >> Reported-by: Sashiko <sashiko-bot@kernel.org>
> >> Cc: Wilken Gottwalt <wilken.gottwalt@posteo.net>
> >> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> >> ---
> >> v2: Skip handling right-shift of negative values
> >> (since it is widely used in the kernel)
> >>
> >> drivers/hwmon/corsair-psu.c | 23 ++++++++++++++---------
> >> 1 file changed, 14 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
> >> index 24100519cd83..c437b469de5c 100644
> >> --- a/drivers/hwmon/corsair-psu.c
> >> +++ b/drivers/hwmon/corsair-psu.c
> >> @@ -137,13 +137,18 @@ struct corsairpsu_data {
> >> };
> >>
> >> /* some values are SMBus LINEAR11 data which need a conversion */
> >> -static int corsairpsu_linear11_to_int(const u16 val, const int scale)
> >> +static long corsairpsu_linear11_to_long(const u16 val, const int scale)
> >> {
> >> const int exp = ((s16)val) >> 11;
> >> - const int mant = (((s16)(val & 0x7ff)) << 5) >> 5;
> >> - const int result = mant * scale;
> >> + const int mant = ((s16)((val & 0x7ff) << 5)) >> 5;
> >
> >
> >> + s64 result = mant * scale;
> >
> > Uhm, this is a 32bit multiplicaiton, actully a C gotcha I explain the beginners
> > in our company. https://godbolt.org/z/eM6TbGG5E
> >
>
> It is, but that is ok and intentional: both mant and exp are guaranteed to be
> no larger than s16, meaning the result is never larger than s32 and will never
> overflow.
>
> >> - return (exp >= 0) ? (result << exp) : (result >> -exp);
> >> + if (exp >= 0)
> >> + result *= (int)(1UL << exp);
>
> This is the calculation that can overflow, making it necessary for result to be s64.
Yeah, it was just funny to see in the wild. It made my day. :D
greetings,
Wilken
next prev parent reply other threads:[~2026-08-06 15:56 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 3:48 [PATCH v2] hwmon: (corsair-psu) Fix linear11 calculation Guenter Roeck
2026-08-04 3:55 ` sashiko-bot
2026-08-06 15:34 ` Wilken Gottwalt
2026-08-06 15:52 ` Guenter Roeck
2026-08-06 15:56 ` Wilken Gottwalt [this message]
2026-08-06 16:28 ` Guenter Roeck
2026-08-06 16:42 ` Wilken Gottwalt
2026-08-06 18:04 ` Guenter Roeck
2026-08-06 18:28 ` Wilken Gottwalt
2026-08-06 19:15 ` Guenter Roeck
2026-08-07 4:26 ` Wilken Gottwalt
2026-08-07 5:36 ` Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260806175645.5e50b70c@posteo.net \
--to=wilken.gottwalt@posteo.net \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=sashiko-bot@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.