DGX Spark fan control

Hi everyone,

I’ve found a way to adjust the DGX Spark fan speed by invoking the EC’s existing command 5 via the SoC’s FF-A eSPI service to override the fan settings.

I’ve uploaded the solution to my GitHub; it has been tested and works, allowing the fan speed to be forced to 100%.

Hi, do you know by any chance if ASUS GX10 relies on the same EC chip and this kernel module can be applied to GX10 too? Their EC firmware versioning doesn’t match NVIDIA’s.

That is an interesting find. With the fan settings being accessible from the software layer there isn’t any reason for Nvidia to not give us a way to set the curve as we want.

What this sysfs knob (/sys/bus/arm_ffa/devices/arm-ffa-17/fan) does is setting the max speed to 13500 RPM. What would this high speed do to fan(s) longevity is unknown. Who wants to try first!?

For my AI workloads the EC automatic thermal curve will do!

@x1917x this utility writes to a specific memory location (0x933dd000) and on ASUS might not be the same as on FE.

See details at dgx-spark-fan-override/nvfancontrol/usr/src/nvfancontrol/nvfancontrol.c at 7ffcb3e28327d3e0f4d62210845d3357f0fbe256 · Z841973620/dgx-spark-fan-override · GitHub

It’s important to understand differences between write to memory and write to flash.

Beginning line 234 in the nvfancontrol.c you’ll see this code snippet:

	if (target == TARGET_FULL_RPM)
		dev_warn(&fdev->dev,
			 "MAX ACKNOWLEDGED: EC accepted high override=13500 RPM; fan0 and fan1 policy outputs saturate at 100%%\n");
	else

The fan speed is set by modifying the EC (embedded controller) and that’s firmware. The writing is done via mailbox located at 0x933dd000 memory address. Is the address the same on an ASUS or other OEM Sparks? IDK! The memory address is hardcoded: define ESPI_NS_SHM_PA 0x933dd000ULL

As mentioned, you need to understand the differences between volatile memory and firmware. In any case, smem is volatile memory, so nothing written survive a power cycle.


This utility modifies volatile RAM (SRAM) only—it does not modify the flash ROM, firmware image, or NVRAM.

  • Target Location: It writes directly to runtime memory addresses in the Embedded Controller (specifically EC SRAM 0x119192 / 0x119190 for dynamic override slots).

  • Execution Path: The kernel module uses ARM FF-A calls via the SoC eSPI service (OEM1 command 17) to communicate with the EC thermal mailbox in memory.

  • Flash Safety: The repository explicitly leaves the destructive flash write/erase commands (OEM1 commands 2 and 3) unused.

  • Persistence: Because changes are written strictly to EC SRAM, the values are completely volatile and will revert to factory defaults (0xFFFF) whenever the EC reinitializes or upon a power cycle/reboot.

the “max” profile works on my gx10, but required secure boot signing to get working. I could not find any way to switch to profile B which would be my preferred solution

I tested this on my DGX Spark using the nvfancontrol kernel module together with a small user-space temperature controller.

The most useful result is that 9000 RPM appears to be the efficiency sweet spot, rather than simply forcing 13500 RPM.

In a controlled auto → 9000 → auto test with the same GEMM + 20 CPU-thread load, the averaged hottest-zone temperature
dropped from 86.2 C on auto to 81.7 C at 9000 RPM, a reduction of 4.5 C. Internal air temperature dropped by 2.9 C and GPU
temperature by 3.4 C.

The 9000 RPM run also used 2.1 W more power and had an average SM clock about 45 MHz higher, so the system was cooler while
doing slightly more work. The response was immediate and reversible: the hottest zone dropped by about 3.7 C within 90 seconds
after switching to 9000 RPM, and rose by about 3.9 C after switching back to auto.

I am now using a temperature-based curve:

  • auto below 70 C
  • 7000 RPM at 70 C
  • 9000 RPM at 80 C
  • 11000 RPM at 86 C
  • 13500 RPM at 90 C

The curve has hysteresis and returns to auto after the load is removed. Under full load, the system settles around 81-82 C on
the 9000 RPM step.

For my use case, 9000 RPM is the best trade-off: it provides most of the measurable cooling benefit without the noise and
potential wear of running at maximum speed. I have not yet validated the additional benefit of 13500 RPM under a fully settled
workload.

The control path writes volatile EC runtime memory rather than flash/NVRAM, so the setting is lost after reboot or power
cycling. Secure Boot also requires signing the kernel module. Fan RPM telemetry is still not exposed, and long-term fan
lifetime at high speed remains unknown.