windfarm_pid.c 3.7 KB

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