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