Skip to content

Fan control is a no-op on Intel T2 Macs (2018+): uses FS! instead of per-fan F0Md key #3

Description

@leitaoodavid

Summary

On Intel Macs with the T2 chip (2018 and later), manual fan control silently does nothing. The app reports success and the UI shows a manual target, but the SMC ignores the write and the fan stays on automatic. Reproduced on a MacBook Pro 13-inch 2018 (A1989), macOS 15.7.

Cause

In HelperService, the Intel (#else, non-arm64) path forces manual mode via writeForceMode, which writes the legacy FS! force bitmask:

#else
try smc.writeForceMode(fanIndex: fanIndex, forced: true)
#endif

On T2 Macs the FS! key is absent / ignored (see hholtmann/smcFanControl#86), so the fan never enters forced mode and the following F{i}Tg target write is ignored by the firmware. The write returns success but nothing persists.

T2 Macs use the same mechanism as Apple Silicon: the per-fan mode key F{i}Md = 1. The code already implements that (writeFanModeKey), but it only compiles into the arch(arm64) path, so Intel T2 machines never use it.

Verification

Writing F0Md = 1 then F0Tg = 3000 (float32) on the affected machine works, both directly via SMC and through the XPC helper:

[before]   Fan0  Md=auto(0)    Tg=0     Actual=auto
[after 7s] Fan0  Md=manual(1)  Tg=3000  Actual=2936

The fan physically spins up to the target. With the old FS! path, F0Tg/F0Md never change.

Suggested fix

On the Intel path, use the per-fan mode key (works on T2) and keep FS! as a best-effort fallback for pre-T2 Intel Macs. Same change applies to both branches of setFanMode:

#else
// T2 Macs (2018+) use the per-fan mode key, like Apple Silicon; older Intel Macs use FS!.
try? smc.writeForceMode(fanIndex: fanIndex, forced: true)  // pre-T2 best-effort
try smc.writeFanModeKey(index: fanIndex, forced: true)     // T2 primary
#endif

Environment

  • MacBook Pro 13-inch 2018 (A1989), Intel, T2 chip
  • macOS 15.7.7
  • ChillMac 1.7.0 (built from source with Xcode 16.4, macOS 15.5 SDK)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions