From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D571538E5ED; Wed, 30 Sep 2026 19:00:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790794806; cv=none; b=OLJFjG5Us/VL1UqpbjxpLT2mFiaTTgFfWertxY4ntt7gJLNrdYcD2SMnL3GRIagPxUFo0X2LI//rQvHKwNQ3Jy13zR6Yjj82X2+6Ss0uahNY2A8hzq/mdx2QWE1/hLdZaBunpfE38VSCXVoANtgVL0ZLzM11Pyd76i+gW6TSsp4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790794806; c=relaxed/simple; bh=j2w4KwLU2BXEs4+k51UeIlx1dgg637eZDOT7sGFLLoM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BTJms4mCEszNHc9q1Gsth1Ha1caYSfo9lZOW2y7cL5u2Dw508tIgU+QEnDT24x5+0EaMBTy+1nKQyTp0Q3V9SjVZKk0qV6rUYD3l/93WrH70LDvZ/p7ML1gVaCXOwoJQvnYtCMNhLNLKJeLtnDMJXt/JwxciI5BvHKhPC+71/FM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=V9MSM9P1; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="V9MSM9P1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0A2DA1F000FF; Wed, 30 Sep 2026 19:00:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1790794804; bh=I3kLvMvqpCjDDNagz1rg17vlv94E/smzu42fk0s/AU4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=V9MSM9P1aIiQWQuQRNjtPxq6ez6gh98a0mH+/Qgg6pv1fkKewyY5O09ipEghVK1yM QSm2QD4sCl1XgVxEdsmz647hHHs26LvjyaTn2CkpEpC5z8MFWghLL4ux3EvgAB6PmY 4U65beBo/mvsNvhyFX21y6XMA7Wut8t2958kt37s= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Sashiko , Wilken Gottwalt , Guenter Roeck , Sasha Levin Subject: [PATCH 6.6 0340/1193] hwmon: (corsair-psu) Fix linear11 calculation Date: Wed, 30 Sep 2026 17:17:04 +0200 Message-ID: <20260930152441.713863388@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260930152434.301151190@linuxfoundation.org> References: <20260930152434.301151190@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Guenter Roeck [ Upstream commit c6c4234928d2eb4f61fecb61067e612d9bdbd2ff ] 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 Cc: Wilken Gottwalt Signed-off-by: Guenter Roeck Tested-by: Wilken Gottwalt Link: https://lore.kernel.org/r/20260804034811.2385506-1-linux@roeck-us.net Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- 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 61d1b22bc63ec..7b64e04116e39 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -140,13 +140,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; - return (exp >= 0) ? (result << exp) : (result >> -exp); + if (exp >= 0) + result *= (int)(1UL << exp); + else + result >>= -exp; + + return clamp(result, LONG_MIN, LONG_MAX); } /* the micro-controller uses percentage values to control pwm */ @@ -271,13 +276,13 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l case PSU_CMD_RAIL_AMPS: case PSU_CMD_TEMP0: case PSU_CMD_TEMP1: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000); + *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1000); break; case PSU_CMD_FAN: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1); break; case PSU_CMD_FAN_PWM_ENABLE: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1); /* * 0 = automatic mode, means the micro-controller controls the fan using a plan * which can be modified, but changing this plan is not supported by this @@ -291,12 +296,12 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l *val = 2; break; case PSU_CMD_FAN_PWM: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1); *val = corsairpsu_dutycycle_to_pwm(*val); break; case PSU_CMD_RAIL_WATTS: case PSU_CMD_TOTAL_WATTS: - *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000); + *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1000000); break; case PSU_CMD_TOTAL_UPTIME: case PSU_CMD_UPTIME: -- 2.53.0