/* We keep a temperature history for average calculation of 180s */ #define CPU_TEMP_HIST_SIZE 180
/* Scale factor for fan speed, *100 */ staticint cpu_fan_scale[NR_CPU_FANS] = {
100,
100,
97, /* inlet fans run at 97% of exhaust fan */
97,
100, /* updated later */
100, /* updated later */
};
/* Implementation... */ staticint create_cpu_loop(int cpu)
{ int chip = cpu / 2; int core = cpu & 1; struct smu_sdbp_header *hdr; struct smu_sdbp_cpupiddata *piddata; struct wf_cpu_pid_param pid; struct wf_control *main_fan = cpu_fans[0];
s32 tmax; int fmin;
/* Get FVT params to get Tmax; if not found, assume default */
hdr = smu_sat_get_sdb_partition(chip, 0xC4 + core, NULL); if (hdr) { struct smu_sdbp_fvt *fvt = (struct smu_sdbp_fvt *)&hdr[1];
tmax = fvt->maxtemp << 16;
} else
tmax = 95 << 16; /* default to 95 degrees C */
/* We keep a global tmax for overtemp calculations */ if (tmax < cpu_all_tmax)
cpu_all_tmax = tmax;
kfree(hdr);
/* Get PID params from the appropriate SAT */
hdr = smu_sat_get_sdb_partition(chip, 0xC8 + core, NULL); if (hdr == NULL) {
printk(KERN_WARNING"windfarm: can't get CPU PID fan config\n"); return -EINVAL;
}
piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
/* * Darwin has a minimum fan speed of 1000 rpm for the 4-way and * 515 for the 2-way. That appears to be overkill, so for now, * impose a minimum of 750 or 515.
*/
fmin = (nr_cores > 2) ? 750 : 515;
/* We max all CPU fans in case of a sensor error. We also do the * cpufreq clamping now, even if it's supposedly done later by the * generic code anyway, we do it earlier here to react faster
*/ if (cpufreq_clamp)
wf_control_set_max(cpufreq_clamp); for (i = 0; i < NR_CPU_FANS; ++i) if (cpu_fans[i])
wf_control_set_max(cpu_fans[i]);
}
/* First check for immediate overtemps */ if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
new_state |= FAILURE_LOW_OVERTEMP; if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
printk(KERN_ERR "windfarm: Overtemp due to immediate CPU" " temperature !\n");
} if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
new_state |= FAILURE_HIGH_OVERTEMP; if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
printk(KERN_ERR "windfarm: Critical overtemp due to" " immediate CPU temperature !\n");
}
/* We calculate a history of max temperatures and use that for the * overtemp management
*/
t_old = cpu_thist[cpu_thist_pt];
cpu_thist[cpu_thist_pt] = temp;
cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
cpu_thist_total -= t_old;
cpu_thist_total += temp;
t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
/* Now check for average overtemps */ if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
new_state |= FAILURE_LOW_OVERTEMP; if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
printk(KERN_ERR "windfarm: Overtemp due to average CPU" " temperature !\n");
} if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
new_state |= FAILURE_HIGH_OVERTEMP; if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
printk(KERN_ERR "windfarm: Critical overtemp due to" " average CPU temperature !\n");
}
/* Now handle overtemp conditions. We don't currently use the windfarm * overtemp handling core as it's not fully suited to the needs of those * new machine. This will be fixed later.
*/ if (new_state) { /* High overtemp -> immediate shutdown */ if (new_state & FAILURE_HIGH_OVERTEMP)
machine_power_off(); if ((failure_state & new_state) != new_state)
cpu_max_all_fans();
failure_state |= new_state;
} elseif ((failure_state & FAILURE_LOW_OVERTEMP) &&
(temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
failure_state &= ~FAILURE_LOW_OVERTEMP;
}
DBG_LOTS(KERN_DEBUG); for (cpu = 0; cpu < nr_cores; ++cpu) { /* Get CPU core temperature */
sr = sens_cpu_temp[cpu];
err = sr->ops->get_value(sr, &temp); if (err) {
DBG("\n");
printk(KERN_WARNING "windfarm: CPU %d temperature " "sensor error %d\n", cpu, err);
failure_state |= FAILURE_SENSOR;
cpu_max_all_fans(); return;
}
/* Get CPU power */
sr = sens_cpu_power[cpu];
err = sr->ops->get_value(sr, &power); if (err) {
DBG("\n");
printk(KERN_WARNING "windfarm: CPU %d power " "sensor error %d\n", cpu, err);
failure_state |= FAILURE_SENSOR;
cpu_max_all_fans(); return;
}
/* Run PID */
sp = &cpu_pid[cpu];
t = wf_cpu_pid_run(sp, power, temp);
err = slots_fan->ops->set_value(slots_fan, speed); if (err) {
printk(KERN_WARNING "windfarm: slots fan error %d\n", err);
failure_state |= FAILURE_FAN;
}
}
staticvoid set_fail_state(void)
{ int i;
if (cpufreq_clamp)
wf_control_set_max(cpufreq_clamp); for (i = 0; i < NR_CPU_FANS; ++i) if (cpu_fans[i])
wf_control_set_max(cpu_fans[i]); if (backside_fan)
wf_control_set_max(backside_fan); if (slots_fan)
wf_control_set_max(slots_fan); if (drive_bay_fan)
wf_control_set_max(drive_bay_fan);
}
staticvoid pm112_tick(void)
{ int i, last_failure;
if (!started) {
started = true;
printk(KERN_INFO "windfarm: CPUs control loops started.\n"); for (i = 0; i < nr_cores; ++i) { if (create_cpu_loop(i) < 0) {
failure_state = FAILURE_PERM;
set_fail_state(); break;
}
}
DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
/* Permanent failure, bail out */ if (failure_state & FAILURE_PERM) return; /* Clear all failure bits except low overtemp which will be eventually * cleared by the control loop itself
*/
last_failure = failure_state;
failure_state &= FAILURE_LOW_OVERTEMP;
cpu_fans_tick();
backside_fan_tick();
slots_fan_tick();
drive_bay_fan_tick();
MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
MODULE_DESCRIPTION("Thermal control for PowerMac11,2");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:windfarm");
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-04-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.