Repository navigation
J616s: drive the fans from the die temperatures (thermal cooling devices) - #560
Merged
Merged
Conversation
The power allocator only budgets power actors on its passive trips. A cooling device without power callbacks, such as a fan, mapped to an active trip of a zone the power allocator governs was never set, so a device tree fan curve did nothing on kernels that make it the default governor. Run those cooling devices the way the bang-bang governor does: when the zone reaches an active trip, each such instance asks for its upper state, and when the zone falls below the trip minus its hysteresis it asks for nothing. A cooling device mapped to several trips takes the deepest state asked for, so a ladder of active trips gives a stepped fan curve. Instances that have no target yet (a cooling device bound after the zone passed the trip, or after resume) are set from the zone temperature on the next update. Power actors are left to the power allocator as before, and zones without active trips are unchanged. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
With #cooling-cells = <3> the SMC hwmon node provides its fans as cooling devices, named by their index among the fan-* nodes as in <&smc_hwmon fan-index lower upper>. State 0 leaves a fan to the SMC; the other states run it at speeds spread from its minimum to its maximum. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
On the M4 Pro MacBook Pro (J616s) the SMC keeps both fans in its own mode 3. With no operating system asking it for cooling, it leaves them off, or switches them on late and ramps them slowly, while the dies heat up: four busy CPU cores took the CPU die from 52 C to 95 C in two minutes with both fans at 0 rpm. Linux has to ask for the cooling. With #cooling-cells = <3> on the hwmon node, every fan registers a cooling device, named by its index among the fan-* nodes. State 0 leaves the fan to the SMC; states 1 to 8 run it at speeds spread evenly from its minimum to its maximum, through the same manual mode and Ftst unlock as the fan_control target, which they do not need. A fan runs at the higher of the userspace target and its cooling state, so userspace cannot take it below what the thermal zones ask for, and it goes back to the SMC once neither asks for anything. Unlocking takes the SMC seconds, so states are applied from a work item. Any failure leaves the fan with the SMC. Suspend, shutdown and removal stop the work and hand every fan back; resume applies the cooling states again. Without #cooling-cells nothing changes. KUnit covers the state to speed mapping, cooling without fan_control, cooling together with a userspace target, the stopped state and a failed unlock. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Make both J616s fans cooling devices of the CPU die zone and the seven GPU zones. Each zone gets a ladder of active trips: 75 C runs the fans at their minimum, 80 C, 85 C and 90 C step them up, and 95 C runs them at full speed. A fan takes the highest state any zone asks for and returns to the SMC once every zone is 10 C below the first trip. The first trip sits above the 70-75 C the CPU die touches for a moment during light desktop bursts, so the fans do not start for those. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On the M4 Pro MacBook Pro 16 (J616s) the fans never respond to load under Linux. The SMC keeps both fans in its own mode 3, and with no operating system asking it for cooling it leaves them off, or switches them on late and ramps them slowly, while the dies heat up. On this machine four busy CPU cores took the CPU die from 52 C to 95 C in under two minutes with both fans at 0 rpm.
On macOS the OS thermal policy provides that demand. Public reports on M4 describe mode 3 as the state the firmware reports while the OS daemon drives cooling, and the
Ftstkey that releases the fans to the OS. Linux had nothing in that role. #512 made manual fan control work on this firmware but left it opt-in and unused by default.This series makes the kernel drive the fans as thermal cooling devices, bound to the die temperature zones through the device tree.
#cooling-cells = <3>on the SMC hwmon node, each fan is a cooling device addressed as<&smc_hwmon fan-index lower upper>(the indexed cooling-spec format the tree already supports). State 0 leaves the fan to the SMC, states 1-8 run it from its minimum to its maximum through the existing manual mode andFtstunlock. A fan runs at the higher of the cooling state and anyfan_controltarget, so userspace can't take it below what the zones ask for. Unlocking takes the SMC about 9 s, so states are applied from a work item. Any failure leaves the fan with the SMC. Suspend, shutdown and unbind hand every fan back, and resume applies the states again. No new module parameters. Without#cooling-cellsnothing changes.Evidence (J616s, fleet4 tree + this series)
The J616s DT comes from the Stage 2 boot loader, which these tests did not touch. So the DT nodes of the last commit were added to the live tree by a test-only module (in the evidence directory, never for merging), and then macsmc-hwmon was rebound. Both fans then bind to all 8 zones (10 instances per zone).
After the load the fans went back to SMC control (target 0) within seconds.
Pending: the idle and load check with the final 75 C first trip. That boot hit the J616s USB stage freeze, which also freezes plain fleet4 boots and is being investigated separately. The state ladder above 75 C is unchanged from the measured run.
Other machines
Neo (J700) has no fan nodes and no active trips, so nothing changes there. No fan cooling device registers, the governor change only acts on active-trip non-power-actor instances, and suspend/resume runs an empty fan loop. Other fan Macs only change if their DT adds
#cooling-cells.Shipping
The DT half reaches the J616s through the device tree in its Stage 2 boot loader, so it needs a Stage 2 rebuild with this DTB. The kernel half is inert until then.
Evidence (logs, fixture, scripts) is in the aurora-ctl reports directory
j616s-fan-cooling-20261029. The baseline and test logs are 1 Hz TSVs of the die zone, hottest zone, fan input/target and cooling states.🤖 Generated with Claude Code