static void cpu_fans_tick_split(void) { int err, cpu; s32 intake, temp, power, t_max = 0; DBG_LOTS("* cpu fans_tick_split()\n"); for (cpu = 0; cpu < nr_chips; ++cpu) { struct wf_cpu_pid_state *sp = &cpu_pid[cpu]; /* Read current speed */ wf_control_get(cpu_rear_fans[cpu], &sp->target); DBG_LOTS(" CPU%d: cur_target = %d RPM\n", cpu, sp->target); err = read_one_cpu_vals(cpu, &temp, &power); if (err) { failure_state |= FAILURE_SENSOR; cpu_max_all_fans(); return; } /* Keep track of highest temp */ t_max = max(t_max, temp); /* Handle possible overtemps */ if (cpu_check_overtemp(t_max)) return; /* Run PID */ wf_cpu_pid_run(sp, power, temp); DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target); /* Apply result directly to exhaust fan */ err = wf_control_set(cpu_rear_fans[cpu], sp->target); if (err) { pr_warning("wf_pm72: Fan %s reports error %d\n", cpu_rear_fans[cpu]->name, err); failure_state |= FAILURE_FAN; break; } /* Scale result for intake fan */ intake = (sp->target * CPU_INTAKE_SCALE) >> 16; DBG_LOTS(" CPU%d: intake = %d RPM\n", cpu, intake); err = wf_control_set(cpu_front_fans[cpu], intake); if (err) { pr_warning("wf_pm72: Fan %s reports error %d\n", cpu_front_fans[cpu]->name, err); failure_state |= FAILURE_FAN; break; } } }
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 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 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_fans_tick(void) { int err, cpu, i; s32 speed, temp, power, t_max = 0; DBG_LOTS("* cpu fans_tick_split()\n"); for (cpu = 0; cpu < nr_chips; ++cpu) { struct wf_cpu_pid_state *sp = &cpu_pid[cpu]; /* Read current speed */ wf_control_get(cpu_fans[cpu][0], &sp->target); err = read_one_cpu_vals(cpu, &temp, &power); if (err) { failure_state |= FAILURE_SENSOR; cpu_max_all_fans(); return; } /* Keep track of highest temp */ t_max = max(t_max, temp); /* Handle possible overtemps */ if (cpu_check_overtemp(t_max)) return; /* Run PID */ wf_cpu_pid_run(sp, power, temp); DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target); /* Apply DIMMs clamp */ speed = max(sp->target, dimms_output_clamp); /* Apply result to all cpu fans */ for (i = 0; i < 3; i++) { err = wf_control_set(cpu_fans[cpu][i], speed); if (err) { pr_warning("wf_rm31: Fan %s reports error %d\n", cpu_fans[cpu][i]->name, err); failure_state |= FAILURE_FAN; } } } }
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 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_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 = wf_control_get_min(fan_slots); param.max = wf_control_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 = wf_sensor_get(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 = wf_control_set(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_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 = wf_control_get_min(fan_hd); param.max = wf_control_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 = wf_sensor_get(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 = wf_control_set(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_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) { s32 new_setpoint, temp, power; int rc; if (--st->ticks != 0) { if (wf_smu_readjust) goto readjust; return; } st->ticks = WF_SMU_CPU_FANS_INTERVAL; rc = wf_sensor_get(sensor_cpu_temp, &temp); if (rc) { printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", rc); wf_smu_failure_state |= FAILURE_SENSOR; return; } rc = wf_sensor_get(sensor_cpu_power, &power); if (rc) { printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", rc); wf_smu_failure_state |= FAILURE_SENSOR; return; } DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n", FIX32TOPRINT(temp), FIX32TOPRINT(power)); #ifdef HACKED_OVERTEMP if (temp > 0x4a0000) wf_smu_failure_state |= FAILURE_OVERTEMP; #else if (temp > st->pid.param.tmax) wf_smu_failure_state |= FAILURE_OVERTEMP; #endif new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint); if (st->cpu_setpoint == new_setpoint) return; st->cpu_setpoint = new_setpoint; readjust: if (fan_cpu_main && wf_smu_failure_state == 0) { rc = wf_control_set(fan_cpu_main, st->cpu_setpoint); if (rc) { printk(KERN_WARNING "windfarm: CPU main fan" " error %d\n", rc); wf_smu_failure_state |= FAILURE_FAN; } } if (fan_cpu_second && wf_smu_failure_state == 0) { rc = wf_control_set(fan_cpu_second, st->cpu_setpoint); if (rc) { printk(KERN_WARNING "windfarm: CPU second fan" " error %d\n", rc); wf_smu_failure_state |= FAILURE_FAN; } } if (fan_cpu_third && wf_smu_failure_state == 0) { rc = wf_control_set(fan_cpu_third, st->cpu_setpoint); if (rc) { printk(KERN_WARNING "windfarm: CPU third fan" " error %d\n", rc); wf_smu_failure_state |= FAILURE_FAN; } } }
static void cpu_fans_tick_combined(void) { s32 temp0, power0, temp1, power1, t_max = 0; s32 temp, power, intake, pump; struct wf_control *pump0, *pump1; struct wf_cpu_pid_state *sp = &cpu_pid[0]; int err, cpu; DBG_LOTS("* cpu fans_tick_combined()\n"); /* Read current speed from cpu 0 */ wf_control_get(cpu_rear_fans[0], &sp->target); DBG_LOTS(" CPUs: cur_target = %d RPM\n", sp->target); /* Read values for both CPUs */ err = read_one_cpu_vals(0, &temp0, &power0); if (err) { failure_state |= FAILURE_SENSOR; cpu_max_all_fans(); return; } err = read_one_cpu_vals(1, &temp1, &power1); if (err) { failure_state |= FAILURE_SENSOR; cpu_max_all_fans(); return; } /* Keep track of highest temp */ t_max = max(t_max, max(temp0, temp1)); /* Handle possible overtemps */ if (cpu_check_overtemp(t_max)) return; /* Use the max temp & power of both */ temp = max(temp0, temp1); power = max(power0, power1); /* Run PID */ wf_cpu_pid_run(sp, power, temp); /* Scale result for intake fan */ intake = (sp->target * CPU_INTAKE_SCALE) >> 16; /* Same deal with pump speed */ pump0 = cpu_pumps[0]; pump1 = cpu_pumps[1]; if (!pump0) { pump0 = pump1; pump1 = NULL; } pump = (sp->target * wf_control_get_max(pump0)) / cpu_mpu_data[0]->rmaxn_exhaust_fan; DBG_LOTS(" CPUs: target = %d RPM\n", sp->target); DBG_LOTS(" CPUs: intake = %d RPM\n", intake); DBG_LOTS(" CPUs: pump = %d RPM\n", pump); for (cpu = 0; cpu < nr_chips; cpu++) { err = wf_control_set(cpu_rear_fans[cpu], sp->target); if (err) { pr_warning("wf_pm72: Fan %s reports error %d\n", cpu_rear_fans[cpu]->name, err); failure_state |= FAILURE_FAN; } err = wf_control_set(cpu_front_fans[cpu], intake); if (err) { pr_warning("wf_pm72: Fan %s reports error %d\n", cpu_front_fans[cpu]->name, err); failure_state |= FAILURE_FAN; } err = 0; if (cpu_pumps[cpu]) err = wf_control_set(cpu_pumps[cpu], pump); if (err) { pr_warning("wf_pm72: Pump %s reports error %d\n", cpu_pumps[cpu]->name, err); failure_state |= FAILURE_FAN; } } }