Changeset View
Changeset View
Standalone View
Standalone View
sys/powerpc/powermac/powermac_thermal.c
Show All 36 Lines | |||||
#include <sys/kthread.h> | #include <sys/kthread.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/reboot.h> | #include <sys/reboot.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include "powermac_thermal.h" | #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 fan_management_proc(void); | ||||
static void pmac_therm_manage_fans(void); | static void pmac_therm_manage_fans(void); | ||||
static struct proc *pmac_them_proc; | static struct proc *pmac_them_proc; | ||||
static int enable_pmac_thermal = 1; | static int enable_pmac_thermal = 1; | ||||
static struct kproc_desc pmac_therm_kp = { | static struct kproc_desc pmac_therm_kp = { | ||||
"pmac_thermal", | "pmac_thermal", | ||||
fan_management_proc, | fan_management_proc, | ||||
&pmac_them_proc | &pmac_them_proc | ||||
}; | }; | ||||
SYSINIT(pmac_therm_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, | SYSINIT(pmac_therm_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, | ||||
&pmac_therm_kp); | &pmac_therm_kp); | ||||
SYSCTL_INT(_machdep, OID_AUTO, manage_fans, CTLFLAG_RW | CTLFLAG_TUN, | SYSCTL_INT(_machdep, OID_AUTO, manage_fans, CTLFLAG_RW | CTLFLAG_TUN, | ||||
&enable_pmac_thermal, 1, "Enable automatic fan management"); | &enable_pmac_thermal, 1, "Enable automatic fan management"); | ||||
static MALLOC_DEFINE(M_PMACTHERM, "pmactherm", "Powermac Thermal Management"); | static MALLOC_DEFINE(M_PMACTHERM, "pmactherm", "Powermac Thermal Management"); | ||||
struct pmac_fan_le { | struct pmac_fan_le { | ||||
struct pmac_fan *fan; | struct pmac_fan *fan; | ||||
int last_val; | int last_val; | ||||
int timer; | |||||
SLIST_ENTRY(pmac_fan_le) entries; | SLIST_ENTRY(pmac_fan_le) entries; | ||||
}; | }; | ||||
struct pmac_sens_le { | struct pmac_sens_le { | ||||
struct pmac_therm *sensor; | struct pmac_therm *sensor; | ||||
int last_val; | int last_val; | ||||
#define MAX_CRITICAL_COUNT 6 | #define MAX_CRITICAL_COUNT 6 | ||||
int critical_count; | int critical_count; | ||||
SLIST_ENTRY(pmac_sens_le) entries; | SLIST_ENTRY(pmac_sens_le) entries; | ||||
Show All 16 Lines | |||||
} | } | ||||
static void | static void | ||||
pmac_therm_manage_fans(void) | pmac_therm_manage_fans(void) | ||||
{ | { | ||||
struct pmac_sens_le *sensor; | struct pmac_sens_le *sensor; | ||||
struct pmac_fan_le *fan; | struct pmac_fan_le *fan; | ||||
int average_excess, max_excess_zone, frac_excess; | int average_excess, max_excess_zone, frac_excess; | ||||
int fan_speed; | |||||
int nsens, nsens_zone; | int nsens, nsens_zone; | ||||
int temp; | int temp; | ||||
if (!enable_pmac_thermal) | if (!enable_pmac_thermal) | ||||
return; | return; | ||||
/* Read all the sensors */ | /* Read all the sensors */ | ||||
SLIST_FOREACH(sensor, &sensors, entries) { | SLIST_FOREACH(sensor, &sensors, entries) { | ||||
Show All 26 Lines | SLIST_FOREACH(sensor, &sensors, entries) { | ||||
} | } | ||||
} | } | ||||
/* Set all the fans */ | /* Set all the fans */ | ||||
SLIST_FOREACH(fan, &fans, entries) { | SLIST_FOREACH(fan, &fans, entries) { | ||||
nsens = nsens_zone = 0; | nsens = nsens_zone = 0; | ||||
average_excess = max_excess_zone = 0; | average_excess = max_excess_zone = 0; | ||||
SLIST_FOREACH(sensor, &sensors, entries) { | 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->target_temp)*100 / | ||||
(sensor->sensor->max_temp - | (sensor->sensor->max_temp - temp + 1); | ||||
sensor->sensor->target_temp); | |||||
if (frac_excess < 0) | if (frac_excess < 0) | ||||
frac_excess = 0; | frac_excess = 0; | ||||
if (sensor->sensor->zone == fan->fan->zone) { | if (sensor->sensor->zone == fan->fan->zone) { | ||||
max_excess_zone = imax(max_excess_zone, | max_excess_zone = imax(max_excess_zone, | ||||
frac_excess); | frac_excess); | ||||
nsens_zone++; | nsens_zone++; | ||||
} | } | ||||
average_excess += frac_excess; | average_excess += frac_excess; | ||||
Show All 9 Lines | if (nsens == 0) { | ||||
fan->fan->set(fan->fan, fan->fan->default_rpm); | fan->fan->set(fan->fan, fan->fan->default_rpm); | ||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
* Scale the fan linearly in the max temperature in its | * Scale the fan linearly in the max temperature in its | ||||
* thermal zone. | * 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->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); | |||||
} | } | ||||
} | } | ||||
void | void | ||||
pmac_thermal_fan_register(struct pmac_fan *fan) | pmac_thermal_fan_register(struct pmac_fan *fan) | ||||
{ | { | ||||
struct pmac_fan_le *list_entry; | struct pmac_fan_le *list_entry; | ||||
Show All 21 Lines |