dm_temp_ctrl.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright 2018 Duan Hao
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation; either version 3 of the License, or (at your option)
  7. * any later version. See COPYING for more details.
  8. */
  9. #include <stdio.h>
  10. #include <stdint.h>
  11. #include <stdlib.h>
  12. #include "dragonmint_t1.h"
  13. #include "dm_temp_ctrl.h"
  14. /******************************************************************************
  15. * Macros & Constants
  16. ******************************************************************************/
  17. #define INVALID_TEMP (9999)
  18. /******************************************************************************
  19. * Global variables
  20. ******************************************************************************/
  21. volatile c_temp_cfg g_tmp_cfg; // configs of temperature control
  22. volatile c_temp g_chain_tmp[MAX_CHAIN_NUM]; // current temperature per chain
  23. volatile int g_tmp_last_upd_time[MAX_CHAIN_NUM];
  24. static uint32_t g_temp_status[MAX_CHAIN_NUM];
  25. /******************************************************************************
  26. * Prototypes
  27. ******************************************************************************/
  28. /******************************************************************************
  29. * Implementations
  30. ******************************************************************************/
  31. /******************************************************************************
  32. * Function: dm_tempctrl_get_defcfg
  33. * Description: get default configs for temerature control
  34. * Arguments: p_cfg temperature configs
  35. * Return: none
  36. ******************************************************************************/
  37. void dm_tempctrl_get_defcfg(c_temp_cfg *p_cfg)
  38. {
  39. p_cfg->tmp_min = -40;
  40. p_cfg->tmp_max = 125;
  41. p_cfg->tmp_target = 75;
  42. p_cfg->tmp_thr_lo = 30;
  43. p_cfg->tmp_thr_hi = 95;
  44. p_cfg->tmp_thr_warn = 105;
  45. p_cfg->tmp_thr_pd = 115;
  46. p_cfg->tmp_exp_time = 2000; // 2s
  47. }
  48. void dm_tempctrl_set(c_temp_cfg *p_cfg)
  49. {
  50. g_tmp_cfg = *p_cfg;
  51. }
  52. /******************************************************************************
  53. * Function: dm_tempctrl_init
  54. * Description: temperature control initializition
  55. * Arguments: p_cfg temperature configs
  56. * Return: none
  57. ******************************************************************************/
  58. void dm_tempctrl_init(c_temp_cfg *p_cfg)
  59. {
  60. int i;
  61. // FIXME: add mutex here
  62. if (NULL == p_cfg) {
  63. c_temp_cfg cfg;
  64. dm_tempctrl_get_defcfg(&cfg); // avoid to pass volatile pointer directly
  65. dm_tempctrl_set(&cfg);
  66. } else
  67. dm_tempctrl_set(p_cfg);
  68. for(i = 0; i < MAX_CHAIN_NUM; ++i) {
  69. g_chain_tmp[i].tmp_lo = g_chain_tmp[i].tmp_hi
  70. = g_chain_tmp[i].tmp_avg = INVALID_TEMP;
  71. }
  72. }
  73. #ifndef USE_AUTOCMD0A
  74. static void dm_tempctrl_get_chain_temp(int *chip_temp, c_temp *chain_temp)
  75. {
  76. int i, cnt, avg, index = -1;
  77. int compr_desc(const void *a, const void *b) {
  78. return (*(int*)b - *(int*)a);
  79. }
  80. /* Sort descending */
  81. qsort(chip_temp, g_chip_num, sizeof(int), compr_desc);
  82. cnt = avg = 0;
  83. for (i = 0; i < g_chip_num; ++i) {
  84. if (chip_temp[i] < g_tmp_cfg.tmp_max && chip_temp[i] > g_tmp_cfg.tmp_min) {
  85. /* Find the first valid temperature */
  86. if (index == -1)
  87. index = i;
  88. /* Get the average temperature */
  89. avg += chip_temp[i];
  90. cnt++;
  91. }
  92. }
  93. if (cnt > 6) {
  94. /* Ignore the highest one and get average of maximal two tempertures */
  95. chain_temp->tmp_hi = (chip_temp[index + 1] + chip_temp[index + 2]) >> 1;
  96. /* Ignore the lowest one and get average of minimal two tempertures */
  97. chain_temp->tmp_lo = (chip_temp[g_chip_num - 2] + chip_temp[g_chip_num - 3]) >> 1;
  98. chain_temp->tmp_avg = avg / cnt;
  99. } else {
  100. chain_temp->tmp_hi = INVALID_TEMP;
  101. chain_temp->tmp_lo = INVALID_TEMP;
  102. chain_temp->tmp_avg = INVALID_TEMP;
  103. }
  104. }
  105. #endif
  106. /******************************************************************************
  107. * Function: dm_tempctrl_update_chain_temp
  108. * Description: update temperature of single chain
  109. * Arguments: chain_id chain id
  110. * Return: device temperature state
  111. ******************************************************************************/
  112. uint32_t dm_tempctrl_update_chain_temp(int chain_id)
  113. {
  114. uint32_t *tstatus = &g_temp_status[chain_id];
  115. c_temp chain_temp;
  116. /* Do not read temperature unless given time has passed or the last
  117. * reading was invalid. Return the last value in that case. */
  118. int curr_time = get_current_ms();
  119. if (curr_time - g_tmp_last_upd_time[chain_id] < g_tmp_cfg.tmp_exp_time &&
  120. *tstatus != (uint32_t)TEMP_INVALID)
  121. goto out;
  122. g_tmp_last_upd_time[chain_id] = curr_time;
  123. // FIXME: add mutex here
  124. #ifdef USE_AUTOCMD0A
  125. if (!mcompat_get_chain_temp(chain_id, &chain_temp))
  126. applog(LOG_ERR, "chain%d: failed to read chain temperature", chain_id);
  127. #else
  128. int chip_temp[MCOMPAT_CONFIG_MAX_CHIP_NUM];
  129. mcompat_get_chip_temp(chain_id, chip_temp);
  130. dm_tempctrl_get_chain_temp(chip_temp, &chain_temp);
  131. #endif
  132. applog(LOG_DEBUG, "chain%d: Tmax=%d, Tmin=%d, Tavg=%d",
  133. chain_id, chain_temp.tmp_hi, chain_temp.tmp_lo, chain_temp.tmp_avg);
  134. if (chain_temp.tmp_hi > g_tmp_cfg.tmp_max || chain_temp.tmp_hi < g_tmp_cfg.tmp_min
  135. || chain_temp.tmp_lo > g_tmp_cfg.tmp_max || chain_temp.tmp_lo < g_tmp_cfg.tmp_min
  136. || chain_temp.tmp_avg > g_tmp_cfg.tmp_max || chain_temp.tmp_avg < g_tmp_cfg.tmp_min) {
  137. applog(LOG_ERR, "error temperature ignored: Tmax=%d, Tmin=%d, Tavg=%d",
  138. chain_temp.tmp_hi, chain_temp.tmp_lo, chain_temp.tmp_avg);
  139. *tstatus = TEMP_INVALID;
  140. goto out;
  141. }
  142. g_chain_tmp[chain_id] = chain_temp;
  143. g_chain_tmp[chain_id].optimal = false;
  144. if (g_chain_tmp[chain_id].tmp_hi >= g_tmp_cfg.tmp_thr_pd)
  145. *tstatus = TEMP_SHUTDOWN;
  146. else if (g_chain_tmp[chain_id].tmp_hi >= g_tmp_cfg.tmp_thr_warn)
  147. *tstatus = TEMP_WARNING;
  148. else if (g_chain_tmp[chain_id].tmp_hi >= g_tmp_cfg.tmp_thr_hi)
  149. *tstatus = TEMP_TOO_HIGH;
  150. else if (g_chain_tmp[chain_id].tmp_lo < g_tmp_cfg.tmp_thr_lo)
  151. *tstatus = TEMP_TOO_LOW;
  152. else {
  153. if (g_chain_tmp[chain_id].tmp_avg > g_tmp_cfg.tmp_target - TEMP_TOLERANCE)
  154. g_chain_tmp[chain_id].optimal = true;
  155. *tstatus = TEMP_NORMAL;
  156. }
  157. out:
  158. return *tstatus;
  159. }
  160. /******************************************************************************
  161. * Function: dm_tempctrl_update_temp
  162. * Description: update temperature of one or more chains
  163. * Arguments: chain_mask chain id mask
  164. * Return: device temperture state
  165. ******************************************************************************/
  166. void dm_tempctrl_update_temp(uint8_t chain_mask)
  167. {
  168. int i;
  169. for (i = 0; i < MAX_CHAIN_NUM; ++i)
  170. {
  171. if(chain_mask & (1 << i))
  172. {
  173. dm_tempctrl_update_chain_temp(i);
  174. }
  175. }
  176. }