/* 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_chips; i++) { if (cpu_fans[i][0])
wf_control_set_max(cpu_fans[i][0]); if (cpu_fans[i][1])
wf_control_set_max(cpu_fans[i][1]); if (cpu_fans[i][2])
wf_control_set_max(cpu_fans[i][2]);
}
}
staticint cpu_check_overtemp(s32 temp)
{ int new_state = 0;
s32 t_avg, t_old; staticbool first = true;
/* 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");
}
/* * The first time around, initialize the array with the first * temperature reading
*/ if (first) { int i;
cpu_thist_total = 0; for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
cpu_thist[i] = temp;
cpu_thist_total += temp;
}
first = false;
}
/* * 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;
}
/* Get voltage */
rc = wf_sensor_get(sens_cpu_volts[cpu], &volts); if (rc) {
DBG(" CPU%d, volts reading error !\n", cpu); return -EIO;
}
DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
/* Get current */
rc = wf_sensor_get(sens_cpu_amps[cpu], &s); if (rc) {
DBG(" CPU%d, current reading error !\n", cpu); return -EIO;
}
DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
/* Calculate power */
/* Scale voltage and current raw sensor values according to fixed scales * obtained in Darwin and calculate power from I and V
*/
*power = (((u64)volts) * ((u64)amps)) >> 16;
DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
/* Apply result to all cpu fans */ for (i = 0; i < 3; i++) {
err = wf_control_set(cpu_fans[cpu][i], speed); if (err) {
pr_warn("wf_rm31: Fan %s reports error %d\n",
cpu_fans[cpu][i]->name, err);
failure_state |= FAILURE_FAN;
}
}
}
}
/* We keep a global tmax for overtemp calculations */ if (tmax < cpu_all_tmax)
cpu_all_tmax = tmax;
/* Set PID min/max by using the rear fan min/max */
fmin = wf_control_get_min(cpu_fans[cpu][0]);
fmax = wf_control_get_max(cpu_fans[cpu][0]);
DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
/* History size */
hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
if (backside_fan)
wf_control_set_max(backside_fan); if (slots_fan)
wf_control_set_max(slots_fan);
}
staticvoid rm31_tick(void)
{ int i, last_failure;
if (!started) {
started = true;
printk(KERN_INFO "windfarm: CPUs control loops started.\n"); for (i = 0; i < nr_chips; ++i) { if (cpu_setup_pid(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;
backside_fan_tick();
slots_fan_tick();
/* We do CPUs last because they can be clamped high by * DIMM temperature
*/
cpu_fans_tick();
staticint __init wf_rm31_init(void)
{ struct device_node *cpu; int i;
if (!of_machine_is_compatible("RackMac3,1")) return -ENODEV;
/* Count the number of CPU cores */
nr_chips = 0;
for_each_node_by_type(cpu, "cpu")
++nr_chips; if (nr_chips > NR_CHIPS)
nr_chips = NR_CHIPS;
pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
nr_chips);
/* Get MPU data for each CPU */ for (i = 0; i < nr_chips; i++) {
cpu_mpu_data[i] = wf_get_mpu(i); if (!cpu_mpu_data[i]) {
pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i); return -ENXIO;
}
}
MODULE_AUTHOR("Benjamin Herrenschmidt ");
MODULE_DESCRIPTION("Thermal control for Xserve G5");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:windfarm");
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.