Root/drivers/macintosh/windfarm_pid.c

1/*
2 * Windfarm PowerMac thermal control. Generic PID helpers
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 */
9
10#include <linux/types.h>
11#include <linux/errno.h>
12#include <linux/kernel.h>
13#include <linux/string.h>
14#include <linux/module.h>
15
16#include "windfarm_pid.h"
17
18#undef DEBUG
19
20#ifdef DEBUG
21#define DBG(args...) printk(args)
22#else
23#define DBG(args...) do { } while(0)
24#endif
25
26void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
27{
28    memset(st, 0, sizeof(struct wf_pid_state));
29    st->param = *param;
30    st->first = 1;
31}
32EXPORT_SYMBOL_GPL(wf_pid_init);
33
34s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
35{
36    s64 error, integ, deriv;
37    s32 target;
38    int i, hlen = st->param.history_len;
39
40    /* Calculate error term */
41    error = new_sample - st->param.itarget;
42
43    /* Get samples into our history buffer */
44    if (st->first) {
45        for (i = 0; i < hlen; i++) {
46            st->samples[i] = new_sample;
47            st->errors[i] = error;
48        }
49        st->first = 0;
50        st->index = 0;
51    } else {
52        st->index = (st->index + 1) % hlen;
53        st->samples[st->index] = new_sample;
54        st->errors[st->index] = error;
55    }
56
57    /* Calculate integral term */
58    for (i = 0, integ = 0; i < hlen; i++)
59        integ += st->errors[(st->index + hlen - i) % hlen];
60    integ *= st->param.interval;
61
62    /* Calculate derivative term */
63    deriv = st->errors[st->index] -
64        st->errors[(st->index + hlen - 1) % hlen];
65    deriv /= st->param.interval;
66
67    /* Calculate target */
68    target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
69          error * (s64)st->param.gp) >> 36);
70    if (st->param.additive)
71        target += st->target;
72    target = max(target, st->param.min);
73    target = min(target, st->param.max);
74    st->target = target;
75
76    return st->target;
77}
78EXPORT_SYMBOL_GPL(wf_pid_run);
79
80void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
81             struct wf_cpu_pid_param *param)
82{
83    memset(st, 0, sizeof(struct wf_cpu_pid_state));
84    st->param = *param;
85    st->first = 1;
86}
87EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
88
89s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
90{
91    s64 integ, deriv, prop;
92    s32 error, target, sval, adj;
93    int i, hlen = st->param.history_len;
94
95    /* Calculate error term */
96    error = st->param.pmaxadj - new_power;
97
98    /* Get samples into our history buffer */
99    if (st->first) {
100        for (i = 0; i < hlen; i++) {
101            st->powers[i] = new_power;
102            st->errors[i] = error;
103        }
104        st->temps[0] = st->temps[1] = new_temp;
105        st->first = 0;
106        st->index = st->tindex = 0;
107    } else {
108        st->index = (st->index + 1) % hlen;
109        st->powers[st->index] = new_power;
110        st->errors[st->index] = error;
111        st->tindex = (st->tindex + 1) % 2;
112        st->temps[st->tindex] = new_temp;
113    }
114
115    /* Calculate integral term */
116    for (i = 0, integ = 0; i < hlen; i++)
117        integ += st->errors[(st->index + hlen - i) % hlen];
118    integ *= st->param.interval;
119    integ *= st->param.gr;
120    sval = st->param.tmax - (s32)(integ >> 20);
121    adj = min(st->param.ttarget, sval);
122
123    DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
124
125    /* Calculate derivative term */
126    deriv = st->temps[st->tindex] -
127        st->temps[(st->tindex + 2 - 1) % 2];
128    deriv /= st->param.interval;
129    deriv *= st->param.gd;
130
131    /* Calculate proportional term */
132    prop = st->last_delta = (new_temp - adj);
133    prop *= st->param.gp;
134
135    DBG("deriv: %lx, prop: %lx\n", deriv, prop);
136
137    /* Calculate target */
138    target = st->target + (s32)((deriv + prop) >> 36);
139    target = max(target, st->param.min);
140    target = min(target, st->param.max);
141    st->target = target;
142
143    return st->target;
144}
145EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
146
147MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
148MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");
149MODULE_LICENSE("GPL");
150

Archive Download this file



interactive