Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Windfarm PowerMac thermal control. Generic PID helpers
0004  *
0005  * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
0006  *                    <benh@kernel.crashing.org>
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     /* Calculate error term */
0040     error = new_sample - st->param.itarget;
0041 
0042     /* Get samples into our history buffer */
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     /* Calculate integral term */
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     /* Calculate derivative term */
0062     deriv = st->errors[st->index] -
0063         st->errors[(st->index + hlen - 1) % hlen];
0064     deriv /= st->param.interval;
0065 
0066     /* Calculate target */
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     /* Calculate error term */
0095     error = st->param.pmaxadj - new_power;
0096 
0097     /* Get samples into our history buffer */
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     /* Calculate integral term */
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     /* Calculate derivative term */
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     /* Calculate proportional term */
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     /* Calculate target */
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");