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;
        }
    }
}
Exemple #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
     */
}
Exemple #4
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;
	}
}
Exemple #5
0
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, &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 = 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, &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 = 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;
        }
    }
}