static void set_fail_state(void) { cpu_max_all_fans(); if (backside_fan) wf_control_set_max(backside_fan); if (slots_fan) wf_control_set_max(slots_fan); }
static void backside_fan_tick(void) { s32 temp, dtemp; int speed, dspeed, fan_min; int err; if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick) return; if (--backside_tick > 0) return; backside_tick = backside_pid.param.interval; DBG_LOTS("* backside fans tick\n"); /* Update fan speed from actual fans */ err = wf_control_get(backside_fan, &speed); if (!err) backside_pid.target = speed; err = wf_sensor_get(backside_temp, &temp); if (err) { printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n", err); failure_state |= FAILURE_SENSOR; wf_control_set_max(backside_fan); return; } speed = wf_pid_run(&backside_pid, temp); DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n", FIX32TOPRINT(temp), speed); err = wf_sensor_get(dimms_temp, &dtemp); if (err) { printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n", err); failure_state |= FAILURE_SENSOR; wf_control_set_max(backside_fan); return; } dspeed = wf_pid_run(&dimms_pid, dtemp); dimms_output_clamp = dspeed; fan_min = (dspeed * 100) / 14000; fan_min = max(fan_min, backside_param.min); speed = max(speed, fan_min); err = wf_control_set(backside_fan, speed); if (err) { printk(KERN_WARNING "windfarm: backside fan error %d\n", err); failure_state |= FAILURE_FAN; } }
static void cpu_max_all_fans(void) { int i; /* 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]); }
static void slots_fan_tick(void) { s32 temp; int speed; int err; if (!slots_fan || !slots_temp || !slots_tick) return; if (--slots_tick > 0) return; slots_tick = slots_pid.param.interval; DBG_LOTS("* slots fans tick\n"); err = wf_sensor_get(slots_temp, &temp); if (err) { pr_warning("wf_rm31: slots temp sensor error %d\n", err); failure_state |= FAILURE_SENSOR; wf_control_set_max(slots_fan); return; } speed = wf_pid_run(&slots_pid, temp); DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n", FIX32TOPRINT(temp), speed); slots_speed = speed; err = wf_control_set(slots_fan, speed); if (err) { printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err); failure_state |= FAILURE_FAN; } }
static void 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); }
static void slots_fan_tick(void) { s32 power; int speed; int err; if (!slots_fan || !slots_power) return; if (!slots_started) { /* first time; initialize things */ ; wf_pid_init(&slots_pid, &slots_param); slots_started = 1; } err = slots_power->ops->get_value(slots_power, &power); if (err) { // printk(KERN_WARNING "windfarm: slots power sensor error %d\n", ; failure_state |= FAILURE_SENSOR; wf_control_set_max(slots_fan); return; } speed = wf_pid_run(&slots_pid, power); DBG_LOTS("slots PID power=%d.%.3d speed=%d\n", FIX32TOPRINT(power), speed); err = slots_fan->ops->set_value(slots_fan, speed); if (err) { ; failure_state |= FAILURE_FAN; } }
static void pm72_tick(void) { int i, last_failure; if (!started) { started = 1; 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)); backside_setup_pid(); drives_setup_pid(); /* * We don't have the right stuff to drive the PCI fan * so we fix it to a default value */ wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM); #ifdef HACKED_OVERTEMP cpu_all_tmax = 60 << 16; #endif } /* 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; if (cpu_pid_combined) cpu_fans_tick_combined(); else cpu_fans_tick_split(); backside_fan_tick(); drives_fan_tick(); DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n", last_failure, failure_state); /* Check for failures. Any failure causes cpufreq clamping */ if (failure_state && last_failure == 0 && cpufreq_clamp) wf_control_set_max(cpufreq_clamp); if (failure_state == 0 && last_failure && cpufreq_clamp) wf_control_set_min(cpufreq_clamp); /* That's it for now, we might want to deal with other failures * differently in the future though */ }
static void rm31_tick(void) { int i, last_failure; if (!started) { started = 1; 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)); backside_setup_pid(); slots_setup_pid(); #ifdef HACKED_OVERTEMP cpu_all_tmax = 60 << 16; #endif } /* 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(); DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n", last_failure, failure_state); /* Check for failures. Any failure causes cpufreq clamping */ if (failure_state && last_failure == 0 && cpufreq_clamp) wf_control_set_max(cpufreq_clamp); if (failure_state == 0 && last_failure && cpufreq_clamp) wf_control_set_min(cpufreq_clamp); /* That's it for now, we might want to deal with other failures * differently in the future though */ }
static void pm112_tick(void) { int i, last_failure; if (!started) { started = 1; ; 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)); #ifdef HACKED_OVERTEMP cpu_all_tmax = 60 << 16; #endif } /* 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(); DBG_LOTS("last_failure: 0x%x, failure_state: %x\n", last_failure, failure_state); /* Check for failures. Any failure causes cpufreq clamping */ if (failure_state && last_failure == 0 && cpufreq_clamp) wf_control_set_max(cpufreq_clamp); if (failure_state == 0 && last_failure && cpufreq_clamp) wf_control_set_min(cpufreq_clamp); /* That's it for now, we might want to deal with other failures * differently in the future though */ }
static void backside_fan_tick(void) { s32 temp; int speed; int err; if (!backside_fan || !backside_temp || !backside_tick) return; if (--backside_tick > 0) return; backside_tick = backside_pid.param.interval; DBG_LOTS("* backside fans tick\n"); /* Update fan speed from actual fans */ err = wf_control_get(backside_fan, &speed); if (!err) backside_pid.target = speed; err = wf_sensor_get(backside_temp, &temp); if (err) { printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n", err); failure_state |= FAILURE_SENSOR; wf_control_set_max(backside_fan); return; } speed = wf_pid_run(&backside_pid, temp); DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n", FIX32TOPRINT(temp), speed); err = wf_control_set(backside_fan, speed); if (err) { printk(KERN_WARNING "windfarm: backside fan error %d\n", err); failure_state |= FAILURE_FAN; } }
static void drive_bay_fan_tick(void) { s32 temp; int speed; int err; if (!drive_bay_fan || !hd_temp) return; if (!drive_bay_tick) { /* first time; initialize things */ ; drive_bay_prm.min = drive_bay_fan->ops->get_min(drive_bay_fan); drive_bay_prm.max = drive_bay_fan->ops->get_max(drive_bay_fan); wf_pid_init(&drive_bay_pid, &drive_bay_prm); drive_bay_tick = 1; } if (--drive_bay_tick > 0) return; drive_bay_tick = drive_bay_pid.param.interval; err = hd_temp->ops->get_value(hd_temp, &temp); if (err) { // printk(KERN_WARNING "windfarm: drive bay temp sensor " ; failure_state |= FAILURE_SENSOR; wf_control_set_max(drive_bay_fan); return; } speed = wf_pid_run(&drive_bay_pid, temp); DBG_LOTS("drive_bay PID temp=%d.%.3d speed=%d\n", FIX32TOPRINT(temp), speed); err = drive_bay_fan->ops->set_value(drive_bay_fan, speed); if (err) { ; failure_state |= FAILURE_FAN; } }
static void backside_fan_tick(void) { s32 temp; int speed; int err; if (!backside_fan || !u4_temp) return; if (!backside_tick) { /* first time; initialize things */ ; backside_param.min = backside_fan->ops->get_min(backside_fan); backside_param.max = backside_fan->ops->get_max(backside_fan); wf_pid_init(&backside_pid, &backside_param); backside_tick = 1; } if (--backside_tick > 0) return; backside_tick = backside_pid.param.interval; err = u4_temp->ops->get_value(u4_temp, &temp); if (err) { // printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n", ; failure_state |= FAILURE_SENSOR; wf_control_set_max(backside_fan); return; } speed = wf_pid_run(&backside_pid, temp); DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n", FIX32TOPRINT(temp), speed); err = backside_fan->ops->set_value(backside_fan, speed); if (err) { ; failure_state |= FAILURE_FAN; } }
static void drives_fan_tick(void) { s32 temp; int speed; int err; if (!drives_fan || !drives_temp || !drives_tick) return; if (--drives_tick > 0) return; drives_tick = drives_pid.param.interval; DBG_LOTS("* drives fans tick\n"); /* Update fan speed from actual fans */ err = wf_control_get(drives_fan, &speed); if (!err) drives_pid.target = speed; err = wf_sensor_get(drives_temp, &temp); if (err) { pr_warning("wf_pm72: drive bay temp sensor error %d\n", err); failure_state |= FAILURE_SENSOR; wf_control_set_max(drives_fan); return; } speed = wf_pid_run(&drives_pid, temp); DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n", FIX32TOPRINT(temp), speed); err = wf_control_set(drives_fan, speed); if (err) { printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err); failure_state |= FAILURE_FAN; } }
static void wf_smu_create_drive_fans(void) { struct wf_pid_param param = { .interval = 5, .history_len = 2, .gd = 0x01e00000, .gp = 0x00500000, .gr = 0x00000000, .itarget = 0x00200000, }; /* Alloc & initialize state */ wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state), GFP_KERNEL); if (wf_smu_drive_fans == NULL) { printk(KERN_WARNING "windfarm: Memory allocation error" " max fan speed\n"); goto fail; } wf_smu_drive_fans->ticks = 1; /* Fill PID params */ param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN); param.min = fan_hd->ops->get_min(fan_hd); param.max = fan_hd->ops->get_max(fan_hd); wf_pid_init(&wf_smu_drive_fans->pid, ¶m); DBG("wf: Drive Fan control initialized.\n"); DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", FIX32TOPRINT(param.itarget), param.min, param.max); return; fail: if (fan_hd) wf_control_set_max(fan_hd); } static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st) { s32 new_setpoint, temp; int rc; if (--st->ticks != 0) { if (wf_smu_readjust) goto readjust; return; } st->ticks = st->pid.param.interval; rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp); if (rc) { printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", rc); wf_smu_failure_state |= FAILURE_SENSOR; return; } DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n", FIX32TOPRINT(temp)); if (temp > (st->pid.param.itarget + 0x50000)) wf_smu_failure_state |= FAILURE_OVERTEMP; new_setpoint = wf_pid_run(&st->pid, temp); DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint); if (st->setpoint == new_setpoint) return; st->setpoint = new_setpoint; readjust: if (fan_hd && wf_smu_failure_state == 0) { rc = fan_hd->ops->set_value(fan_hd, st->setpoint); if (rc) { printk(KERN_WARNING "windfarm: HD fan error %d\n", rc); wf_smu_failure_state |= FAILURE_FAN; } } }
static void wf_smu_create_cpu_fans(void) { struct wf_cpu_pid_param pid_param; const struct smu_sdbp_header *hdr; struct smu_sdbp_cpupiddata *piddata; struct smu_sdbp_fvt *fvt; s32 tmax, tdelta, maxpow, powadj; /* First, locate the PID params in SMU SBD */ hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); if (hdr == 0) { printk(KERN_WARNING "windfarm: CPU PID fan config not found " "max fan speed\n"); goto fail; } piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; /* Get the FVT params for operating point 0 (the only supported one * for now) in order to get tmax */ hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); if (hdr) { fvt = (struct smu_sdbp_fvt *)&hdr[1]; tmax = ((s32)fvt->maxtemp) << 16; } else tmax = 0x5e0000; /* 94 degree default */ /* Alloc & initialize state */ wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state), GFP_KERNEL); if (wf_smu_cpu_fans == NULL) goto fail; wf_smu_cpu_fans->ticks = 1; /* Fill PID params */ pid_param.interval = WF_SMU_CPU_FANS_INTERVAL; pid_param.history_len = piddata->history_len; if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { printk(KERN_WARNING "windfarm: History size overflow on " "CPU control loop (%d)\n", piddata->history_len); pid_param.history_len = WF_CPU_PID_MAX_HISTORY; } pid_param.gd = piddata->gd; pid_param.gp = piddata->gp; pid_param.gr = piddata->gr / pid_param.history_len; tdelta = ((s32)piddata->target_temp_delta) << 16; maxpow = ((s32)piddata->max_power) << 16; powadj = ((s32)piddata->power_adj) << 16; pid_param.tmax = tmax; pid_param.ttarget = tmax - tdelta; pid_param.pmaxadj = maxpow - powadj; pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main); pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main); wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); DBG("wf: CPU Fan control initialized.\n"); DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n", FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), pid_param.min, pid_param.max); return; fail: printk(KERN_WARNING "windfarm: CPU fan config not found\n" "for this machine model, max fan speed\n"); if (cpufreq_clamp) wf_control_set_max(cpufreq_clamp); if (fan_cpu_main) wf_control_set_max(fan_cpu_main); }
static void wf_smu_create_slots_fans(void) { struct wf_pid_param param = { .interval = 1, .history_len = 8, .gd = 0x00000000, .gp = 0x00000000, .gr = 0x00020000, .itarget = 0x00000000 }; /* Alloc & initialize state */ wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state), GFP_KERNEL); if (wf_smu_slots_fans == NULL) { printk(KERN_WARNING "windfarm: Memory allocation error" " max fan speed\n"); goto fail; } wf_smu_slots_fans->ticks = 1; /* Fill PID params */ param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN); param.min = fan_slots->ops->get_min(fan_slots); param.max = fan_slots->ops->get_max(fan_slots); wf_pid_init(&wf_smu_slots_fans->pid, ¶m); DBG("wf: Slots Fan control initialized.\n"); DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", FIX32TOPRINT(param.itarget), param.min, param.max); return; fail: if (fan_slots) wf_control_set_max(fan_slots); } static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st) { s32 new_setpoint, power; int rc; if (--st->ticks != 0) { if (wf_smu_readjust) goto readjust; return; } st->ticks = st->pid.param.interval; rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power); if (rc) { printk(KERN_WARNING "windfarm: Slots power sensor error %d\n", rc); wf_smu_failure_state |= FAILURE_SENSOR; return; } DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n", FIX32TOPRINT(power)); #if 0 /* Check what makes a good overtemp condition */ if (power > (st->pid.param.itarget + 0x50000)) wf_smu_failure_state |= FAILURE_OVERTEMP; #endif new_setpoint = wf_pid_run(&st->pid, power); DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint); if (st->setpoint == new_setpoint) return; st->setpoint = new_setpoint; readjust: if (fan_slots && wf_smu_failure_state == 0) { rc = fan_slots->ops->set_value(fan_slots, st->setpoint); if (rc) { printk(KERN_WARNING "windfarm: Slots fan error %d\n", rc); wf_smu_failure_state |= FAILURE_FAN; } } }
static void wf_smu_tick(void) { unsigned int last_failure = wf_smu_failure_state; unsigned int new_failure; if (!wf_smu_started) { DBG("wf: creating control loops !\n"); wf_smu_create_drive_fans(); wf_smu_create_slots_fans(); wf_smu_create_cpu_fans(); wf_smu_started = 1; } /* Skipping ticks */ if (wf_smu_skipping && --wf_smu_skipping) return; wf_smu_failure_state = 0; if (wf_smu_drive_fans) wf_smu_drive_fans_tick(wf_smu_drive_fans); if (wf_smu_slots_fans) wf_smu_slots_fans_tick(wf_smu_slots_fans); if (wf_smu_cpu_fans) wf_smu_cpu_fans_tick(wf_smu_cpu_fans); wf_smu_readjust = 0; new_failure = wf_smu_failure_state & ~last_failure; /* If entering failure mode, clamp cpufreq and ramp all * fans to full speed. */ if (wf_smu_failure_state && !last_failure) { if (cpufreq_clamp) wf_control_set_max(cpufreq_clamp); if (fan_cpu_main) wf_control_set_max(fan_cpu_main); if (fan_cpu_second) wf_control_set_max(fan_cpu_second); if (fan_cpu_third) wf_control_set_max(fan_cpu_third); if (fan_hd) wf_control_set_max(fan_hd); if (fan_slots) wf_control_set_max(fan_slots); } /* If leaving failure mode, unclamp cpufreq and readjust * all fans on next iteration */ if (!wf_smu_failure_state && last_failure) { if (cpufreq_clamp) wf_control_set_min(cpufreq_clamp); wf_smu_readjust = 1; } /* Overtemp condition detected, notify and start skipping a couple * ticks to let the temperature go down */ if (new_failure & FAILURE_OVERTEMP) { wf_set_overtemp(); wf_smu_skipping = 2; } /* We only clear the overtemp condition if overtemp is cleared * _and_ no other failure is present. Since a sensor error will * clear the overtemp condition (can't measure temperature) at * the control loop levels, but we don't want to keep it clear * here in this case */ if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) wf_clear_overtemp(); }
static void wf_smu_tick(void) { unsigned int last_failure = wf_smu_failure_state; unsigned int new_failure; if (!wf_smu_started) { DBG("wf: creating control loops !\n"); wf_smu_create_drive_fans(); wf_smu_create_slots_fans(); wf_smu_create_cpu_fans(); wf_smu_started = 1; } if (wf_smu_skipping && --wf_smu_skipping) return; wf_smu_failure_state = 0; if (wf_smu_drive_fans) wf_smu_drive_fans_tick(wf_smu_drive_fans); if (wf_smu_slots_fans) wf_smu_slots_fans_tick(wf_smu_slots_fans); if (wf_smu_cpu_fans) wf_smu_cpu_fans_tick(wf_smu_cpu_fans); wf_smu_readjust = 0; new_failure = wf_smu_failure_state & ~last_failure; if (wf_smu_failure_state && !last_failure) { if (cpufreq_clamp) wf_control_set_max(cpufreq_clamp); if (fan_cpu_main) wf_control_set_max(fan_cpu_main); if (fan_cpu_second) wf_control_set_max(fan_cpu_second); if (fan_cpu_third) wf_control_set_max(fan_cpu_third); if (fan_hd) wf_control_set_max(fan_hd); if (fan_slots) wf_control_set_max(fan_slots); } if (!wf_smu_failure_state && last_failure) { if (cpufreq_clamp) wf_control_set_min(cpufreq_clamp); wf_smu_readjust = 1; } if (new_failure & FAILURE_OVERTEMP) { wf_set_overtemp(); wf_smu_skipping = 2; } if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) wf_clear_overtemp(); }