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