/ 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 }