RE: nct6694-hwmon: temp17_enable and above write into the fan enable bitmap

"[email protected]" <[email protected]> Mon, 3 Aug 2026 03:04:27 +0000
Newsgroups org.kernel.vger.linux-hwmon,org.kernel.vger.linux-kernel
Message-ID <TYZPR03MB6792D706A7C27E8AC068E33DE7D52@TYZPR03MB6792.apcprd03.prod.outlook.com>
Hi Ali,

Thanks for the careful analysis, and good catch.

It's actually a fourth case. On the device side, tin_en[2] only covers the =
first 10 temperature channels (5 THR + 5 TDP, index 0-9), which are indexed=
 correctly today. The 16 DTIN channels (index 10-25) are enabled by the fir=
mware, so the driver should only expose their temperature input and the max=
/hyst limits - never their enable. Indexing tin_en past channel 15 spilling=
 into fin_en is exactly that missing distinction.

So the fix is to not advertise HWMON_T_ENABLE on the DTIN channels. I'd spl=
it the temp config:

#define NCT6694_HWMON_TEMP_CONFIG (HWMON_T_INPUT | HWMON_T_ENABLE |     \
                                                HWMON_T_MAX | HWMON_T_MAX_H=
YST |        \
                                                HWMON_T_MAX_ALARM)
#define NCT6694_HWMON_DTIN_CONFIG (HWMON_T_INPUT |                      \
                                               HWMON_T_MAX | HWMON_T_MAX_HY=
ST | \
                                               HWMON_T_MAX_ALARM)

and use NCT6694_HWMON_DTIN_CONFIG for the 16 DTIN entries. The core then ne=
ver creates tempX_enable for them, and fin_en stops getting clobbered. The =
first 10 channels are unaffected.

Feel free to write the patch, and add a Fixes: tag. Thanks again for the re=
port.

Best regards,
Ming

-----Original Message-----
From: Ali Ahmet Memis <[email protected]>
Sent: Sunday, August 2, 2026 8:48 PM
To: CS10 TMYu0 <[email protected]>
Cc: Ming Yu <[email protected]>; Guenter Roeck <[email protected]>; Je=
an Delvare <[email protected]>; [email protected]; linux-kernel@v=
ger.kernel.org
Subject: nct6694-hwmon: temp17_enable and above write into the fan enable b=
itmap

CAUTION - External Email: Do not click links or open attachments unless you=
 acknowledge the sender and content.


Hi,

While reading nct6694-hwmon.c I ran into something that looks wrong, but wh=
ich way to fix it depends on the device protocol, so I would rather ask tha=
n guess.

The driver registers 26 temperature channels, each with HWMON_T_ENABLE:

        HWMON_CHANNEL_INFO(temp,
                           NCT6694_HWMON_TEMP_CONFIG,   /* THR1 */
                           ...
                           NCT6694_HWMON_TEMP_CONFIG),  /* DTIN15 */

That is 5 THR plus 5 TDP plus 16 DTIN. The enable bitmap it indexes is two =
bytes:

        struct __packed nct6694_hwmon_control {
                u8 vin_en[2];
                u8 tin_en[2];
                u8 fin_en[2];
                u8 pwm_en[2];
                u8 reserved1[40];
                u8 pwm_freq[10];
                u8 reserved2[6];
        };

and both the read and the write path index it with the raw channel:

        temp_en =3D data->hwmon_en.tin_en[channel / 8];
        ...
        data->hwmon_en.tin_en[channel / 8] |=3D BIT(channel % 8);

nct6694_is_visible() returns 0644 for hwmon_temp_enable without looking at =
the channel number, so all 26 are writable. Since the structure is packed, =
channel 16 and above land past tin_en[]:

        channel  0-15 -> tin_en[0-1]
        channel 16-23 -> tin_en[2] =3D=3D fin_en[0]
        channel 24-25 -> tin_en[3] =3D=3D fin_en[1]

nct6694_hwmon_init() sends the whole control structure back to the device, =
so writing temp17_enable through temp26_enable ends up toggling the fan ena=
ble bits, and reading them reports fan state as temperature state. It stays=
 inside the structure, so this is not a memory safety problem, but on a boa=
rd using the fan channels it is not harmless.

What I cannot tell from here is which side is wrong, and the answers need d=
ifferent patches:

 1. If the control block really has two bytes of tin_en, then only 16
    temperature channels can be enabled and the last ten should not
    advertise HWMON_T_ENABLE.

 2. If the device has four bytes of tin_en, the structure is wrong, and
    fin_en and pwm_en are being read and written at the wrong offsets as
    well.

 3. If the bitmap only covers the digital inputs, the indexing is wrong
    in a third way: there are exactly 16 DTIN channels, which is exactly
    what tin_en[2] holds, and they sit at channel 10 and above.

The structure is 64 bytes as declared, and it would still be 64 bytes with =
tin_en[4] and reserved1[38], so the total size does not settle it.
Two things make me unsure rather than confident: the other three bitmaps ma=
tch their channel counts exactly, 16 in channels against vin_en[2] and
10 fan channels against fin_en[2], which argues for the first case; but the=
 16 DTIN channels also match tin_en[2] exactly, which is what made me think=
 of the third. I could not find a public datasheet to settle it.

Ming, could you say which one it is? I am happy to write the patch once I k=
now, I just do not want to guess at the device side.

I have no NCT6694 hardware, so this is from reading the driver against curr=
ent mainline rather than from an observed misbehaviour.

Thanks,
Ali
________________________________
________________________________
 The privileged confidential information contained in this email is intende=
d for use only by the addressees as indicated by the original sender of thi=
s email. If you are not the addressee indicated in this email or are not re=
sponsible for delivery of the email to such a person, please kindly reply t=
o the sender indicating this fact and delete all copies of it from your com=
puter and network server immediately. Your cooperation is highly appreciate=
d. It is advised that any unauthorized use of confidential information of N=
uvoton is strictly prohibited; and any information in this email irrelevant=
 to the official business of Nuvoton shall be deemed as neither given nor e=
ndorsed by Nuvoton.