175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt/* 275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt * Windfarm PowerMac thermal control. Generic PID helpers 375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt * 475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. 575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt * <benh@kernel.crashing.org> 675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt * 775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt * Released under the term of the GNU GPL v2. 875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt */ 975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 1075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#include <linux/types.h> 1175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#include <linux/errno.h> 1275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#include <linux/kernel.h> 1375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#include <linux/string.h> 1475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#include <linux/module.h> 1575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 1675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#include "windfarm_pid.h" 1775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 1875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#undef DEBUG 1975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 2075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#ifdef DEBUG 2175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#define DBG(args...) printk(args) 2275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#else 2375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#define DBG(args...) do { } while(0) 2475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt#endif 2575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 2675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidtvoid wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param) 2775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt{ 2875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt memset(st, 0, sizeof(struct wf_pid_state)); 2975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->param = *param; 3075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->first = 1; 3175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt} 3275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin HerrenschmidtEXPORT_SYMBOL_GPL(wf_pid_init); 3375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 3475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidts32 wf_pid_run(struct wf_pid_state *st, s32 new_sample) 3575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt{ 3675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt s64 error, integ, deriv; 3775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt s32 target; 3875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt int i, hlen = st->param.history_len; 3975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 4075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate error term */ 4175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt error = new_sample - st->param.itarget; 4275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 4375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Get samples into our history buffer */ 4475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt if (st->first) { 4575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt for (i = 0; i < hlen; i++) { 4675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->samples[i] = new_sample; 4775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->errors[i] = error; 4875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt } 4975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->first = 0; 5075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->index = 0; 5175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt } else { 5275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->index = (st->index + 1) % hlen; 5375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->samples[st->index] = new_sample; 5475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->errors[st->index] = error; 5575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt } 5675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 5775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate integral term */ 5875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt for (i = 0, integ = 0; i < hlen; i++) 5975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt integ += st->errors[(st->index + hlen - i) % hlen]; 6075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt integ *= st->param.interval; 6175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 6275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate derivative term */ 6375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt deriv = st->errors[st->index] - 6475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->errors[(st->index + hlen - 1) % hlen]; 6575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt deriv /= st->param.interval; 6675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 6775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate target */ 6875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd + 6975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt error * (s64)st->param.gp) >> 36); 7075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt if (st->param.additive) 7175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target += st->target; 7275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target = max(target, st->param.min); 7375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target = min(target, st->param.max); 7475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->target = target; 7575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 7675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt return st->target; 7775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt} 7875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin HerrenschmidtEXPORT_SYMBOL_GPL(wf_pid_run); 7975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 8075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidtvoid wf_cpu_pid_init(struct wf_cpu_pid_state *st, 8175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt struct wf_cpu_pid_param *param) 8275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt{ 8375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt memset(st, 0, sizeof(struct wf_cpu_pid_state)); 8475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->param = *param; 8575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->first = 1; 8675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt} 8775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin HerrenschmidtEXPORT_SYMBOL_GPL(wf_cpu_pid_init); 8875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 8975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidts32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp) 9075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt{ 91ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt s64 integ, deriv, prop; 92ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt s32 error, target, sval, adj; 9375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt int i, hlen = st->param.history_len; 9475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 9575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate error term */ 9675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt error = st->param.pmaxadj - new_power; 9775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 9875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Get samples into our history buffer */ 9975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt if (st->first) { 10075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt for (i = 0; i < hlen; i++) { 10175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->powers[i] = new_power; 10275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->errors[i] = error; 10375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt } 10475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->temps[0] = st->temps[1] = new_temp; 10575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->first = 0; 10675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->index = st->tindex = 0; 10775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt } else { 10875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->index = (st->index + 1) % hlen; 10975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->powers[st->index] = new_power; 11075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->errors[st->index] = error; 11175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->tindex = (st->tindex + 1) % 2; 11275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->temps[st->tindex] = new_temp; 11375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt } 11475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 11575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate integral term */ 11675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt for (i = 0, integ = 0; i < hlen; i++) 11775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt integ += st->errors[(st->index + hlen - i) % hlen]; 11875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt integ *= st->param.interval; 11975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt integ *= st->param.gr; 120ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sval = st->param.tmax - (s32)(integ >> 20); 12175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt adj = min(st->param.ttarget, sval); 12275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 12375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj); 12475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 12575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate derivative term */ 12675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt deriv = st->temps[st->tindex] - 12775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->temps[(st->tindex + 2 - 1) % 2]; 12875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt deriv /= st->param.interval; 12975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt deriv *= st->param.gd; 13075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 13175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate proportional term */ 132ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt prop = st->last_delta = (new_temp - adj); 13375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt prop *= st->param.gp; 13475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 13575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt DBG("deriv: %lx, prop: %lx\n", deriv, prop); 13675722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 13775722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt /* Calculate target */ 13875722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target = st->target + (s32)((deriv + prop) >> 36); 13975722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target = max(target, st->param.min); 14075722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt target = min(target, st->param.max); 14175722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt st->target = target; 14275722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt 14375722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt return st->target; 14475722d3992f57375c0cc029dcceb2334a45ceff1Benjamin Herrenschmidt} 14575722d3992f57375c0cc029dcceb2334a45ceff1Benjamin HerrenschmidtEXPORT_SYMBOL_GPL(wf_cpu_pid_run); 146cdd440fe9f2e83b1e268148647126440799b71fcBenjamin Herrenschmidt 147cdd440fe9f2e83b1e268148647126440799b71fcBenjamin HerrenschmidtMODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 148cdd440fe9f2e83b1e268148647126440799b71fcBenjamin HerrenschmidtMODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control"); 149cdd440fe9f2e83b1e268148647126440799b71fcBenjamin HerrenschmidtMODULE_LICENSE("GPL"); 150