Skip to content

Commit a617028

Browse files
committed
thermal: surgically excise power-down timeout (#2585)
Presently, the thermal loop will power down the system if any component remains above its "critical" threshold for 60 seconds. We believe this behavior to be excessively conservative, and unnecessary, as an uncontrollable thermal runaway event will eventually result in something tripping its "power-down" threshold and shutting the system down immediately. This commit makes the smallest possible change to the thermal loop to remove the timeout. This allows us to operate at the edge of our thermal envelope for as long as is necessary, while still ensuring that the fans go full-throttle when we hit 90 Funny AMD Temperature Units, or when anything else hits its crit threshold. The rest of the control loop behavior should be identical.
1 parent 048b990 commit a617028

1 file changed

Lines changed: 36 additions & 62 deletions

File tree

task/thermal/src/control.rs

Lines changed: 36 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,6 @@ pub(crate) struct ThermalControl<'a> {
452452
/// Controller state
453453
state: ThermalControlState,
454454

455-
/// How long to wait in the `Overheated` state before powering down
456-
overheat_timeout_ms: u64,
457-
458455
/// Most recent power mode mask
459456
power_mode: PowerBitmask,
460457

@@ -673,30 +670,15 @@ type DynamicChannelsArray =
673670
/// threshold, we return to normal control.
674671
///
675672
/// In addition, the thermal control loop will perform an emergency power down
676-
/// of the system under either of the following conditions:
677-
///
678-
/// - Any component temperature has been above its critical threshold for
679-
/// longer than [`overheat_timeout_ms`].
680-
/// - Any component temperature exceeds its power-down threshold.
681-
///
682-
/// In either of these cases, we will decide that the system's temperatures
683-
/// cannot be controlled, and transition to
684-
/// [`ThermalControlState::Uncontrollable`]. In this state, the thermal loop
685-
/// will request a power state change to A2, shutting down the system.
673+
/// of the system if any component temperature exceeds its power-down threshold.
674+
/// In that case, we will decide that the system's temperatures cannot be
675+
/// controlled, and transition to [`ThermalControlState::Uncontrollable`]. In
676+
/// this state, the thermal loop will request a power state change to A2,
677+
/// shutting down the system.
686678
///
687-
/// The intent behind the overheat timeout is to safely power down the system
688-
/// when in a situation where even running the fans at their maximum duty cycle
689-
/// cannot reduce temperatures below a critical threshold. Therefore, the
690-
/// timeout is only applied while any component temperature(s) are at or above
691-
/// critical thresholds. If running the fans at full speed is effectively
692-
/// reducing the system temperature, but we have not yet returned to normal
693-
/// control, the timeout is not applied. Therefore, we separate the overheated
694-
/// control regime into two substates:
695-
///
696-
/// - `Overheat`, in which at least one component is critical and the timeout
697-
/// is being tracked, and
679+
/// - `Overheat`, in which at least one component is critical
698680
/// - `FanParty`, in which all temperatures are below critical, and we will run
699-
/// the fans at 100% duty cycle but do not track the overheat timeout.
681+
/// the fans at 100% duty cycle until we return to nomal
700682
///
701683
/// This diagram depicts the transitions between control states:
702684
///
@@ -718,24 +700,24 @@ type DynamicChannelsArray =
718700
/// | | . +----------+ . |
719701
/// | +--------------->| |--------->-------+
720702
/// +------<-------------| OVERHEAT | . |
721-
/// | . | |-------------+ |
722-
/// | . +----------+ . | |
723-
/// | . | ^ . | ^
724-
/// | all temps | * . any temp v |
725-
/// | under crit . . * | over crit | |
726-
/// | . | | . | |
727-
/// | . v | . | |
728-
/// | . +-----------+ . | |
703+
/// | . | | . |
704+
/// | . +----------+ . |
705+
/// | . | ^ . ^
706+
/// | all temps | * . any temp |
707+
/// | under crit . . * | over crit |
708+
/// | . | | . |
709+
/// | . v | . |
710+
/// | . +-----------+ . |
729711
/// +-------------------| FAN PARTY |----------->-----+
730-
/// | . +-----------+ . |
731-
/// | ......................... |
732-
/// | |
733-
/// * . . Any temp over * . . overheat_timeout_ms
734-
/// | power_down | elapsed
735-
/// | |
736-
/// v |
737-
/// +----------------+ |
738-
/// | UNCONTROLLABLE |<------------------------------+
712+
/// | . +-----------+ .
713+
/// | .........................
714+
/// |
715+
/// * . . Any temp over
716+
/// | power_down
717+
/// |
718+
/// v
719+
/// +----------------+
720+
/// | UNCONTROLLABLE |
739721
/// +----------------+
740722
/// |
741723
/// V
@@ -764,22 +746,20 @@ enum ThermalControlState {
764746
//
765747
/// In the critical state, one or more components has entered their
766748
/// critical temperature ranges. We turn on fans at high power and record
767-
/// the time at which we entered this state; at a certain point, we will
768-
/// timeout and drop into `Uncontrolled` if components do not recover.
749+
/// the time at which we entered this state.
769750
Critical {
770751
values: TemperatureArray,
771752
/// The time at which we transitioned to the `Critical` state *this*
772753
/// time, either from `Running` or from FAN PARTY!!!.
773754
start_time: u64,
774755
},
775756

776-
/// If we are in the `Critical` state and all temperatures drop below
777-
/// their Critical threshold, but above their nominal threshold, we leave
778-
/// the `Critical` state and enter FAN PARTY!!!!, a special state that's
779-
/// kind of halfway between `Critical` and normal operation. In FAN PARTY
780-
/// MODE, we continue to run the fans at their max duty cycle, but we don't
781-
/// track the overheated timeout. If anything goes above critical while in
782-
/// FAN PARTY!!!!!, we return to `Critical`.
757+
/// If we are in the `Critical` state and all temperatures drop below their
758+
/// Critical threshold, but above their nominal threshold, we leave the
759+
/// `Critical` state and enter FAN PARTY!!!!, a special state that's kind of
760+
/// halfway between `Critical` and normal operation. In FAN PARTY MODE, we
761+
/// continue to run the fans at their max duty cycle until we go below a
762+
/// nomal threshold.
783763
///
784764
/// This gives us an opportunity to recover from overheating by running the
785765
/// fans aggressively without also deciding to give up and kill ourselves
@@ -1044,8 +1024,6 @@ impl<'a> ThermalControl<'a> {
10441024
},
10451025
pid_config,
10461026

1047-
overheat_timeout_ms: 60_000,
1048-
10491027
power_mode: PowerBitmask::empty(), // no sensors active
10501028

10511029
dynamic_inputs: [None; bsp::NUM_DYNAMIC_TEMPERATURE_INPUTS],
@@ -1403,7 +1381,7 @@ impl<'a> ThermalControl<'a> {
14031381
ControlResult::Pwm(PWMDuty(pwm as u8))
14041382
}
14051383
}
1406-
ThermalControlState::Critical { values, start_time } => {
1384+
ThermalControlState::Critical { values, .. } => {
14071385
let mut all_nominal = true;
14081386
let mut any_still_critical = false;
14091387
let mut any_power_down = None;
@@ -1437,10 +1415,6 @@ impl<'a> ThermalControl<'a> {
14371415
// nominal.
14381416
let values = *values;
14391417
self.transition_to_fan_party(now_ms, values)
1440-
} else if now_ms > *start_time + self.overheat_timeout_ms {
1441-
// If blasting the fans hasn't cooled us down in this amount
1442-
// of time, then something is terribly wrong - abort!
1443-
self.transition_to_uncontrollable(now_ms)
14441418
} else {
14451419
ControlResult::Pwm(PWMDuty(
14461420
self.pid_config.max_output as u8,
@@ -1594,7 +1568,7 @@ impl<'a> ThermalControl<'a> {
15941568
/// also records the sensor ID and temperature measurements for the device
15951569
/// that tripped over the threshold. We separate this into two functions as
15961570
/// we may also transition to uncontrollable due to an inability to read
1597-
/// sensors at all, or due to the power-down timeout.
1571+
/// sensors at all.
15981572
fn transition_to_uncontrollable_due_to(
15991573
&mut self,
16001574
(sensor_id, worst_case): (SensorId, WorstCaseTemperature),
@@ -1617,9 +1591,9 @@ impl<'a> ThermalControl<'a> {
16171591
self.transition_to_uncontrollable(now_ms)
16181592
}
16191593

1620-
/// Transition to the `Uncontrollable` state, either in response to the
1621-
/// overheat timeout, thermal sensor errors, or a component exceeding its
1622-
/// power-down temperature threshold.
1594+
/// Transition to the `Uncontrollable` state, either in response to thermal
1595+
/// sensor errors, or a component exceeding its power-down temperature
1596+
/// threshold.
16231597
fn transition_to_uncontrollable(&mut self, now_ms: u64) -> ControlResult {
16241598
self.record_leaving_critical(now_ms);
16251599
self.record_leaving_overheat(now_ms);

0 commit comments

Comments
 (0)