mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
ac171c4666
This patch adds a windfarm module, windfarm_pm112, for the dual core G5s (both 2 and 4 core models), keeping the machine from getting into vacuum-cleaner mode ;) For proper credits, the patch was initially written by Paul Mackerras, and slightly reworked by me to add overtemp handling among others. The patch also removes the sysfs attributes from windfarm_pm81 and windfarm_pm91 and instead adds code to the windfarm core to automagically expose attributes for sensor & controls. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
145 lines
3.5 KiB
C
145 lines
3.5 KiB
C
/*
|
|
* Windfarm PowerMac thermal control. Generic PID helpers
|
|
*
|
|
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
|
|
* <benh@kernel.crashing.org>
|
|
*
|
|
* Released under the term of the GNU GPL v2.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/module.h>
|
|
|
|
#include "windfarm_pid.h"
|
|
|
|
#undef DEBUG
|
|
|
|
#ifdef DEBUG
|
|
#define DBG(args...) printk(args)
|
|
#else
|
|
#define DBG(args...) do { } while(0)
|
|
#endif
|
|
|
|
void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
|
|
{
|
|
memset(st, 0, sizeof(struct wf_pid_state));
|
|
st->param = *param;
|
|
st->first = 1;
|
|
}
|
|
EXPORT_SYMBOL_GPL(wf_pid_init);
|
|
|
|
s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
|
|
{
|
|
s64 error, integ, deriv;
|
|
s32 target;
|
|
int i, hlen = st->param.history_len;
|
|
|
|
/* Calculate error term */
|
|
error = new_sample - st->param.itarget;
|
|
|
|
/* Get samples into our history buffer */
|
|
if (st->first) {
|
|
for (i = 0; i < hlen; i++) {
|
|
st->samples[i] = new_sample;
|
|
st->errors[i] = error;
|
|
}
|
|
st->first = 0;
|
|
st->index = 0;
|
|
} else {
|
|
st->index = (st->index + 1) % hlen;
|
|
st->samples[st->index] = new_sample;
|
|
st->errors[st->index] = error;
|
|
}
|
|
|
|
/* Calculate integral term */
|
|
for (i = 0, integ = 0; i < hlen; i++)
|
|
integ += st->errors[(st->index + hlen - i) % hlen];
|
|
integ *= st->param.interval;
|
|
|
|
/* Calculate derivative term */
|
|
deriv = st->errors[st->index] -
|
|
st->errors[(st->index + hlen - 1) % hlen];
|
|
deriv /= st->param.interval;
|
|
|
|
/* Calculate target */
|
|
target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
|
|
error * (s64)st->param.gp) >> 36);
|
|
if (st->param.additive)
|
|
target += st->target;
|
|
target = max(target, st->param.min);
|
|
target = min(target, st->param.max);
|
|
st->target = target;
|
|
|
|
return st->target;
|
|
}
|
|
EXPORT_SYMBOL_GPL(wf_pid_run);
|
|
|
|
void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
|
|
struct wf_cpu_pid_param *param)
|
|
{
|
|
memset(st, 0, sizeof(struct wf_cpu_pid_state));
|
|
st->param = *param;
|
|
st->first = 1;
|
|
}
|
|
EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
|
|
|
|
s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
|
|
{
|
|
s64 integ, deriv, prop;
|
|
s32 error, target, sval, adj;
|
|
int i, hlen = st->param.history_len;
|
|
|
|
/* Calculate error term */
|
|
error = st->param.pmaxadj - new_power;
|
|
|
|
/* Get samples into our history buffer */
|
|
if (st->first) {
|
|
for (i = 0; i < hlen; i++) {
|
|
st->powers[i] = new_power;
|
|
st->errors[i] = error;
|
|
}
|
|
st->temps[0] = st->temps[1] = new_temp;
|
|
st->first = 0;
|
|
st->index = st->tindex = 0;
|
|
} else {
|
|
st->index = (st->index + 1) % hlen;
|
|
st->powers[st->index] = new_power;
|
|
st->errors[st->index] = error;
|
|
st->tindex = (st->tindex + 1) % 2;
|
|
st->temps[st->tindex] = new_temp;
|
|
}
|
|
|
|
/* Calculate integral term */
|
|
for (i = 0, integ = 0; i < hlen; i++)
|
|
integ += st->errors[(st->index + hlen - i) % hlen];
|
|
integ *= st->param.interval;
|
|
integ *= st->param.gr;
|
|
sval = st->param.tmax - (s32)(integ >> 20);
|
|
adj = min(st->param.ttarget, sval);
|
|
|
|
DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
|
|
|
|
/* Calculate derivative term */
|
|
deriv = st->temps[st->tindex] -
|
|
st->temps[(st->tindex + 2 - 1) % 2];
|
|
deriv /= st->param.interval;
|
|
deriv *= st->param.gd;
|
|
|
|
/* Calculate proportional term */
|
|
prop = st->last_delta = (new_temp - adj);
|
|
prop *= st->param.gp;
|
|
|
|
DBG("deriv: %lx, prop: %lx\n", deriv, prop);
|
|
|
|
/* Calculate target */
|
|
target = st->target + (s32)((deriv + prop) >> 36);
|
|
target = max(target, st->param.min);
|
|
target = min(target, st->param.max);
|
|
st->target = target;
|
|
|
|
return st->target;
|
|
}
|
|
EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
|