Thermal protection on the K230: what exists, and what does not
Prompted by a direct question — whether it is safe to leave the board powered unattended. Short answer: the temperature is readable, and nothing acts on it. No throttling, no shutdown. That is a property of the vendor kernel and device tree, not of anything we configured.
All symbol evidence below is from System.map of our own build,
linux-riscv64-unknown-linux-gnu-6.6.36-xuantie.
What works
The sensor has a driver, and it is built in.
t canaan_thermal_probe
t canaan_thermal_init
d __initcall__kmod_canaan_thermal__258_122_canaan_thermal_init6
d of_canaan_thermal_match
drivers/thermal/canaan_thermal.c, enabled by CONFIG_CANAAN_THERMAL, which
is default ARCH_CANAAN and so comes in without being named in
k230_defconfig. It matches tsensor@91107000, compatible = "canaan,k230-tsensor", which is status = "okay" in k230.dtsi:850.
The thermal core is built in — 306 thermal* symbols, including
thermal_zone_device_register_with_trips and thermal_zone_device_critical,
the emergency-shutdown path.
/sys/class/thermal/thermal_zone0 exists on the booted board and reads:
/sys/class/thermal/thermal_zone0 canaan_thermal_zone 7179
But that number is not a temperature. See below.
The reading is a raw sensor code, not millidegrees
canaan_get_temp() does no conversion at all:
while (1) {
val = ioread32(data->base + TS_DATA);
if (val >> 12) {
*temp = val;
break;
}
}
*temp is the raw TS_DATA register. The sysfs contract for
thermal_zone*/temp is millidegrees Celsius, so 7179 would be read by
any standard consumer as 7.2 °C — implausible for a running SoC. It is
neither 7.2 °C nor 71.8 °C; it is an uncalibrated ADC code with no published
transfer function in the driver.
Two consequences:
- Anything that reads this zone gets nonsense. A userspace thermal daemon,
a monitoring agent, or a
criticaltrip expressed in millidegrees would all be operating on a number that does not mean what the interface says it does. - A trip point cannot be set correctly without the transfer function. This is why step 2 below has to come before step 3; picking a millidegree threshold against a raw code would produce a trip that fires at the wrong temperature or never.
Also worth noting: that while (1) has no timeout or iteration cap. If
val >> 12 never becomes non-zero the read spins forever in kernel context.
It has not been observed to hang, but nothing prevents it.
What does not work, and why
1. The driver registers a zone with no trip points, deliberately.
canaan_thermal.c:86:
data->tz = thermal_tripless_zone_device_register(
thermal_tripless_* is exactly what it says. A zone with no trips never
crosses a trip, so the thermal core never invokes a governor and never calls
thermal_zone_device_critical(). The driver is a thermometer.
2. No device tree supplies trips either. There is no thermal-zones node
in any K230 device tree in the Xuantie tree — the usual place a board declares
trip-point / critical and binds a cooling device. So the gap is not closed
from the DT side.
3. There is no cooling device to bind even if a trip existed. The only
cpufreq symbol in the kernel is cpufreq_add_device; there is no
cpufreq_register_driver, so no cpufreq driver is present and the CPU has no
DVFS states Linux can select. The conventional response to a passive trip —
throttle the CPU — has nothing to act on.
That leaves a critical trip forcing an orderly poweroff as the only meaningful protection available, and it is not configured.
What this means in practice
- Nothing in software will stop this board getting hot. Any protection is whatever the silicon does on its own, which we have not characterised.
- The RT-Smart core is still running its own firmware on the second C908
(see
hardware-userspace.md), and whether it implements a thermal response is unknown and outside our kernel. - Powering the board down when leaving it unattended is, on this evidence, the correct instinct rather than excessive caution.
Proposed next steps
Cheap, in order:
- Read the sensor.
cat /sys/class/thermal/thermal_zone*/tempat idle, then after a sustained load, and write both down. This costs one boot and tells us whether the part even runs warm. It may make the rest moot. - Find the hardware limit. The K230 datasheet’s operating range, and
whether the TSENSOR block has its own hardware trip independent of Linux.
canaan_thermal.cand thehardlock = <2>property in the DT node are the places to look. - Add a critical trip. A
thermal-zonesnode with acriticaltrip referencing the tsensor, which givesthermal_zone_device_critical()something to fire. This needs step 2 first — a made-up threshold is worse than none, because it either never fires or shuts the board down during normal work. - Only then consider throttling, which means a cpufreq driver and OPP table, and is a substantially larger piece of work for a board that may simply never get hot enough to need it.
Steps 1 and 2 are research. Step 3 is a small change. Step 4 should not be started until 1 and 2 say it is needed.