mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-11-02 03:08:17 +00:00
Merge pull request #560 from jostar-yang/as9716_20190521
Add as9716-32d thermal plan
This commit is contained in:
@@ -37,22 +37,12 @@
|
||||
#include "x86_64_accton_as9716_32d_int.h"
|
||||
#include "x86_64_accton_as9716_32d_log.h"
|
||||
|
||||
|
||||
#define NUM_OF_FAN_ON_MAIN_BROAD 6
|
||||
#define PREFIX_PATH_ON_CPLD_DEV "/sys/bus/i2c/devices/"
|
||||
#define NUM_OF_CPLD 3
|
||||
#define FAN_DUTY_CYCLE_MAX (100)
|
||||
#define FAN_DUTY_CYCLE_DEFAULT (32)
|
||||
#define FAN_DUTY_PLUS_FOR_DIR (13)
|
||||
/* Note, all chassis fans share 1 single duty setting.
|
||||
* Here use fan 1 to represent global fan duty value.*/
|
||||
#define FAN_ID_FOR_SET_FAN_DUTY (1)
|
||||
#define CELSIUS_RECORD_NUMBER (2) /*Must >= 2*/
|
||||
|
||||
typedef struct fan_ctrl_policy {
|
||||
int duty_cycle; /* In percetage */
|
||||
int step_up_thermal; /* In mini-Celsius */
|
||||
int step_dn_thermal; /* In mini-Celsius */
|
||||
} fan_ctrl_policy_t;
|
||||
#define FAN_DUTY_CYCLE_75 (75)
|
||||
#define FAN_DUTY_CYCLE_50 (50)
|
||||
|
||||
static char arr_cplddev_name[NUM_OF_CPLD][10] =
|
||||
{
|
||||
@@ -99,7 +89,7 @@ onlp_sysi_oids_get(onlp_oid_t* table, int max)
|
||||
onlp_oid_t* e = table;
|
||||
memset(table, 0, max*sizeof(onlp_oid_t));
|
||||
|
||||
/* 6 Thermal sensors on the chassis */
|
||||
/* 8 Thermal sensors on the chassis */
|
||||
for (i = 1; i <= CHASSIS_THERMAL_COUNT; i++) {
|
||||
*e++ = ONLP_THERMAL_ID_CREATE(i);
|
||||
}
|
||||
@@ -145,355 +135,397 @@ onlp_sysi_platform_info_free(onlp_platform_info_t* pi)
|
||||
aim_free(pi->cpld_versions);
|
||||
}
|
||||
|
||||
/* Thermal plan:
|
||||
* $TMP = (CPU_core + LM75_1+ LM75_2 + LM75_3 + LM75_4)/5
|
||||
* 1. If any FAN failed, set all the other fans as full speed, 100%.
|
||||
* 2. If any sensor is high than 45 degrees, set fan speed to duty 62.5%.
|
||||
* 3. If any sensor is high than 50 degrees, set fan speed to duty 100%.
|
||||
* 4. When $TMP >= 40 C, set fan speed to duty 62.5%.
|
||||
* 5. When $TMP >= 45 C, set fan speed to duty 100%.
|
||||
* 6. When $TMP < 35 C, set fan speed to duty 31.25%.
|
||||
* 7. Direction factor, when B2F, duty + 12.5%.
|
||||
*
|
||||
* Note, all chassis fans share 1 single duty setting.
|
||||
/*Read fanN_direction=1: The air flow of Fan6 is <20><>AFI-Back to Front<6E><74>
|
||||
* 0: The air flow of Fan6 is <20><>AFO-Front to back<63><6B>
|
||||
*/
|
||||
fan_ctrl_policy_t fan_ctrl_policy_avg[] = {
|
||||
{FAN_DUTY_CYCLE_MAX , 45000, INT_MIN},
|
||||
{63 , 40000, INT_MIN},
|
||||
{32 , INT_MAX, 35000},
|
||||
/*
|
||||
Thermal policy:
|
||||
One fan fail, set to fan pwm=100%
|
||||
1. For AFI:
|
||||
Default fan pwm will be 75%(LEVEL_FAN_DEF).
|
||||
When below case, Fan pwm will be 100%(LEVEL_FAN_DAX)
|
||||
(MB board)
|
||||
LM75-1(0X48)<29><>61.5<EFBFBD>J
|
||||
LM75-2(0X49)<29><>51.5<EFBFBD>J
|
||||
LM75-3(0X4A)<29><>49.4<EFBFBD>J
|
||||
LM75-4(0X4C)<29><>49.4<EFBFBD>J
|
||||
LM75-5(0X4E)<29><>45.1<EFBFBD>J
|
||||
LM75-6(0X4F)<29><>46.75<EFBFBD>J
|
||||
(CPU board)
|
||||
Core<72><65>48
|
||||
LM75-1(0X4B)<29><>38.5<EFBFBD>J
|
||||
|
||||
When FAN pwm was 100%(LEVEL_FAN_MAX). If all below case meet with, set to 75%(LEVEL_FAN_DEF).
|
||||
MB board
|
||||
LM75-1(0X48)<29><>57<35>J
|
||||
LM75-2(0X49)<29><>47.3<EFBFBD>J
|
||||
LM75-3(0X4A)<29><>45<34>J
|
||||
LM75-4(0X4C)<29><>45.1<EFBFBD>J
|
||||
LM75-5(0X4E)<29><>40.75<EFBFBD>J
|
||||
LM75-6(0X4F)<29><>42.1<EFBFBD>J
|
||||
CPU board
|
||||
Core<72><65>44
|
||||
LM75-1(0X4B)<29><>35<33>J
|
||||
|
||||
2. For AFO:
|
||||
Default fan pwm will be 50%(LEVEL_FAN_DEF).
|
||||
When below case, Fan pwm will be 75%(LEVEL_FAN_MID)
|
||||
(MB board)
|
||||
LM75-1(0X48)<29><>67<36>J
|
||||
LM75-2(0X49)<29><>62.5<EFBFBD>J
|
||||
LM75-3(0X4A)<29><>65<36>J
|
||||
LM75-4(0X4C)<29><>59<35>J
|
||||
LM75-5(0X4E)<29><>58.5<EFBFBD>J
|
||||
LM75-6(0X4F)<29><>63<36>J
|
||||
(CPU board)
|
||||
Core >=69<36>J
|
||||
LM75-1(0X4B)<29><>49<34>J
|
||||
|
||||
When FAN pwm was 75%(LEVEL_FAN_MID). If all below case meet with, set to 100%(LEVEL_FAN_MAX).
|
||||
(MB board)
|
||||
LM75-1(0X48)<29><>70<37>J
|
||||
LM75-2(0X49)<29><>66<36>J
|
||||
LM75-3(0X4A)<29><>68<36>J
|
||||
LM75-4(0X4C)<29><>62<36>J
|
||||
LM75-5(0X4E)<29><>62<36>J
|
||||
LM75-6(0X4F)<29><>67<36>J
|
||||
(CPU board)
|
||||
Core<72><65>77
|
||||
LM75-1(0X4B)<29><>50<35>J
|
||||
|
||||
When FAN pwm was 100%(LEVEL_FAN_MAX). If all below case meet with, set to 75%(LEVEL_FAN_MID).
|
||||
(MB board)
|
||||
LM75-1(0X48)<29><>59<35>J
|
||||
LM75-2(0X49)<29><>53.5<EFBFBD>J
|
||||
LM75-3(0X4A)<29><>55.3<EFBFBD>J
|
||||
LM75-4(0X4C)<29><>50.3<EFBFBD>J
|
||||
LM75-5(0X4E)<29><>50<35>J
|
||||
LM75-6(0X4F)<29><>52.5<EFBFBD>J
|
||||
(CPU board)
|
||||
Core<72><65>59
|
||||
LM75-1(0X4B)<29><>41.1<EFBFBD>J
|
||||
|
||||
When FAN pwm was 75%(LEVEL_FAN_MID). If all below case meet with, set to 50%(LEVEL_FAN_DEF).
|
||||
(MB board)
|
||||
LM75-1(0X48)<29><>55.8<EFBFBD>J
|
||||
LM75-2(0X49)<29><>50.5<EFBFBD>J
|
||||
LM75-3(0X4A)<29><>51.1<EFBFBD>J
|
||||
LM75-4(0X4C)<29><>47.6<EFBFBD>J
|
||||
LM75-5(0X4E)<29><>45.75<EFBFBD>J
|
||||
LM75-6(0X4F)<29><>50.1<EFBFBD>J
|
||||
(CPU board)
|
||||
Core<72><65>57
|
||||
LM75-1(0X4B)<29><>36.6<EFBFBD>J
|
||||
|
||||
|
||||
*/
|
||||
|
||||
typedef struct afi_temp_range{
|
||||
int def_to_max_temp[8];
|
||||
int max_to_def_temp[8];
|
||||
}afi_temp_range_t;
|
||||
|
||||
afi_temp_range_t afi_thermal_spec={
|
||||
{61500, 51500, 49400, 49400, 45100, 46750, 48000, 38500},
|
||||
{57000, 47300, 45000, 45100, 40750, 42100, 44000, 35000}
|
||||
};
|
||||
|
||||
fan_ctrl_policy_t fan_ctrl_policy_single[] = {
|
||||
{FAN_DUTY_CYCLE_MAX , 50000, INT_MIN},
|
||||
{63 , 45000, INT_MIN},
|
||||
typedef struct afo_temp_range{
|
||||
int def_to_mid_temp[8];
|
||||
int mid_to_max_temp[8];
|
||||
int max_to_mid_temp[8];
|
||||
int mid_to_def_temp[8];
|
||||
} afo_temp_range_t;
|
||||
|
||||
|
||||
afo_temp_range_t afo_thermal_spec={
|
||||
{67000, 62000, 65000, 59000, 58500, 63000, 69000, 49000},
|
||||
{70000, 66000, 68000, 62000, 62000, 67000, 77000, 50000},
|
||||
{59000, 53500, 55300, 50300, 50000, 52500, 59000, 41100},
|
||||
{55800, 50500, 51100, 47600, 45750, 50100, 57000, 36600}
|
||||
};
|
||||
|
||||
struct fan_control_data_s {
|
||||
|
||||
typedef struct fan_ctrl_policy {
|
||||
int duty_cycle;
|
||||
int dir_plus;
|
||||
int mc_avg_pre[CELSIUS_RECORD_NUMBER];
|
||||
int mc_high_pre[CELSIUS_RECORD_NUMBER];
|
||||
int pwm;
|
||||
int state;
|
||||
} fan_ctrl_policy_t;
|
||||
|
||||
} fan_control_data_pre =
|
||||
|
||||
/*For AFI. 2 state. LEVEL_FAN_DEF(75%), LEVEL_FAN_MAX(100%)
|
||||
For AFO. 3 state. LEVEL_FAN_DEF(50%), LEVEL_FAN_MID(75%), LEVEL_FAN_MAX(100%)
|
||||
*/
|
||||
enum
|
||||
{
|
||||
.duty_cycle = FAN_DUTY_CYCLE_DEFAULT,
|
||||
.dir_plus = 0,
|
||||
.mc_avg_pre = {INT_MIN+1, INT_MIN}, /*init as thermal rising to avoid full speed.*/
|
||||
.mc_high_pre = {INT_MIN+1, INT_MIN}, /*init as thermal rising to avoid full speed.*/
|
||||
LEVEL_FAN_INIT=0,
|
||||
LEVEL_FAN_DEF=1,
|
||||
LEVEL_FAN_MID,
|
||||
LEVEL_FAN_MAX,
|
||||
};
|
||||
|
||||
fan_ctrl_policy_t fan_thermal_policy_f2b[] = { /*AFO*/
|
||||
{50, 0x7, LEVEL_FAN_DEF},
|
||||
{75, 0xb, LEVEL_FAN_MID},
|
||||
{100, 0xf, LEVEL_FAN_MAX},
|
||||
|
||||
};
|
||||
|
||||
static int
|
||||
sysi_check_fan(uint32_t *fan_dir){
|
||||
int i, present;
|
||||
fan_ctrl_policy_t fan_thermal_policy_b2f[] = { /*AFI*/
|
||||
{75, 0xb, LEVEL_FAN_DEF},
|
||||
{100, 0xf, LEVEL_FAN_MAX}
|
||||
};
|
||||
|
||||
for (i = 1; i <= CHASSIS_FAN_COUNT; i++)
|
||||
int onlp_sysi_get_duty_cycle_by_fan_state(int state, int direction)
|
||||
{
|
||||
int i;
|
||||
if(direction)
|
||||
{
|
||||
for(i=0; i< 2; i++)
|
||||
{
|
||||
if(state==fan_thermal_policy_b2f[i].state)
|
||||
{
|
||||
return fan_thermal_policy_b2f[i].duty_cycle;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0; i< 3; i++)
|
||||
{
|
||||
if(state==fan_thermal_policy_f2b[i].state)
|
||||
{
|
||||
return fan_thermal_policy_f2b[i].duty_cycle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#define FAN_SPEED_CTRL_PATH "/sys/bus/i2c/devices/17-0066/fan_duty_cycle_percentage"
|
||||
#define FAN_DIRECTION_PATH "/sys/bus/i2c/devices/17-0066/fan1_direction"
|
||||
|
||||
static int fan_state=LEVEL_FAN_INIT;
|
||||
static int fan_fail = 0;
|
||||
|
||||
int current_duty_cycle, new_duty_cycle;
|
||||
|
||||
int onlp_sysi_platform_manage_fans(void)
|
||||
{
|
||||
int i=0,k=0, ori_state=LEVEL_FAN_DEF, current_state=LEVEL_FAN_DEF;
|
||||
int fd, len, direction_val=1;
|
||||
int max_to_def=0, max_to_mid=0, mid_to_def=0; /* Only this flag equal to 8, otherwise state can not to be down.*/
|
||||
onlp_thermal_info_t thermal[8];
|
||||
char buf[10] = {0};
|
||||
|
||||
/* Get fan direction
|
||||
*/
|
||||
if (onlp_file_read_int(&direction_val, FAN_DIRECTION_PATH) < 0) {
|
||||
AIM_LOG_ERROR("Unable to read status from file (%s)\r\n", FAN_DIRECTION_PATH);
|
||||
}
|
||||
|
||||
/* Get current temperature
|
||||
*/
|
||||
|
||||
for (i=2; i <5; i++)
|
||||
{
|
||||
|
||||
if (onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(i), &thermal[k]) != ONLP_STATUS_OK )
|
||||
{
|
||||
AIM_LOG_ERROR("Unable to read thermal status, set fans to 75% speed");
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(i), 75);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
for (i=6; i <=8; i++)
|
||||
{
|
||||
if (onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(i), &thermal[k]) != ONLP_STATUS_OK )
|
||||
{
|
||||
AIM_LOG_ERROR("Unable to read thermal status, set fans to 75% speed");
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(i), 75);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
if (onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(1), &thermal[6]) != ONLP_STATUS_OK )
|
||||
{
|
||||
AIM_LOG_ERROR("Unable to read thermal status, set fans to 75% speed");
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(1), 75);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
if (onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(5), &thermal[7]) != ONLP_STATUS_OK )
|
||||
{
|
||||
AIM_LOG_ERROR("Unable to read thermal status, set fans to 75% speed");
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(5), 75);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
|
||||
/* Get current fan pwm percent
|
||||
*/
|
||||
fd = open(FAN_SPEED_CTRL_PATH, O_RDONLY);
|
||||
if (fd == -1){
|
||||
AIM_LOG_ERROR("Unable to open fan speed control node (%s)", FAN_SPEED_CTRL_PATH);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (len <= 0) {
|
||||
AIM_LOG_ERROR("Unable to read fan speed from (%s)", FAN_SPEED_CTRL_PATH);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
|
||||
current_duty_cycle = atoi(buf);
|
||||
|
||||
current_state=ori_state=fan_state;
|
||||
|
||||
/* Check thermal is in which range. */
|
||||
max_to_def=0;
|
||||
if(direction_val==1) /* AFI */
|
||||
{
|
||||
if(fan_state==LEVEL_FAN_INIT)
|
||||
{
|
||||
current_state=LEVEL_FAN_DEF;
|
||||
}
|
||||
for (i=0; i <CHASSIS_THERMAL_COUNT; i++)
|
||||
{
|
||||
if (thermal[i].mcelsius >= afi_thermal_spec.def_to_max_temp[i])
|
||||
{
|
||||
current_state=LEVEL_FAN_MAX;
|
||||
break;
|
||||
}
|
||||
if (thermal[i].mcelsius <= afi_thermal_spec.def_to_max_temp[i])
|
||||
{
|
||||
max_to_def++;
|
||||
}
|
||||
}
|
||||
if(max_to_def==CHASSIS_THERMAL_COUNT && fan_state==LEVEL_FAN_MAX)
|
||||
{
|
||||
current_state=LEVEL_FAN_DEF;
|
||||
}
|
||||
}
|
||||
else /* AFO */
|
||||
{
|
||||
if(fan_state==LEVEL_FAN_INIT)
|
||||
{
|
||||
current_state=LEVEL_FAN_DEF;
|
||||
}
|
||||
for (i=0; i <CHASSIS_THERMAL_COUNT; i++)
|
||||
{
|
||||
if (thermal[i].mcelsius >= afo_thermal_spec.def_to_mid_temp[i])
|
||||
{
|
||||
current_state=LEVEL_FAN_MID;
|
||||
}
|
||||
if (thermal[i].mcelsius >= afo_thermal_spec.mid_to_max_temp[i])
|
||||
{
|
||||
current_state=LEVEL_FAN_MAX;
|
||||
break;
|
||||
}
|
||||
if (thermal[i].mcelsius <= afo_thermal_spec.max_to_mid_temp[i])
|
||||
{
|
||||
max_to_mid++;
|
||||
}
|
||||
if (thermal[i].mcelsius <= afo_thermal_spec.mid_to_def_temp[i])
|
||||
{
|
||||
mid_to_def++;
|
||||
}
|
||||
}
|
||||
if(max_to_mid==CHASSIS_THERMAL_COUNT && fan_state==LEVEL_FAN_MAX)
|
||||
{
|
||||
current_state=LEVEL_FAN_MID;
|
||||
}
|
||||
if(mid_to_def==CHASSIS_THERMAL_COUNT && fan_state==LEVEL_FAN_MID)
|
||||
{
|
||||
current_state=LEVEL_FAN_DEF;
|
||||
}
|
||||
|
||||
}
|
||||
// fan_state = current_state;
|
||||
/*
|
||||
for(i=0; i < sizeof(fan_thermal_policy_f2b)/sizeof(fan_ctrl_policy_t); i++)
|
||||
{
|
||||
if (temp > fan_thermal_policy[i].temp_down)
|
||||
{
|
||||
if (temp <= fan_thermal_policy[i].temp_up)
|
||||
{
|
||||
current_state =i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Get each fan status
|
||||
*/
|
||||
for (i = 1; i <= NUM_OF_FAN_ON_MAIN_BROAD; i++)
|
||||
{
|
||||
onlp_fan_info_t fan_info;
|
||||
|
||||
if (onlp_fani_info_get(ONLP_FAN_ID_CREATE(i), &fan_info) != ONLP_STATUS_OK) {
|
||||
AIM_LOG_ERROR("Unable to get fan(%d) status\r\n", i);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
|
||||
present = fan_info.status & ONLP_FAN_STATUS_PRESENT;
|
||||
if ((fan_info.status & ONLP_FAN_STATUS_FAILED) || !present) {
|
||||
AIM_LOG_WARN("Fan(%d) is not working, set the other fans as full speed\r\n", i);
|
||||
int ret = onlp_fani_percentage_set(
|
||||
ONLP_FAN_ID_CREATE(FAN_ID_FOR_SET_FAN_DUTY), FAN_DUTY_CYCLE_MAX);
|
||||
if (ret != ONLP_STATUS_OK)
|
||||
return ret;
|
||||
else
|
||||
return ONLP_STATUS_E_MISSING;
|
||||
}
|
||||
|
||||
/* Get fan direction (Only get the first one since all fan direction are the same)
|
||||
AIM_LOG_ERROR("Unable to get fan(%d) status, try to set the other fans as full speed\r\n", i);
|
||||
if(current_duty_cycle != FAN_DUTY_CYCLE_MAX)
|
||||
{
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(1), FAN_DUTY_CYCLE_MAX);
|
||||
}
|
||||
fan_fail=1;
|
||||
break;
|
||||
}
|
||||
/* Decision 1: Set fan as full speed if any fan is failed.
|
||||
*/
|
||||
if (i == 1) {
|
||||
*fan_dir = fan_info.status & (ONLP_FAN_STATUS_F2B|ONLP_FAN_STATUS_B2F);
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
sysi_get_fan_duty(int *cur_duty_cycle){
|
||||
int fd, len;
|
||||
char buf[10] = {0};
|
||||
char *node = FAN_NODE(fan_duty_cycle_percentage);
|
||||
|
||||
/* Get current fan duty*/
|
||||
fd = open(node, O_RDONLY);
|
||||
if (fd == -1){
|
||||
AIM_LOG_ERROR("Unable to open fan speed control node (%s)", node);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (len <= 0) {
|
||||
AIM_LOG_ERROR("Unable to read fan speed from (%s)", node);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
*cur_duty_cycle = atoi(buf);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
sysi_get_thermal_sum(int *mcelsius){
|
||||
onlp_thermal_info_t thermal_info;
|
||||
int i;
|
||||
|
||||
*mcelsius = 0;
|
||||
for (i = 1; i <= CHASSIS_THERMAL_COUNT; i++) {
|
||||
if (onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(i), &thermal_info)
|
||||
!= ONLP_STATUS_OK) {
|
||||
AIM_LOG_ERROR("Unable to read thermal status");
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
if (fan_info.status & ONLP_FAN_STATUS_FAILED || !(fan_info.status & ONLP_FAN_STATUS_PRESENT)) {
|
||||
AIM_LOG_ERROR("Fan(%d) is not working, set the other fans as full speed\r\n", i);
|
||||
if(current_duty_cycle != FAN_DUTY_CYCLE_MAX)
|
||||
{
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(1), FAN_DUTY_CYCLE_MAX);
|
||||
}
|
||||
*mcelsius += thermal_info.mcelsius;
|
||||
|
||||
DEBUG_PRINT("Thermal %d: %d \n ", i, thermal_info.mcelsius);
|
||||
|
||||
}
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
sysi_get_highest_thermal(int *mcelsius){
|
||||
onlp_thermal_info_t thermal_info;
|
||||
int i, highest;
|
||||
|
||||
highest = 0;
|
||||
for (i = 1; i <= CHASSIS_THERMAL_COUNT; i++) {
|
||||
if (onlp_thermali_info_get(ONLP_THERMAL_ID_CREATE(i), &thermal_info)
|
||||
!= ONLP_STATUS_OK) {
|
||||
AIM_LOG_ERROR("Unable to read thermal status");
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
highest = (thermal_info.mcelsius > highest)?
|
||||
thermal_info.mcelsius : highest;
|
||||
}
|
||||
*mcelsius = highest;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
/* Anaylze thermal changing history to judge if the change is a stable trend. */
|
||||
static int _is_thermal_a_trend(int *mc_history){
|
||||
int i, trend, trended;
|
||||
|
||||
if (mc_history == NULL) {
|
||||
AIM_LOG_ERROR("Unable to get history of thermal\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get heat up/down trend. */
|
||||
trend = 0;
|
||||
for (i = 0; i < CELSIUS_RECORD_NUMBER; i++) {
|
||||
if (( mc_history[i+1] < mc_history[i])){
|
||||
trend++;
|
||||
}else if (( mc_history[i+1] > mc_history[i])){
|
||||
trend--;
|
||||
}
|
||||
}
|
||||
|
||||
trended = (abs(trend) >= ((CELSIUS_RECORD_NUMBER+1)/2))? 1:0;
|
||||
#if (DEBUG_MODE == 1)
|
||||
DEBUG_PRINT("[INFO]%s#%d, trended: %d, UP/DW: %d mcelsius:",
|
||||
__func__, __LINE__, trended, trend );
|
||||
for (i = 0; i <= CELSIUS_RECORD_NUMBER; i++) {
|
||||
DEBUG_PRINT(" %d =>", mc_history[i]);
|
||||
}
|
||||
DEBUG_PRINT("%c\n", ' ');
|
||||
#endif
|
||||
|
||||
/*For more than half changes are same direction, it's a firm trend.*/
|
||||
return trended;
|
||||
}
|
||||
|
||||
|
||||
/* Decide duty by highest value of thermal sensors.*/
|
||||
static int
|
||||
sysi_get_duty_by_highest(int *duty_cycle){
|
||||
int i, ret, maxtrix_len;
|
||||
int new_duty_cycle = 0 ;
|
||||
int mc_history[CELSIUS_RECORD_NUMBER+1] = {0};
|
||||
int *mcelsius_pre_p = &mc_history[1];
|
||||
int *mcelsius_now_p = &mc_history[0];
|
||||
|
||||
/* Fill up mcelsius array,
|
||||
* [0] is current temperature, others are history.
|
||||
*/
|
||||
ret = sysi_get_highest_thermal(mcelsius_now_p);
|
||||
if(ONLP_STATUS_OK != ret){
|
||||
return ret;
|
||||
}
|
||||
memcpy (mcelsius_pre_p, fan_control_data_pre.mc_high_pre,
|
||||
sizeof(fan_control_data_pre.mc_high_pre));
|
||||
|
||||
DEBUG_PRINT("[INFO]%s#%d, highest mcelsius:%d!\n",
|
||||
__func__, __LINE__, *mcelsius_now_p);
|
||||
|
||||
/* Shift records to the right */
|
||||
for (i = 0; i < CELSIUS_RECORD_NUMBER; i++) {
|
||||
fan_control_data_pre.mc_high_pre[i] = mc_history[i];
|
||||
}
|
||||
|
||||
/* Only change duty on consecutive heat rising or falling.*/
|
||||
maxtrix_len = AIM_ARRAYSIZE(fan_ctrl_policy_single);
|
||||
|
||||
/* Only change duty when the thermal changing are firm. */
|
||||
if (_is_thermal_a_trend(mc_history))
|
||||
{
|
||||
int matched = 0;
|
||||
for (i = 0; i < maxtrix_len; i++) {
|
||||
if ((*mcelsius_now_p > fan_ctrl_policy_single[i].step_up_thermal)) {
|
||||
new_duty_cycle = fan_ctrl_policy_single[i].duty_cycle;
|
||||
matched = !matched;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* if (!matched) {
|
||||
DEBUG_PRINT("%s#%d, celsius(%d) falls into undefined range!!\n",
|
||||
__func__, __LINE__, *mcelsius_now_p);
|
||||
} */
|
||||
}
|
||||
*duty_cycle = new_duty_cycle;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
/* Decide duty by average value of thermal sensors.*/
|
||||
static int
|
||||
sysi_get_duty_by_average(int *duty_cycle){
|
||||
int i, mcelsius_avg, ret, maxtrix_len;
|
||||
int new_duty_cycle=0;
|
||||
int mc_history[CELSIUS_RECORD_NUMBER+1] = {0};
|
||||
int *mcelsius_pre_p = &mc_history[1];
|
||||
int *mcelsius_now_p = &mc_history[0];
|
||||
|
||||
/* Fill up mcelsius array,
|
||||
* [0] is current temperature, others are history.
|
||||
*/
|
||||
*mcelsius_now_p = 0;
|
||||
ret = sysi_get_thermal_sum(mcelsius_now_p);
|
||||
if(ONLP_STATUS_OK != ret){
|
||||
return ret;
|
||||
}
|
||||
mcelsius_avg = (*mcelsius_now_p)/CHASSIS_THERMAL_COUNT;
|
||||
|
||||
memcpy (mcelsius_pre_p, fan_control_data_pre.mc_avg_pre,
|
||||
sizeof(fan_control_data_pre.mc_avg_pre));
|
||||
|
||||
DEBUG_PRINT("[INFO]%s#%d, mcelsius:%d!\n", __func__, __LINE__, mcelsius_avg);
|
||||
|
||||
/* Shift records to the right */
|
||||
for (i = 0; i < CELSIUS_RECORD_NUMBER; i++) {
|
||||
fan_control_data_pre.mc_avg_pre[i] = mc_history[i];
|
||||
}
|
||||
|
||||
/* Only change duty on consecutive heat rising or falling.*/
|
||||
maxtrix_len = AIM_ARRAYSIZE(fan_ctrl_policy_avg);
|
||||
|
||||
/* Only change duty when the thermal changing are firm. */
|
||||
if (_is_thermal_a_trend(mc_history))
|
||||
{
|
||||
int matched = 0;
|
||||
for (i = 0; i < maxtrix_len; i++) {
|
||||
if ((mcelsius_avg >= fan_ctrl_policy_avg[i].step_up_thermal)) {
|
||||
new_duty_cycle = fan_ctrl_policy_avg[i].duty_cycle;
|
||||
matched = !matched;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = maxtrix_len-1; i>=0; i--) {
|
||||
if ((mcelsius_avg < fan_ctrl_policy_avg[i].step_dn_thermal)) {
|
||||
new_duty_cycle = fan_ctrl_policy_avg[i].duty_cycle;
|
||||
matched = !matched;
|
||||
fan_fail=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*if (!matched) {
|
||||
DEBUG_PRINT("%s#%d, celsius(%d) falls into undefined range!!\n",
|
||||
__func__, __LINE__, mcelsius_avg);
|
||||
} */
|
||||
}
|
||||
|
||||
*duty_cycle = new_duty_cycle;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
onlp_sysi_platform_manage_fans(void)
|
||||
{
|
||||
uint32_t fan_dir;
|
||||
int ret;
|
||||
int cur_duty_cycle, new_duty_cycle, tmp;
|
||||
int direct_addon = 0;
|
||||
onlp_oid_t fan_duty_oid = ONLP_FAN_ID_CREATE(FAN_ID_FOR_SET_FAN_DUTY);
|
||||
|
||||
/**********************************************************
|
||||
* Decision 1: Set fan as full speed if any fan is failed.
|
||||
**********************************************************/
|
||||
ret = sysi_check_fan(&fan_dir);
|
||||
if(ONLP_STATUS_OK != ret){
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fan_dir & ONLP_FAN_STATUS_B2F) {
|
||||
direct_addon = FAN_DUTY_PLUS_FOR_DIR;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Decision 2: If no matched fan speed is found from the policy,
|
||||
* use FAN_DUTY_CYCLE_MIN as default speed
|
||||
**********************************************************/
|
||||
ret = sysi_get_fan_duty(&cur_duty_cycle);
|
||||
if(ONLP_STATUS_OK != ret){
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Decision 3: Decide new fan speed depend on fan direction and temperature
|
||||
**********************************************************/
|
||||
ret = sysi_get_duty_by_average(&new_duty_cycle);
|
||||
if (ONLP_STATUS_OK != ret){
|
||||
return ret;
|
||||
}
|
||||
ret = sysi_get_duty_by_highest(&tmp);
|
||||
if (ONLP_STATUS_OK != ret){
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_duty_cycle = (tmp > new_duty_cycle)? tmp : new_duty_cycle;
|
||||
if (new_duty_cycle == 0)
|
||||
if(current_state!=ori_state)
|
||||
{
|
||||
new_duty_cycle = fan_control_data_pre.duty_cycle;
|
||||
} else {
|
||||
fan_control_data_pre.duty_cycle = new_duty_cycle;
|
||||
}
|
||||
fan_control_data_pre.dir_plus = direct_addon;
|
||||
DEBUG_PRINT("[INFO]%s#%d, new duty: %d = %d + %d (%d)!\n", __func__, __LINE__,
|
||||
new_duty_cycle + direct_addon, new_duty_cycle, direct_addon, cur_duty_cycle);
|
||||
|
||||
new_duty_cycle += direct_addon;
|
||||
new_duty_cycle = (new_duty_cycle > FAN_DUTY_CYCLE_MAX)?
|
||||
FAN_DUTY_CYCLE_MAX : new_duty_cycle;
|
||||
|
||||
if (new_duty_cycle == cur_duty_cycle) {
|
||||
/* Duty cycle does not change, just return */
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
fan_state=current_state;
|
||||
new_duty_cycle=onlp_sysi_get_duty_cycle_by_fan_state(current_state, direction_val);
|
||||
if(new_duty_cycle!=current_duty_cycle && !fan_fail)
|
||||
{
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(1), new_duty_cycle);
|
||||
}
|
||||
if(!new_duty_cycle && !fan_fail)
|
||||
{
|
||||
onlp_fani_percentage_set(ONLP_FAN_ID_CREATE(1), FAN_DUTY_CYCLE_MAX);
|
||||
}
|
||||
|
||||
switch (ori_state)
|
||||
{
|
||||
case LEVEL_FAN_INIT:
|
||||
break;
|
||||
case LEVEL_FAN_DEF:
|
||||
break;
|
||||
case LEVEL_FAN_MID:
|
||||
break;
|
||||
case LEVEL_FAN_MAX:
|
||||
break;
|
||||
default:
|
||||
AIM_SYSLOG_WARN("onlp_sysi_platform_manage_fans abnormal state", "onlp_sysi_platform_manage_fans abnormal state", "onlp_sysi_platform_manage_fans at abnormal state\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return onlp_fani_percentage_set(fan_duty_oid, new_duty_cycle);
|
||||
}
|
||||
|
||||
int
|
||||
onlp_sysi_platform_manage_leds(void)
|
||||
{
|
||||
return ONLP_STATUS_E_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user