static void backside_setup_pid(void)
{
    /* first time initialize things */
    s32 fmin = wf_control_get_min(backside_fan);
    s32 fmax = wf_control_get_max(backside_fan);
    struct wf_pid_param param;
    struct device_node *u3;
    int u3h = 1; /* conservative by default */

    u3 = of_find_node_by_path("/u3@0,f8000000");
    if (u3 != NULL) {
        const u32 *vers = of_get_property(u3, "device-rev", NULL);
        if (vers)
            if (((*vers) & 0x3f) < 0x34)
                u3h = 0;
        of_node_put(u3);
    }

    param = u3h ? backside_u3h_param : backside_u3_param;

    param.min = max(param.min, fmin);
    param.max = min(param.max, fmax);
    wf_pid_init(&backside_pid, &param);
    backside_tick = 1;

    pr_info("wf_pm72: Backside control loop started.\n");
}
Beispiel #2
0
static void slots_setup_pid(void)
{
	/* first time initialize things */
	s32 fmin = wf_control_get_min(slots_fan);
	s32 fmax = wf_control_get_max(slots_fan);
	struct wf_pid_param param = slots_param;

	param.min = max(param.min, fmin);
	param.max = min(param.max, fmax);
	wf_pid_init(&slots_pid, &param);
	slots_tick = 1;

	pr_info("wf_rm31: Slots control loop started.\n");
}
static void drives_setup_pid(void)
{
    /* first time initialize things */
    s32 fmin = wf_control_get_min(drives_fan);
    s32 fmax = wf_control_get_max(drives_fan);
    struct wf_pid_param param = drives_param;

    param.min = max(param.min, fmin);
    param.max = min(param.max, fmax);
    wf_pid_init(&drives_pid, &param);
    drives_tick = 1;

    pr_info("wf_pm72: Drive bay control loop started.\n");
}
Beispiel #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;
}
Beispiel #5
0
static void backside_setup_pid(void)
{
	/* first time initialize things */
	s32 fmin = wf_control_get_min(backside_fan);
	s32 fmax = wf_control_get_max(backside_fan);
	struct wf_pid_param param;

	param = backside_param;
	param.min = max(param.min, fmin);
	param.max = min(param.max, fmax);
	wf_pid_init(&backside_pid, &param);

	param = dimms_param;
	wf_pid_init(&dimms_pid, &param);

	backside_tick = 1;

	pr_info("wf_rm31: Backside control loop started.\n");
}
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_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 = wf_control_get_min(fan_cpu_main);
	pid_param.max = wf_control_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);
}