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;
	}
}
Example #2
0
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
     */
}
Example #4
0
/* Implementation... */
static int cpu_setup_pid(int cpu)
{
	struct wf_cpu_pid_param pid;
	const struct mpu_data *mpu = cpu_mpu_data[cpu];
	s32 tmax, ttarget, ptarget;
	int fmin, fmax, hsize;

	/* Get PID params from the appropriate MPU EEPROM */
	tmax = mpu->tmax << 16;
	ttarget = mpu->ttarget << 16;
	ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;

	DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
	    cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));

	/* 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);

	/* Initialize PID loop */
	pid.interval	= 1;	/* seconds */
	pid.history_len = hsize;
	pid.gd		= mpu->pid_gd;
	pid.gp		= mpu->pid_gp;
	pid.gr		= mpu->pid_gr;
	pid.tmax	= tmax;
	pid.ttarget	= ttarget;
	pid.pmaxadj	= ptarget;
	pid.min		= fmin;
	pid.max		= fmax;

	wf_cpu_pid_init(&cpu_pid[cpu], &pid);
	cpu_pid[cpu].target = 4000;
	
	return 0;
}
Example #5
0
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
	 */
}
Example #6
0
static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
{
	s32 dtemp, volts, amps;
	int rc;

	/* Get diode temperature */
	rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
	if (rc) {
		DBG("  CPU%d: temp reading error !\n", cpu);
		return -EIO;
	}
	DBG_LOTS("  CPU%d: temp   = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
	*temp = dtemp;

	/* 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], &amps);
	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)));

	return 0;

}
Example #7
0
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;
	}
}
Example #8
0
/*
 * CPUs fans control loop
 */
static void do_monitor_cpu(struct cpu_pid_state *state)
{
	s32 temp, voltage, current_a, power, power_target;
	s32 integral, derivative, proportional, adj_in_target, sval;
	s64 integ_p, deriv_p, prop_p, sum; 
	int i, intake, rc;

	DBG("cpu %d:\n", state->index);

	/* Read current fan status */
	if (state->index == 0)
		rc = get_rpm_fan(CPUA_EXHAUST_FAN_RPM_ID, !RPM_PID_USE_ACTUAL_SPEED);
	else
		rc = get_rpm_fan(CPUB_EXHAUST_FAN_RPM_ID, !RPM_PID_USE_ACTUAL_SPEED);
	if (rc < 0) {
		printk(KERN_WARNING "Error %d reading CPU %d exhaust fan !\n",
		       rc, state->index);
		/* XXX What do we do now ? */
	} else
		state->rpm = rc;
	DBG("  current rpm: %d\n", state->rpm);

	/* Get some sensor readings and scale it */
	temp = read_smon_adc(state, 1);
	if (temp == -1) {
		state->overtemp++;
		return;
	}
	voltage = read_smon_adc(state, 3);
	current_a = read_smon_adc(state, 4);

	/* Fixup temperature according to diode calibration
	 */
	DBG("  temp raw: %04x, m_diode: %04x, b_diode: %04x\n",
	    temp, state->mpu.mdiode, state->mpu.bdiode);
	temp = ((s32)temp * (s32)state->mpu.mdiode + ((s32)state->mpu.bdiode << 12)) >> 2;
	state->last_temp = temp;
	DBG("  temp: %d.%03d\n", FIX32TOPRINT(temp));

	/* Check tmax, increment overtemp if we are there. At tmax+8, we go
	 * full blown immediately and try to trigger a shutdown
	 */
	if (temp >= ((state->mpu.tmax + 8) << 16)) {
		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum"
		       " (%d) !\n",
		       state->index, temp >> 16);
		state->overtemp = CPU_MAX_OVERTEMP;
	} else if (temp > (state->mpu.tmax << 16))
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
	 */
}
Example #10
0
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;
	}
}
Example #11
0
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 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_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 = sensor_cpu_temp->ops->get_value(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 = sensor_cpu_power->ops->get_value(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 = fan_cpu_main->ops->set_value(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 = fan_cpu_second->ops->set_value(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 = fan_cpu_main->ops->set_value(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 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);
}
Example #16
0
static void cpu_fans_tick(void)
{
	int err, cpu;
	s32 greatest_delta = 0;
	s32 temp, power, t_max = 0;
	int i, t, target = 0;
	struct wf_sensor *sr;
	struct wf_control *ct;
	struct wf_cpu_pid_state *sp;

	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 "
;
			failure_state |= FAILURE_SENSOR;
			cpu_max_all_fans();
			return;
		}

		/* Keep track of highest temp */
		t_max = max(t_max, temp);

		/* 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 "
;
			failure_state |= FAILURE_SENSOR;
			cpu_max_all_fans();
			return;
		}

		/* Run PID */
		sp = &cpu_pid[cpu];
		t = wf_cpu_pid_run(sp, power, temp);

		if (cpu == 0 || sp->last_delta > greatest_delta) {
			greatest_delta = sp->last_delta;
			target = t;
		}
		DBG_LOTS("[%d] P=%d.%.3d T=%d.%.3d ",
		    cpu, FIX32TOPRINT(power), FIX32TOPRINT(temp));
	}
	DBG_LOTS("fans = %d, t_max = %d.%03d\n", target, FIX32TOPRINT(t_max));

	/* Darwin limits decrease to 20 per iteration */
	if (target < (cpu_last_target - 20))
		target = cpu_last_target - 20;
	cpu_last_target = target;
	for (cpu = 0; cpu < nr_cores; ++cpu)
		cpu_pid[cpu].target = target;

	/* Handle possible overtemps */
	if (cpu_check_overtemp(t_max))
		return;

	/* Set fans */
	for (i = 0; i < NR_CPU_FANS; ++i) {
		ct = cpu_fans[i];
		if (ct == NULL)
			continue;
		err = ct->ops->set_value(ct, target * cpu_fan_scale[i] / 100);
		if (err) {
//			printk(KERN_WARNING "windfarm: fan %s reports "
;
			failure_state |= FAILURE_FAN;
			break;
		}
	}
}
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, &param);

    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_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, &param);

    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;
        }
    }
}
Example #19
0
static int cpu_check_overtemp(s32 temp)
{
	int new_state = 0;
	s32 t_avg, t_old;
	static bool 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;

	DBG_LOTS("  t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
		 FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));

	/* 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;
	} else if ((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;
	}

	return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
}