0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/kernel.h>
0012 #include <linux/string.h>
0013 #include <linux/module.h>
0014
0015 #include "windfarm_pid.h"
0016
0017 #undef DEBUG
0018
0019 #ifdef DEBUG
0020 #define DBG(args...) printk(args)
0021 #else
0022 #define DBG(args...) do { } while(0)
0023 #endif
0024
0025 void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
0026 {
0027 memset(st, 0, sizeof(struct wf_pid_state));
0028 st->param = *param;
0029 st->first = 1;
0030 }
0031 EXPORT_SYMBOL_GPL(wf_pid_init);
0032
0033 s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
0034 {
0035 s64 error, integ, deriv;
0036 s32 target;
0037 int i, hlen = st->param.history_len;
0038
0039
0040 error = new_sample - st->param.itarget;
0041
0042
0043 if (st->first) {
0044 for (i = 0; i < hlen; i++) {
0045 st->samples[i] = new_sample;
0046 st->errors[i] = error;
0047 }
0048 st->first = 0;
0049 st->index = 0;
0050 } else {
0051 st->index = (st->index + 1) % hlen;
0052 st->samples[st->index] = new_sample;
0053 st->errors[st->index] = error;
0054 }
0055
0056
0057 for (i = 0, integ = 0; i < hlen; i++)
0058 integ += st->errors[(st->index + hlen - i) % hlen];
0059 integ *= st->param.interval;
0060
0061
0062 deriv = st->errors[st->index] -
0063 st->errors[(st->index + hlen - 1) % hlen];
0064 deriv /= st->param.interval;
0065
0066
0067 target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
0068 error * (s64)st->param.gp) >> 36);
0069 if (st->param.additive)
0070 target += st->target;
0071 target = max(target, st->param.min);
0072 target = min(target, st->param.max);
0073 st->target = target;
0074
0075 return st->target;
0076 }
0077 EXPORT_SYMBOL_GPL(wf_pid_run);
0078
0079 void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
0080 struct wf_cpu_pid_param *param)
0081 {
0082 memset(st, 0, sizeof(struct wf_cpu_pid_state));
0083 st->param = *param;
0084 st->first = 1;
0085 }
0086 EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
0087
0088 s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
0089 {
0090 s64 integ, deriv, prop;
0091 s32 error, target, sval, adj;
0092 int i, hlen = st->param.history_len;
0093
0094
0095 error = st->param.pmaxadj - new_power;
0096
0097
0098 if (st->first) {
0099 for (i = 0; i < hlen; i++) {
0100 st->powers[i] = new_power;
0101 st->errors[i] = error;
0102 }
0103 st->temps[0] = st->temps[1] = new_temp;
0104 st->first = 0;
0105 st->index = st->tindex = 0;
0106 } else {
0107 st->index = (st->index + 1) % hlen;
0108 st->powers[st->index] = new_power;
0109 st->errors[st->index] = error;
0110 st->tindex = (st->tindex + 1) % 2;
0111 st->temps[st->tindex] = new_temp;
0112 }
0113
0114
0115 for (i = 0, integ = 0; i < hlen; i++)
0116 integ += st->errors[(st->index + hlen - i) % hlen];
0117 integ *= st->param.interval;
0118 integ *= st->param.gr;
0119 sval = st->param.tmax - (s32)(integ >> 20);
0120 adj = min(st->param.ttarget, sval);
0121
0122 DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
0123
0124
0125 deriv = st->temps[st->tindex] -
0126 st->temps[(st->tindex + 2 - 1) % 2];
0127 deriv /= st->param.interval;
0128 deriv *= st->param.gd;
0129
0130
0131 prop = st->last_delta = (new_temp - adj);
0132 prop *= st->param.gp;
0133
0134 DBG("deriv: %lx, prop: %lx\n", deriv, prop);
0135
0136
0137 target = st->target + (s32)((deriv + prop) >> 36);
0138 target = max(target, st->param.min);
0139 target = min(target, st->param.max);
0140 st->target = target;
0141
0142 return st->target;
0143 }
0144 EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
0145
0146 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0147 MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");
0148 MODULE_LICENSE("GPL");