Index: sys/powerpc/powermac/powermac_thermal.c =================================================================== --- sys/powerpc/powermac/powermac_thermal.c +++ sys/powerpc/powermac/powermac_thermal.c @@ -42,6 +42,9 @@ #include "powermac_thermal.h" +/* A 10 second timer for spinning down fans. */ +#define FAN_HYSTERESIS_TIMER 10 + static void fan_management_proc(void); static void pmac_therm_manage_fans(void); @@ -63,6 +66,7 @@ struct pmac_fan_le { struct pmac_fan *fan; int last_val; + int timer; SLIST_ENTRY(pmac_fan_le) entries; }; struct pmac_sens_le { @@ -95,6 +99,7 @@ struct pmac_sens_le *sensor; struct pmac_fan_le *fan; int average_excess, max_excess_zone, frac_excess; + int fan_speed; int nsens, nsens_zone; int temp; @@ -137,10 +142,11 @@ nsens = nsens_zone = 0; average_excess = max_excess_zone = 0; SLIST_FOREACH(sensor, &sensors, entries) { - frac_excess = (sensor->last_val - + temp = imin(sensor->last_val, + sensor->sensor->max_temp); + frac_excess = (temp - sensor->sensor->target_temp)*100 / - (sensor->sensor->max_temp - - sensor->sensor->target_temp); + (sensor->sensor->max_temp - temp + 1); if (frac_excess < 0) frac_excess = 0; if (sensor->sensor->zone == fan->fan->zone) { @@ -166,9 +172,21 @@ * Scale the fan linearly in the max temperature in its * thermal zone. */ - fan->fan->set(fan->fan, max_excess_zone * + max_excess_zone = imin(max_excess_zone, 100); + fan_speed = max_excess_zone * (fan->fan->max_rpm - fan->fan->min_rpm)/100 + - fan->fan->min_rpm); + fan->fan->min_rpm; + if (fan_speed >= fan->last_val) { + fan->timer = FAN_HYSTERESIS_TIMER; + fan->last_val = fan_speed; + } else { + fan->timer--; + if (fan->timer == 0) { + fan->last_val = fan_speed; + fan->timer = FAN_HYSTERESIS_TIMER; + } + } + fan->fan->set(fan->fan, fan->last_val); } }