meta-facebook/meta-fbtp/recipes-fbtp/sensor-svc-pal/files/sensorsvcpal.c (1,910 lines of code) (raw):

/* * sensorsvcpal.c * * Copyright 2017-present Facebook. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <fcntl.h> #include <errno.h> #include <syslog.h> #include <sys/mman.h> #include <string.h> #include <ctype.h> #include <pthread.h> #include <unistd.h> #include <sys/time.h> #include "sensorsvcpal.h" #include <openbmc/obmc-i2c.h> #include <sys/stat.h> #include <openbmc/gpio.h> #include <openbmc/kv.h> #define BIT(value, index) ((value >> index) & 1) #define LAST_KEY "last_key" #define GPIO_VAL "/sys/class/gpio/gpio%d/value" #define GPIO_DIR "/sys/class/gpio/gpio%d/direction" #define GPIO_POWER_GOOD 14 #define GPIO_BOARD_SKU_ID0 120 #define GPIO_BOARD_SKU_ID1 121 #define GPIO_BOARD_SKU_ID2 122 #define GPIO_BOARD_SKU_ID3 123 #define GPIO_BOARD_SKU_ID4 124 #define GPIO_SLT_CFG0 142 #define GPIO_SLT_CFG1 143 #define GPIO_FM_CPU0_SKTOCC_LVT3_N 51 #define GPIO_FM_CPU1_SKTOCC_LVT3_N 208 #define GPIO_FM_BIOS_POST_CMPLT_N 215 #define GPIO_FM_SLPS4_N 193 #define GPIO_FM_FORCE_ADR_N 66 #define LARGEST_DEVICE_NAME 120 #define PWM_DIR "/sys/devices/platform/ast_pwm_tacho.0" #define PWM_UNIT_MAX 96 #define HSC_IN_VOLT "in1_input" #define HSC_OUT_CURR "curr1_input" #define RISER_BUS_ID 0x1 #define READING_NA -2 #define READING_SKIP 1 #define NIC_MAX_TEMP 125 #define MAX_READ_RETRY 10 #define POST_CODE_FILE "/sys/devices/platform/ast-snoop-dma.0/data_history" #define CPLD_BUS_ID 0x6 #define CPLD_ADDR 0xA0 static size_t pal_pwm_cnt = 2; static int key_func_por_policy (int event, void *arg); static int key_func_lps (int event, void *arg); static int key_func_tz (int event, void *arg); static uint8_t power_fail_log = 0; enum key_event { KEY_BEFORE_SET, KEY_AFTER_INI, }; struct pal_key_cfg { char *name; char *def_val; int (*function)(int, void*); } key_cfg[] = { /* name, default value, function */ {"pwr_server_last_state", "on", key_func_lps}, {"sysfw_ver_server", "0", NULL}, {"identify_sled", "off", NULL}, {"timestamp_sled", "0", NULL}, {"server_por_cfg", "lps", key_func_por_policy}, {"server_sensor_health", "1", NULL}, {"nic_sensor_health", "1", NULL}, {"server_sel_error", "1", NULL}, {"server_boot_order", "0000000", NULL}, {"ntp_server", "", NULL}, {"time_zone", "UTC", key_func_tz}, /* Add more Keys here */ {LAST_KEY, LAST_KEY, NULL} /* This is the last key of the list */ }; typedef struct _inlet_corr_t { uint8_t duty; int8_t delta_t; } inlet_corr_t; static inlet_corr_t g_ict[] = { { 10, 7 }, { 12, 6 }, { 14, 5 }, { 18, 4 }, { 20, 3 }, { 24, 2 }, { 32, 1 }, { 41, 0 }, }; static uint8_t g_ict_count = sizeof(g_ict)/sizeof(inlet_corr_t); static void _print_sensor_discrete_log(uint8_t fru, uint8_t snr_num, char *snr_name, uint8_t val, char *event); void pal_apply_inlet_correction(float *value) { static int8_t dt = 0; int i; uint8_t pwm[2] = {0}; // Get PWM value if (pal_get_pwm_value(0, &pwm[0]) || pal_get_pwm_value(1, &pwm[1])) { // If error reading PWM value, use the previous deltaT *value -= dt; return; } pwm[0] = (pwm[0] + pwm[1]) /2; // Scan through the correction table to get correction value for given PWM dt=g_ict[0].delta_t; for (i=0; i< g_ict_count; i++) { if (pwm[0] >= g_ict[i].duty) dt = g_ict[i].delta_t; else break; } // Apply correction for the sensor *(float*)value -= dt; } static int pal_control_mux(int fd, uint8_t addr, uint8_t channel) { uint8_t tcount = 1, rcount = 0; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}; // PCA9544A if (channel < 4) tbuf[0] = 0x04 + channel; else tbuf[0] = 0x00; // close all channels return i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount); } static int pal_control_switch(int fd, uint8_t addr, uint8_t channel) { uint8_t tcount = 1, rcount = 0; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}; // PCA9846 if (channel < 4) tbuf[0] = 0x01 << channel; else tbuf[0] = 0x00; // close all channels return i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount); } static int read_device(const char *device, int *value) { FILE *fp; int rc; fp = fopen(device, "r"); if (!fp) { int err = errno; #ifdef DEBUG syslog(LOG_INFO, "failed to open device %s", device); #endif return err; } rc = fscanf(fp, "%d", value); fclose(fp); if (rc != 1) { #ifdef DEBUG syslog(LOG_INFO, "failed to read device %s", device); #endif return ENOENT; } else { return 0; } } static int read_device_hex(const char *device, int *value) { FILE *fp; int rc; fp = fopen(device, "r"); if (!fp) { #ifdef DEBUG syslog(LOG_INFO, "failed to open device %s", device); #endif return errno; } rc = fscanf(fp, "%x", value); fclose(fp); if (rc != 1) { #ifdef DEBUG syslog(LOG_INFO, "failed to read device %s", device); #endif return ENOENT; } else { return 0; } } int pal_read_hsc_current_value(float *value) { uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP uint8_t tbuf[256] = {0x00}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 0; uint8_t rlen = 0; float hsc_b = 20475; float Rsence; ipmb_req_t *req; char path[64] = {0}; int val=0; int ret = 0; static int retry = 0; req = (ipmb_req_t*)tbuf; req->res_slave_addr = 0x2C; //ME's Slave Address req->netfn_lun = NETFN_NM_REQ<<2; req->hdr_cksum = req->res_slave_addr + req->netfn_lun; req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum; req->req_slave_addr = 0x20; req->seq_lun = 0x00; req->cmd = CMD_NM_SEND_RAW_PMBUS; req->data[0] = 0x57; req->data[1] = 0x01; req->data[2] = 0x00; req->data[3] = 0x86; //HSC slave addr check for SS and DS sprintf(path, GPIO_VAL, GPIO_BOARD_SKU_ID4); read_device(path, &val); if (val){ //DS req->data[4] = 0x8A; Rsence = 0.265; }else{ //SS req->data[4] = 0x22; Rsence = 0.505; } req->data[5] = 0x00; req->data[6] = 0x00; req->data[7] = 0x01; req->data[8] = 0x02; req->data[9] = 0x8C; tlen = 16; // Invoke IPMB library handler lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf, &rlen); if (rlen == 0) { #ifdef DEBUG syslog(LOG_DEBUG, "read_hsc_current_value: Zero bytes received\n"); #endif ret = READING_NA; } if (rbuf[6] == 0) { *value = ((float) (rbuf[11] << 8 | rbuf[10])*10-hsc_b )/(800*Rsence); retry = 0; } else { ret = READING_NA; } if (ret == READING_NA) { retry++; if (retry <= 3 ) ret = READING_SKIP; } return ret; } int pal_read_sensor_reading_from_ME(uint8_t snr_num, float *value) { uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP uint8_t tbuf[256] = {0x00}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 0; uint8_t rlen = 0; ipmb_req_t *req; int ret = 0; enum { e_HSC_PIN, e_HSC_VIN, e_PCH_TEMP, e_MAX, }; static uint8_t retry[e_MAX] = {0}; req = (ipmb_req_t*)tbuf; req->res_slave_addr = 0x2C; //ME's Slave Address req->netfn_lun = NETFN_SENSOR_REQ<<2; req->hdr_cksum = req->res_slave_addr + req->netfn_lun; req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum; req->req_slave_addr = 0x20; req->seq_lun = 0x00; req->cmd = CMD_SENSOR_GET_SENSOR_READING; req->data[0] = snr_num; tlen = 7; // Invoke IPMB library handler lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf, &rlen); if (rlen == 0) { //ME no response #ifdef DEBUG syslog(LOG_DEBUG, "read HSC %x from_ME: Zero bytes received\n", snr_num); #endif ret = READING_NA; } else { if (rbuf[6] == 0) { if (rbuf[8] & 0x20) { //not available ret = READING_NA; } } else { ret = READING_NA; } } if(snr_num == MB_SENSOR_HSC_IN_POWER) { if (!ret) { *value = (((float) rbuf[7])*0x28 + 0 )/10 ; retry[e_HSC_PIN] = 0; } else { retry[e_HSC_PIN]++; if (retry[e_HSC_PIN] <= 3) ret = READING_SKIP; } } else if(snr_num == MB_SENSOR_HSC_IN_VOLT) { if (!ret) { *value = (((float) rbuf[7])*0x02 + (0x5e*10) )/100 ; retry[e_HSC_VIN] = 0; } else { retry[e_HSC_VIN]++; if (retry[e_HSC_VIN] <= 3) ret = READING_SKIP; } } else if(snr_num == MB_SENSOR_PCH_TEMP) { if (!ret) { *value = (float) rbuf[7]; retry[e_PCH_TEMP] = 0; } else { retry[e_PCH_TEMP]++; if (retry[e_PCH_TEMP] <= 3) ret = READING_SKIP; } } return ret; } int pal_read_cpu_temp(uint8_t snr_num, float *value) { int ret = 0; uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP uint8_t tbuf[256] = {0x00}; uint8_t rbuf1[256] = {0x00}; static uint8_t tjmax[2] = {0x00}; static uint8_t tjmax_flag[2] = {0}; uint8_t tlen = 0; uint8_t rlen = 0; ipmb_req_t *req; char key[MAX_KEY_LEN] = {0}; char str[MAX_VALUE_LEN] = {0}; int cpu_index; int16_t dts; static uint8_t retry[2] = {0x00}; // CPU0 and CPU1 switch (snr_num) { case MB_SENSOR_CPU0_TEMP: cpu_index = 0; break; case MB_SENSOR_CPU1_TEMP: cpu_index = 1; break; default: return -1; } req = (ipmb_req_t*)tbuf; req->res_slave_addr = 0x2C; //ME's Slave Address req->netfn_lun = NETFN_NM_REQ<<2; req->hdr_cksum = req->res_slave_addr + req->netfn_lun; req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum; req->req_slave_addr = 0x20; req->seq_lun = 0x00; if( tjmax_flag[cpu_index] == 0 ) { // First time to get CPU0/CPU1 Tjmax reading //Get CPU0/CPU1 Tjmax req->cmd = CMD_NM_SEND_RAW_PECI; req->data[0] = 0x57; req->data[1] = 0x01; req->data[2] = 0x00; req->data[3] = 0x30 + cpu_index; req->data[4] = 0x05; req->data[5] = 0x05; req->data[6] = 0xa1; req->data[7] = 0x00; req->data[8] = 0x10; req->data[9] = 0x00; req->data[10] = 0x00; tlen = 17; // Invoke IPMB library handler lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen); if (rlen == 0) { //ME no response #ifdef DEBUG syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__); #endif } else { if (rbuf1[6] == 0) { // If PECI command successes and got a reasonable value if ( (rbuf1[10] == 0x40) && rbuf1[13] > 50) { tjmax[cpu_index] = rbuf1[13]; tjmax_flag[cpu_index] = 1; } } } } //Updated CPU Tjmax cache sprintf(key, "mb_sensor%d", (cpu_index?MB_SENSOR_CPU1_TJMAX:MB_SENSOR_CPU0_TJMAX)); if (tjmax_flag[cpu_index] != 0) { sprintf(str, "%.2f",(float) tjmax[cpu_index]); } else { //ME no response or PECI command completion code error. Set "NA" in sensor cache. strcpy(str, "NA"); } kv_set(key, str, 0, 0); // Get CPU temp if BMC got TjMax ret = READING_NA; if (tjmax_flag[cpu_index] != 0) { rlen = 0; memset( rbuf1,0x00,sizeof(rbuf1) ); //Get CPU Temp req->cmd = CMD_NM_SEND_RAW_PECI; req->data[0] = 0x57; req->data[1] = 0x01; req->data[2] = 0x00; req->data[3] = 0x30 + cpu_index; req->data[4] = 0x05; req->data[5] = 0x05; req->data[6] = 0xa1; req->data[7] = 0x00; req->data[8] = 0x02; req->data[9] = 0xff; req->data[10] = 0x00; tlen = 17; // Invoke IPMB library handler lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen); if (rlen == 0) { //ME no response #ifdef DEBUG syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__); #endif } else { if (rbuf1[6] == 0) { // ME Completion Code if ( (rbuf1[10] == 0x40) ) { // PECI Completion Code dts = (rbuf1[11] | rbuf1[12] << 8); // Intel Doc#554767 p.58: Reserved Values 0x8000~0x81ff if (dts <= -32257) { ret = READING_NA; } else { // 16-bit, 2s complement [15]Sign Bit;[14:6]Integer Value;[5:0]Fractional Value *value = (float) (tjmax[0] + (dts >> 6)); ret = 0; } } } } } if (ret != 0) { retry[cpu_index]++; if (retry[cpu_index] <= 3) { ret = READING_SKIP; return ret; } } else retry[cpu_index] = 0; return ret; } static int pal_get_platform_id(uint8_t *id) { int val; char path[64] = {0}; sprintf(path, GPIO_VAL, GPIO_BOARD_SKU_ID0); if (read_device(path, &val)) { return -1; } *id = val&0x01; sprintf(path, GPIO_VAL, GPIO_BOARD_SKU_ID1); if (read_device(path, &val)) { return -1; } *id = *id | (val<<1); sprintf(path, GPIO_VAL, GPIO_BOARD_SKU_ID2); if (read_device(path, &val)) { return -1; } *id = *id | (val<<2); sprintf(path, GPIO_VAL, GPIO_BOARD_SKU_ID3); if (read_device(path, &val)) { return -1; } *id = *id | (val<<3); sprintf(path, GPIO_VAL, GPIO_BOARD_SKU_ID4); if (read_device(path, &val)) { return -1; } *id = *id | (val<<4); return 0; } int pal_read_dimm_temp(uint8_t snr_num, float *value) { int ret = READING_NA; uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP uint8_t tbuf[256] = {0x00}; uint8_t rbuf1[256] = {0x00}; uint8_t tlen = 0; uint8_t rlen = 0; ipmb_req_t *req; int dimm_index, i; int max = 0; static uint8_t retry[4] = {0x00}; int val; char path[64] = {0}; static int odm_id = -1; uint8_t BoardInfo; //Use FM_BOARD_SKU_ID0 to identify ODM to apply filter if (odm_id == -1) { ret = pal_get_platform_id(&BoardInfo); if (ret == 0) { odm_id = (int) (BoardInfo & 0x1); } } // show NA if BIOS has not completed POST. sprintf(path, GPIO_VAL, GPIO_FM_BIOS_POST_CMPLT_N); if (read_device(path, &val) || val) { return ret; } switch (snr_num) { case MB_SENSOR_CPU0_DIMM_GRPA_TEMP: dimm_index = 0; break; case MB_SENSOR_CPU0_DIMM_GRPB_TEMP: dimm_index = 1; break; case MB_SENSOR_CPU1_DIMM_GRPC_TEMP: dimm_index = 2; break; case MB_SENSOR_CPU1_DIMM_GRPD_TEMP: dimm_index = 3; break; default: return -1; } req = (ipmb_req_t*)tbuf; req->res_slave_addr = 0x2C; //ME's Slave Address req->netfn_lun = NETFN_NM_REQ<<2; req->hdr_cksum = req->res_slave_addr + req->netfn_lun; req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum; req->req_slave_addr = 0x20; req->seq_lun = 0x00; for (i=0; i<3; i++) { // Get 3 channel for each DIMM group //Get DIMM Temp per channel req->cmd = CMD_NM_SEND_RAW_PECI; req->data[0] = 0x57; req->data[1] = 0x01; req->data[2] = 0x00; req->data[3] = 0x30 + (dimm_index / 2); req->data[4] = 0x05; req->data[5] = 0x05; req->data[6] = 0xa1; req->data[7] = 0x00; req->data[8] = 0x0e; req->data[9] = 0x00 + (dimm_index % 2 * 3) + i; req->data[10] = 0x00; tlen = 17; // Invoke IPMB library handler lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen); if (rlen == 0) { //ME no response #ifdef DEBUG syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__); #endif } else { if (rbuf1[6] == 0) { // If PECI command successes if ( (rbuf1[10] == 0x40)) { if (rbuf1[11] > max) max = rbuf1[11]; if (rbuf1[12] > max) max = rbuf1[11]; } } } } if (odm_id == 1) { // Filter abnormal values: 0x0 and 0xFF if (max != 0 && max != 0xFF) ret = 0; } else { // Filter abnormal values: 0x0 if (max != 0) ret = 0; } if (ret != 0) { retry[dimm_index]++; if (retry[dimm_index] <= 3) { ret = READING_SKIP; return ret; } } else retry[dimm_index] = 0; if (ret == 0) { *value = (float)max; } return ret; } int pal_read_cpu_package_power(uint8_t snr_num, float *value) { int ret = READING_NA; uint8_t bus_id = 0x4; //TODO: ME's address 0x2c in FBTP uint8_t tbuf[256] = {0x00}; uint8_t rbuf1[256] = {0x00}; // Energy units: Intel Doc#554767, p37, 2^(-ENERGY UNIT) J, ENERGY UNIT defalut is 14 // Run Time units: Intel Doc#554767, p33, msec // 2^(-14)*1000 = 0.06103515625 float unit = 0.06103515625f; static uint32_t last_pkg_energy[2] = {0}, last_run_time[2] = {0}; uint32_t pkg_energy, run_time, diff_energy, diff_time; uint8_t tlen = 0; uint8_t rlen = 0; ipmb_req_t *req; int cpu_index; static uint8_t retry[2] = {0x00}; // CPU0 and CPU1 switch (snr_num) { case MB_SENSOR_CPU0_PKG_POWER: cpu_index = 0; break; case MB_SENSOR_CPU1_PKG_POWER: cpu_index = 1; break; default: return -1; } req = (ipmb_req_t*)tbuf; req->res_slave_addr = 0x2C; //ME's Slave Address req->netfn_lun = NETFN_NM_REQ<<2; req->hdr_cksum = req->res_slave_addr + req->netfn_lun; req->hdr_cksum = ZERO_CKSUM_CONST - req->hdr_cksum; req->req_slave_addr = 0x20; req->seq_lun = 0x00; // Get CPU package power and run time rlen = 0; memset( rbuf1,0x00,sizeof(rbuf1) ); //Read Accumulated Energy Pkg and Accumulated Run Time req->cmd = CMD_NM_AGGREGATED_SEND_RAW_PECI; req->data[0] = 0x57; req->data[1] = 0x01; req->data[2] = 0x00; req->data[3] = 0x30 + cpu_index; req->data[4] = 0x05; req->data[5] = 0x05; req->data[6] = 0xa1; req->data[7] = 0x00; req->data[8] = 0x03; req->data[9] = 0xff; req->data[10] = 0x00; req->data[11] = 0x30 + cpu_index; req->data[12] = 0x05; req->data[13] = 0x05; req->data[14] = 0xa1; req->data[15] = 0x00; req->data[16] = 0x1F; req->data[17] = 0x00; req->data[18] = 0x00; tlen = 25; // Invoke IPMB library handler lib_ipmb_handle(bus_id, tbuf, tlen+1, rbuf1, &rlen); if (rlen == 0) { //ME no response #ifdef DEBUG syslog(LOG_DEBUG, "%s(%d): Zero bytes received\n", __func__, __LINE__); #endif goto error_exit; } else { if (rbuf1[6] == 0) { // ME Completion Code if ( (rbuf1[10] == 0x00) && (rbuf1[11] == 0x40) && // 1st ME CC & PECI CC (rbuf1[16] == 0x00) && (rbuf1[17] == 0x40) ){ // 2nd ME CC & PECI CC pkg_energy = rbuf1[15]; pkg_energy = (pkg_energy << 8) | rbuf1[14]; pkg_energy = (pkg_energy << 8) | rbuf1[13]; pkg_energy = (pkg_energy << 8) | rbuf1[12]; run_time = rbuf1[21]; run_time = (run_time << 8) | rbuf1[20]; run_time = (run_time << 8) | rbuf1[19]; run_time = (run_time << 8) | rbuf1[18]; ret = 0; } } } // need at least 2 entries to calculate if (last_pkg_energy[cpu_index] == 0 && last_run_time[cpu_index] == 0) { if (ret == 0) { last_pkg_energy[cpu_index] = pkg_energy; last_run_time[cpu_index] = run_time; } ret = READING_NA; } if(!ret) { if(pkg_energy >= last_pkg_energy[cpu_index]) diff_energy = pkg_energy - last_pkg_energy[cpu_index]; else diff_energy = pkg_energy + (0xffffffff - last_pkg_energy[cpu_index] + 1); last_pkg_energy[cpu_index] = pkg_energy; if(run_time >= last_run_time[cpu_index]) diff_time = run_time - last_run_time[cpu_index]; else diff_time = run_time + (0xffffffff - last_run_time[cpu_index] + 1); last_run_time[cpu_index] = run_time; if(diff_time == 0) ret = READING_NA; else *value = ((float)diff_energy / (float)diff_time * unit); } error_exit: if (ret != 0) { retry[cpu_index]++; if (retry[cpu_index] <= 3) { ret = READING_SKIP; return ret; } } else retry[cpu_index] = 0; return ret; } static int pal_get_slot_cfg_id(uint8_t *id) { int val; char path[64] = {0}; sprintf(path, GPIO_VAL, GPIO_SLT_CFG0); if (read_device(path, &val)) { return -1; } *id = val&0x01; sprintf(path, GPIO_VAL, GPIO_SLT_CFG1); if (read_device(path, &val)) { return -1; } *id = *id | (val<<1); return 0; } int pal_read_ava_temp(uint8_t sensor_num, float *value) { int fd = 0; char fn[32]; int ret = READING_NA;; static unsigned int retry[6] = {0}; uint8_t i_retry; uint8_t tcount, rcount, slot_cfg, addr, mux_chan, mux_addr = 0xe2; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}; if (pal_get_slot_cfg_id(&slot_cfg) < 0) slot_cfg = SLOT_CFG_EMPTY; switch(sensor_num) { case MB_SENSOR_C2_AVA_FTEMP: i_retry = 0; break; case MB_SENSOR_C2_AVA_RTEMP: i_retry = 1; break; case MB_SENSOR_C3_AVA_FTEMP: i_retry = 2; break; case MB_SENSOR_C3_AVA_RTEMP: i_retry = 3; break; case MB_SENSOR_C4_AVA_FTEMP: i_retry = 4; break; case MB_SENSOR_C4_AVA_RTEMP: i_retry = 5; break; default: return READING_NA; } switch(sensor_num) { case MB_SENSOR_C2_AVA_FTEMP: case MB_SENSOR_C2_AVA_RTEMP: if(slot_cfg == SLOT_CFG_EMPTY) return READING_NA; mux_chan = 0; break; case MB_SENSOR_C3_AVA_FTEMP: case MB_SENSOR_C3_AVA_RTEMP: if(slot_cfg == SLOT_CFG_EMPTY) return READING_NA; mux_chan = 1; break; case MB_SENSOR_C4_AVA_FTEMP: case MB_SENSOR_C4_AVA_RTEMP: if(slot_cfg != SLOT_CFG_SS_3x8) return READING_NA; mux_chan = 2; break; default: return READING_NA; } switch(sensor_num) { case MB_SENSOR_C2_AVA_FTEMP: case MB_SENSOR_C3_AVA_FTEMP: case MB_SENSOR_C4_AVA_FTEMP: addr = 0x92; break; case MB_SENSOR_C2_AVA_RTEMP: case MB_SENSOR_C3_AVA_RTEMP: case MB_SENSOR_C4_AVA_RTEMP: addr = 0x90; break; default: return READING_NA; } snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID); fd = open(fn, O_RDWR); if (fd < 0) { ret = READING_NA; goto error_exit; } // control multiplexer to target channel. ret = pal_control_mux(fd, mux_addr, mux_chan); if (ret < 0) { ret = READING_NA; goto error_exit; } // Read 2 bytes from TMP75 tbuf[0] = 0x00; tcount = 1; rcount = 2; ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount); if (ret < 0) { ret = READING_NA; goto error_exit; } ret = 0; retry[i_retry] = 0; // rbuf:MSB, LSB; 12-bit value on Bit[15:4], unit: 0.0625 *value = (float)(signed char)rbuf[0]; error_exit: if (fd > 0) { pal_control_mux(fd, mux_addr, 0xff); // close close(fd); } if (ret == READING_NA && ++retry[i_retry] <= 3) ret = READING_SKIP; return ret; } int pal_read_INA230 (uint8_t sensor_num, float *value, int pot) { int fd = 0; char fn[32]; int ret = READING_NA;; static unsigned int retry[12] = {0}; uint8_t i_retry = 0; uint8_t slot_cfg, addr, mux_chan, mux_addr = 0xe2; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}; /*previous_addr - it is used for identifying the slave address. * If the slave address is changed, bus_voltage and shunt_voltage are updated. *Rshunt - it is defined by the schematic. It will be 2m ohm in the fbtp * */ static uint8_t previous_addr = 0; const float Rshunt = 0.002; // 2m ohm static float bus_voltage = 0x0; static float shunt_voltage = 0x0; static float current = 0x0; static float power = 0x0; if (pal_get_slot_cfg_id(&slot_cfg) < 0) slot_cfg = SLOT_CFG_EMPTY; switch(sensor_num) { case MB_SENSOR_C2_P12V_INA230_VOL: i_retry = 0; break; case MB_SENSOR_C2_P12V_INA230_CURR: i_retry = 1; break; case MB_SENSOR_C2_P12V_INA230_PWR: i_retry = 2; break; case MB_SENSOR_C3_P12V_INA230_VOL: i_retry = 3; break; case MB_SENSOR_C3_P12V_INA230_CURR: i_retry = 4; break; case MB_SENSOR_C3_P12V_INA230_PWR: i_retry = 5; break; case MB_SENSOR_C4_P12V_INA230_VOL: i_retry = 6; break; case MB_SENSOR_C4_P12V_INA230_CURR: i_retry = 7; break; case MB_SENSOR_C4_P12V_INA230_PWR: i_retry = 8; break; case MB_SENSOR_CONN_P12V_INA230_VOL: i_retry = 9; break; case MB_SENSOR_CONN_P12V_INA230_CURR: i_retry = 10; break; case MB_SENSOR_CONN_P12V_INA230_PWR: i_retry = 11; break; } switch(sensor_num) { case MB_SENSOR_C2_P12V_INA230_VOL: case MB_SENSOR_C2_P12V_INA230_CURR: case MB_SENSOR_C2_P12V_INA230_PWR: case MB_SENSOR_C3_P12V_INA230_VOL: case MB_SENSOR_C3_P12V_INA230_CURR: case MB_SENSOR_C3_P12V_INA230_PWR: case MB_SENSOR_CONN_P12V_INA230_VOL: case MB_SENSOR_CONN_P12V_INA230_CURR: case MB_SENSOR_CONN_P12V_INA230_PWR: if(slot_cfg == SLOT_CFG_EMPTY) return READING_NA; break; case MB_SENSOR_C4_P12V_INA230_VOL: case MB_SENSOR_C4_P12V_INA230_CURR: case MB_SENSOR_C4_P12V_INA230_PWR: if(slot_cfg != SLOT_CFG_SS_3x8) return READING_NA; break; default: return READING_NA; } //use channel 4 mux_chan = 0x3; snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID); fd = open(fn, O_RDWR); if (fd < 0) { ret = READING_NA; goto error_exit; } //control multiplexer to target channel. ret = pal_control_mux(fd, mux_addr, mux_chan); if (ret < 0) { ret = READING_NA; goto error_exit; } switch(sensor_num) { case MB_SENSOR_C2_P12V_INA230_VOL: case MB_SENSOR_C2_P12V_INA230_CURR: case MB_SENSOR_C2_P12V_INA230_PWR: addr = 0x80; break; case MB_SENSOR_C3_P12V_INA230_VOL: case MB_SENSOR_C3_P12V_INA230_CURR: case MB_SENSOR_C3_P12V_INA230_PWR: addr = 0x82; break; case MB_SENSOR_C4_P12V_INA230_VOL: case MB_SENSOR_C4_P12V_INA230_CURR: case MB_SENSOR_C4_P12V_INA230_PWR: addr = 0x88; break; case MB_SENSOR_CONN_P12V_INA230_VOL: case MB_SENSOR_CONN_P12V_INA230_CURR: case MB_SENSOR_CONN_P12V_INA230_PWR: addr = 0x8A; break; default: syslog(LOG_WARNING, "read_INA230: undefined sensor number") ; break; } //check the previous all INA230 sensors are read and change the addr to the next if ( previous_addr != addr ) { //record the current addr previous_addr = addr; //get the bus voltage tbuf[0] = 0x02; memset(rbuf, 0, sizeof(rbuf)); ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 1, rbuf, 2); if (ret < 0) { ret = READING_NA; goto error_exit; } //transform the value from raw data to the reading bus_voltage = ((rbuf[1] + rbuf[0]*256) * 0.00125); //get the shunt voltage tbuf[0] = 0x01; memset(rbuf, 0, sizeof(rbuf)); ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, 1, rbuf, 2); if (ret < 0) { ret = READING_NA; goto error_exit; } //If shunt voltage is a negative value, set the shunt_voltage to 0 if ( BIT(rbuf[0], 7) ) { shunt_voltage = 0; } else { shunt_voltage = ((rbuf[1] + rbuf[0]*256) * 0.0000025); } //get the current according to the shunt_voltage and Rshunt current = (shunt_voltage / Rshunt); //get the power according to the bus_voltage and current power = current * bus_voltage; } switch(sensor_num) { case MB_SENSOR_C2_P12V_INA230_VOL: case MB_SENSOR_C3_P12V_INA230_VOL: case MB_SENSOR_C4_P12V_INA230_VOL: case MB_SENSOR_CONN_P12V_INA230_VOL: *value = bus_voltage; break; case MB_SENSOR_C2_P12V_INA230_CURR: case MB_SENSOR_C3_P12V_INA230_CURR: case MB_SENSOR_C4_P12V_INA230_CURR: case MB_SENSOR_CONN_P12V_INA230_CURR: *value = current; break; case MB_SENSOR_C2_P12V_INA230_PWR: case MB_SENSOR_C3_P12V_INA230_PWR: case MB_SENSOR_C4_P12V_INA230_PWR: case MB_SENSOR_CONN_P12V_INA230_PWR: *value = power; break; default: syslog(LOG_WARNING, "read_INA230: undefined sensor number") ; break; } ret = 0; retry[i_retry] = 0; error_exit: if (fd > 0) { pal_control_mux(fd, mux_addr, 0xff); // close close(fd); } if (ret == READING_NA && ++retry[i_retry] <= 3) ret = READING_SKIP; return ret; } int pal_read_nvme_temp(uint8_t sensor_num, float *value) { int fd = 0; char fn[32]; int ret = READING_NA; static unsigned int retry[12] = {0}; uint8_t i_retry; uint8_t tcount, rcount, slot_cfg, addr = 0xd4, mux_chan, mux_addr = 0xe2; uint8_t switch_chan, switch_addr=0xe6; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}; if (pal_get_slot_cfg_id(&slot_cfg) < 0) slot_cfg = SLOT_CFG_EMPTY; switch(sensor_num) { case MB_SENSOR_C2_1_NVME_CTEMP: i_retry = 0; break; case MB_SENSOR_C2_2_NVME_CTEMP: i_retry = 1; break; case MB_SENSOR_C2_3_NVME_CTEMP: i_retry = 2; break; case MB_SENSOR_C2_4_NVME_CTEMP: i_retry = 3; break; case MB_SENSOR_C3_1_NVME_CTEMP: i_retry = 4; break; case MB_SENSOR_C3_2_NVME_CTEMP: i_retry = 5; break; case MB_SENSOR_C3_3_NVME_CTEMP: i_retry = 6; break; case MB_SENSOR_C3_4_NVME_CTEMP: i_retry = 7; break; case MB_SENSOR_C4_1_NVME_CTEMP: i_retry = 8; break; case MB_SENSOR_C4_2_NVME_CTEMP: i_retry = 9; break; case MB_SENSOR_C4_3_NVME_CTEMP: i_retry = 10; break; case MB_SENSOR_C4_4_NVME_CTEMP: i_retry = 11; break; default: return READING_NA; } switch(sensor_num) { case MB_SENSOR_C2_1_NVME_CTEMP: case MB_SENSOR_C2_2_NVME_CTEMP: case MB_SENSOR_C2_3_NVME_CTEMP: case MB_SENSOR_C2_4_NVME_CTEMP: if(slot_cfg == SLOT_CFG_EMPTY) return READING_NA; mux_chan = 0; break; case MB_SENSOR_C3_1_NVME_CTEMP: case MB_SENSOR_C3_2_NVME_CTEMP: case MB_SENSOR_C3_3_NVME_CTEMP: case MB_SENSOR_C3_4_NVME_CTEMP: if(slot_cfg == SLOT_CFG_EMPTY) return READING_NA; mux_chan = 1; break; case MB_SENSOR_C4_1_NVME_CTEMP: case MB_SENSOR_C4_2_NVME_CTEMP: case MB_SENSOR_C4_3_NVME_CTEMP: case MB_SENSOR_C4_4_NVME_CTEMP: if(slot_cfg != SLOT_CFG_SS_3x8) return READING_NA; mux_chan = 2; break; default: return READING_NA; } switch(sensor_num) { case MB_SENSOR_C2_1_NVME_CTEMP: case MB_SENSOR_C3_1_NVME_CTEMP: case MB_SENSOR_C4_1_NVME_CTEMP: switch_chan = 0; break; case MB_SENSOR_C2_2_NVME_CTEMP: case MB_SENSOR_C3_2_NVME_CTEMP: case MB_SENSOR_C4_2_NVME_CTEMP: switch_chan = 1; break; case MB_SENSOR_C2_3_NVME_CTEMP: case MB_SENSOR_C3_3_NVME_CTEMP: case MB_SENSOR_C4_3_NVME_CTEMP: switch_chan = 2; break; case MB_SENSOR_C2_4_NVME_CTEMP: case MB_SENSOR_C3_4_NVME_CTEMP: case MB_SENSOR_C4_4_NVME_CTEMP: switch_chan = 3; break; default: return READING_NA; } snprintf(fn, sizeof(fn), "/dev/i2c-%d", RISER_BUS_ID); fd = open(fn, O_RDWR); if (fd < 0) { ret = READING_NA; goto error_exit; } // control I2C multiplexer to target channel. ret = pal_control_mux(fd, mux_addr, mux_chan); if (ret < 0) { ret = READING_NA; goto error_exit; } // control I2C switch to target channel. ret = pal_control_switch(fd, switch_addr, switch_chan); // Report temp of PCIe card on MB_SENSOR_CX_1_NVME_CTEMP senosrs, // no I2C Switch on PCIe Card if (ret < 0 && switch_chan != 0) { ret = READING_NA; goto error_exit; } // Read 8 bytes from NVMe tbuf[0] = 0x00; tcount = 1; rcount = 8; ret = i2c_rdwr_msg_transfer(fd, addr, tbuf, tcount, rbuf, rcount); if (ret < 0) { ret = READING_NA; goto error_exit; } ret = 0; retry[i_retry] = 0; // Cmd 0: length, SFLGS, SMART Warnings, CTemp, PDLU, Reserved, Reserved, PEC *value = (float)(signed char)rbuf[3]; error_exit: if (fd > 0) { pal_control_switch(fd, switch_addr, 0xff); // close pal_control_mux(fd, mux_addr, 0xff); // close close(fd); } if (ret == READING_NA && ++retry[i_retry] <= 3) ret = READING_SKIP; return ret; } static void pal_add_cri_sel(char *str) { char cmd[128]; snprintf(cmd, 128, "logger -p local0.err \"%s\"",str); system(cmd); } static void add_CPLD_event (uint8_t fru, uint8_t snr_num, uint8_t reg, uint8_t snr_val, uint8_t value) { char sensor_name[32] = {0}, event_str[30] = {0}; pal_get_sensor_name(fru, snr_num, sensor_name); strcpy(event_str, ""); switch(reg) { case PWRDATA1_REG : if (value == 0x40) strcat(event_str, "FM_CTNR_PS_ON power rail fails"); else if (value == 0x00) strcat(event_str, "PWRGD_P12V_MAIN power rail fails"); else if (value == 0xc0) strcat(event_str, "PWRGD_P5V power rail fails"); else if (value == 0xe0) strcat(event_str, "PWRGD_P3V3 power rail fails"); else if (value == 0xf7) strcat(event_str, "PWRGD_PVPP_ABC power rail fails"); else if (value == 0xfb) strcat(event_str, "PWRGD_PVPP_DEF power rail fails"); else if (value == 0xfd) strcat(event_str, "PWRGD_PVPP_GHJ power rail fails"); else if (value == 0xfe) strcat(event_str, "PWRGD_PVPP_KLM power rail fails"); else strcat(event_str, "Unknown power rail fails(PWRDATA1)"); break; case PWRDATA2_REG : if (value == 0x55) strcat(event_str, "PWRGD_PVTT_CPU0 power rail fails"); else if (value == 0xaa) strcat(event_str, "PWRGD_PVTT_CPU1 power rail fails"); else if (value == 0xd5) strcat(event_str, "PWRGD_PVCCIO_CPU0 power rail fails"); else if (value == 0xea) strcat(event_str, "PWRGD_PVCCIO_CPU1 power rail fails"); else if (value == 0xf7) strcat(event_str, "PWRGD_PVCCIN_CPU0 power rail fails"); else if (value == 0xfb) strcat(event_str, "PWRGD_PVCCIN_CPU1 power rail fails"); else if (value == 0xfd) strcat(event_str, "PWRGD_PVSA_CPU0 power rail fails"); else if (value == 0xfe) strcat(event_str, "PWRGD_PVSA_CPU1 power rail fails"); else strcat(event_str, "Unknown power rail fails(PWRDATA2)"); break; case PWRDATA3_REG : if (value == 0x40) strcat(event_str, "PWRGD_CPUPWRGD power rail fails"); else if (value == 0x80) strcat(event_str, "RST_PLTRST_N power rail fails"); else strcat(event_str, "Unknown power rail fails(PWRDATA3)"); break; } if(power_fail_log == 0){ _print_sensor_discrete_log(fru, snr_num, sensor_name, reg, event_str); pal_add_cri_sel(event_str); power_fail_log = 1; } } int pal_read_CPLD_power_fail_sts (uint8_t fru, uint8_t sensor_num, float *value, int pot) { int fd = 0; char fn[32]; int ret = READING_NA, i; static unsigned int retry=0; static uint8_t power_fail = 0; uint8_t tbuf[16] = {0}; uint8_t rbuf[16] = {0}, data_chk; uint8_t sensor_value; int val; char path[64] = {0}; //Check SLPS4 is high before start monitor CPLD power fail sprintf(path, GPIO_VAL, GPIO_FM_SLPS4_N); if (read_device(path, &val)) { goto error_exit; } if (val == 0x0) { power_fail = 0; goto error_exit; } snprintf(fn, sizeof(fn), "/dev/i2c-%d", CPLD_BUS_ID); fd = open(fn, O_RDWR); if (fd < 0) { goto error_exit; } for(i=0;i<3;i++) { switch(i) { case MAIN_PWR_STS_REG : data_chk = MAIN_PWR_STS_VAL; break; case CPU0_PWR_STS_REG : data_chk = CPU0_PWR_STS_VAL; break; case CPU1_PWR_STS_REG : data_chk = CPU1_PWR_STS_VAL; break; } tbuf[0] = i; ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDR, tbuf, 1, rbuf, 1); if (ret < 0) { ret = READING_NA; goto error_exit; } if ( rbuf[0] != data_chk ) { power_fail++; break; } } if(power_fail <= 3) { ret = 0; *value = 0; power_fail_log = 0; } else { for(i=3;i<6;i++) { switch(i) { case PWRDATA1_REG : data_chk = PWRDATA1_VAL; break; case PWRDATA2_REG : data_chk = PWRDATA2_VAL; break; case PWRDATA3_REG : data_chk = PWRDATA3_VAL; break; } // Read 1 byte in offset 00h tbuf[0] = i; ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDR, tbuf, 1, rbuf, 1); if (ret < 0) { ret = READING_NA; goto error_exit; } if ( (rbuf[0] != data_chk) && (power_fail > 3)) { sensor_value = 0x01<<i; *value = sensor_value; add_CPLD_event(fru, sensor_num, i , sensor_value, rbuf[0]); break; } } } error_exit: if (fd > 0) { close(fd); } if ((ret == READING_NA) && (retry < MAX_READ_RETRY)){ ret = READING_SKIP; retry++; } else { retry = 0; } return ret; } static int pal_key_index(char *key) { int i; i = 0; while(strcmp(key_cfg[i].name, LAST_KEY)) { // If Key is valid, return success if (!strcmp(key, key_cfg[i].name)) return i; i++; } #ifdef DEBUG syslog(LOG_WARNING, "pal_key_index: invalid key - %s", key); #endif return -1; } int pal_set_key_value(char *key, char *value) { int index, ret; // Check is key is defined and valid if ((index = pal_key_index(key)) < 0) return -1; if (key_cfg[index].function) { ret = key_cfg[index].function(KEY_BEFORE_SET, value); if (ret < 0) return ret; } return kv_set(key, value, 0, KV_FPERSIST); } static int key_func_por_policy (int event, void *arg) { char cmd[MAX_VALUE_LEN]; char value[MAX_VALUE_LEN]; switch (event) { case KEY_BEFORE_SET: if (pal_is_fw_update_ongoing(FRU_MB)) return -1; // sync to env snprintf(cmd, MAX_VALUE_LEN, "/sbin/fw_setenv por_policy %s", (char *)arg); system(cmd); break; case KEY_AFTER_INI: // sync to env kv_get("server_por_cfg", value, NULL, KV_FPERSIST); snprintf(cmd, MAX_VALUE_LEN, "/sbin/fw_setenv por_policy %s", value); system(cmd); break; } return 0; } static int key_func_lps (int event, void *arg) { char cmd[MAX_VALUE_LEN]; char value[MAX_VALUE_LEN]; switch (event) { case KEY_BEFORE_SET: if (pal_is_fw_update_ongoing(FRU_MB)) return -1; snprintf(cmd, MAX_VALUE_LEN, "/sbin/fw_setenv por_ls %s", (char *)arg); system(cmd); break; case KEY_AFTER_INI: kv_get("pwr_server_last_state", value, NULL, KV_FPERSIST); snprintf(cmd, MAX_VALUE_LEN, "/sbin/fw_setenv por_ls %s", value); system(cmd); break; } return 0; } static int key_func_tz (int event, void *arg) { char cmd[MAX_VALUE_LEN]; char timezone[MAX_VALUE_LEN]; char path[MAX_VALUE_LEN]; switch (event) { case KEY_BEFORE_SET: snprintf(timezone, MAX_VALUE_LEN, "%s", (char *)arg); snprintf(path, MAX_VALUE_LEN, "/usr/share/zoneinfo/%s", (char *)arg); if( access(path, F_OK) != -1 ) { snprintf(cmd, MAX_VALUE_LEN, "echo %s > /etc/timezone", timezone); system(cmd); snprintf(cmd, MAX_VALUE_LEN, "ln -fs %s /etc/localtime", path); system(cmd); } else { return -1; } break; case KEY_AFTER_INI: break; } return 0; } int pal_get_server_power(uint8_t fru, uint8_t *status) { int val; char path[64] = {0}; sprintf(path, GPIO_VAL, GPIO_POWER_GOOD); if (read_device(path, &val)) { return -1; } if (val == 0x0) { *status = 0; } else { *status = 1; } return 0; } static bool is_server_off(void) { int ret; uint8_t status; ret = pal_get_server_power(FRU_MB, &status); if (ret) { return false; } if (status == SERVER_POWER_OFF) { return true; } else { return false; } } int pal_check_postcodes(uint8_t fru_id, uint8_t sensor_num, float *value) { static int log_asserted = 0; const int loop_threshold = 3; const int longest_loop_code = 4; int i, nearest_00, loop_count, check_until; size_t len; uint8_t buff[256]; uint8_t location, maj_err, min_err, mem_train_fail; int ret = READING_NA, rc; static unsigned int retry=0; char sensor_name[32] = {0}; char str[32] = {0}; if (fru_id != 1) { syslog(LOG_ERR, "Not Supported Operation for fru %d", fru_id); goto error_exit; } if (is_server_off()) { log_asserted = 0; goto error_exit; } len = 0; // clear higher bits rc = pal_get_80port_record(FRU_MB, buff, sizeof(buff), &len); if (rc != PAL_EOK) goto error_exit; mem_train_fail = 0; loop_count = 0; check_until = len - (longest_loop_code * (loop_threshold+1) ); // Check post code from tail for(i = len - 1; i >= 0 && i >= check_until; i--) { if (buff[i] == 0x00) { if (loop_count < loop_threshold) { // found 00 loop_count++; nearest_00 = i; continue; } else { // found (loop_threshold+1)-th 00 from tail if (!memcmp(&buff[i], &buff[nearest_00], len - nearest_00)) { // PostCode looping over loop_threshold times if ((nearest_00 - i) == 4) { // Loop Convention1 mem_train_fail = 1; location = buff[i+1]; maj_err = buff[i+2]; min_err = buff[i+3]; } if ((nearest_00 - i) == 3) { // Loop Convention2 mem_train_fail = 1; location = 0x00; maj_err = buff[i+1]; min_err = buff[i+2]; } } // break after 2nd 00 break; } } } if (mem_train_fail) { if (!log_asserted) { pal_get_sensor_name(fru_id, sensor_num, sensor_name); if (location) { snprintf(str, sizeof(str), "Location:%02X Err:%02X %02X",location, maj_err, min_err); _print_sensor_discrete_log(fru_id, sensor_num, sensor_name, 0x01, str); snprintf(str, sizeof(str), "DIMM %02X initial fails",location); pal_add_cri_sel(str); //syslog(LOG_CRIT, "Memory training failure at %02X MajErr:%02X, MinErr:%02X", location, maj_err, min_err); } else { snprintf(str, sizeof(str), "Location Unknown Err:%02X %02X", maj_err, min_err); _print_sensor_discrete_log(fru_id, sensor_num, sensor_name, 0x01, str); //syslog(LOG_CRIT, "Memory training failure MajErr:%02X, MinErr:%02X", maj_err, min_err); snprintf(str, sizeof(str), "DIMM XX initial fails"); pal_add_cri_sel(str); } } log_asserted = 1; } else { log_asserted = 0; } *value = (float)log_asserted; ret = 0; error_exit: if ((ret == READING_NA) && (retry < MAX_READ_RETRY)){ ret = READING_SKIP; retry++; } else { retry = 0; } return ret; } int pal_check_frb3(uint8_t fru_id, uint8_t sensor_num, float *value) { static unsigned int retry = 0; static uint8_t frb3_fail = 0x10; // bit 4: FRB3 failure static time_t rst_time = 0; static uint8_t postcodes_last[256] = {0}; uint8_t postcodes[256] = {0}; struct stat file_stat; int ret = READING_NA, rc, len; char sensor_name[32] = {0}; char error[32] = {0}; if (fru_id != 1) { syslog(LOG_ERR, "Not Supported Operation for fru %d", fru_id); return READING_NA; } if (stat("/tmp/rst_touch", &file_stat) == 0 && file_stat.st_mtime > rst_time) { rst_time = file_stat.st_mtime; // assume fail till we know it is not frb3_fail = 0x10; // bit 4: FRB3 failure retry = 0; // cache current postcode buffer memset(postcodes_last, 0, sizeof(postcodes_last)); pal_get_80port_record(FRU_MB, postcodes_last, sizeof(postcodes_last), &len); } if (frb3_fail) { // KCS transaction if (stat("/tmp/kcs_touch", &file_stat) == 0 && file_stat.st_mtime > rst_time) frb3_fail = 0; // Port 80 updated memset(postcodes, 0, sizeof(postcodes_last)); rc = pal_get_80port_record(FRU_MB, postcodes, sizeof(postcodes), &len); if (rc == PAL_EOK && memcmp(postcodes_last, postcodes, 256) != 0) { frb3_fail = 0; } // BIOS POST COMPLT, in case BMC reboot when system idle in OS if (gpio_get(GPIO_FM_BIOS_POST_CMPLT_N) == GPIO_VALUE_LOW) frb3_fail = 0; } if (frb3_fail) retry++; else retry = 0; if (retry == MAX_READ_RETRY) { pal_get_sensor_name(fru_id, sensor_num, sensor_name); snprintf(error, sizeof(error), "FRB3 failure"); _print_sensor_discrete_log(fru_id, sensor_num, sensor_name, frb3_fail, error); } *value = (float)frb3_fail; ret = 0; return ret; } int pal_get_sensor_name(uint8_t fru, uint8_t sensor_num, char *name) { switch(fru) { case FRU_MB: switch(sensor_num) { case MB_SENSOR_INLET_TEMP: sprintf(name, "MB_INLET_TEMP"); break; case MB_SENSOR_OUTLET_TEMP: sprintf(name, "MB_OUTLET_TEMP"); break; case MB_SENSOR_INLET_REMOTE_TEMP: sprintf(name, "MB_INLET_REMOTE_TEMP"); break; case MB_SENSOR_OUTLET_REMOTE_TEMP: sprintf(name, "MB_OUTLET_REMOTE_TEMP"); break; case MB_SENSOR_FAN0_TACH: sprintf(name, "MB_FAN0_TACH"); break; case MB_SENSOR_FAN1_TACH: sprintf(name, "MB_FAN1_TACH"); break; case MB_SENSOR_P3V3: sprintf(name, "MB_P3V3"); break; case MB_SENSOR_P5V: sprintf(name, "MB_P5V"); break; case MB_SENSOR_P12V: sprintf(name, "MB_P12V"); break; case MB_SENSOR_P1V05: sprintf(name, "MB_P1V05"); break; case MB_SENSOR_PVNN_PCH_STBY: sprintf(name, "MB_PVNN_PCH_STBY"); break; case MB_SENSOR_P3V3_STBY: sprintf(name, "MB_P3V3_STBY"); break; case MB_SENSOR_P5V_STBY: sprintf(name, "MB_P5V_STBY"); break; case MB_SENSOR_P3V_BAT: sprintf(name, "MB_P3V_BAT"); break; case MB_SENSOR_HSC_IN_VOLT: sprintf(name, "MB_HSC_IN_VOLT"); break; case MB_SENSOR_HSC_OUT_CURR: sprintf(name, "MB_HSC_OUT_CURR"); break; case MB_SENSOR_HSC_IN_POWER: sprintf(name, "MB_HSC_IN_POWER"); break; case MB_SENSOR_CPU0_TEMP: sprintf(name, "MB_CPU0_TEMP"); break; case MB_SENSOR_CPU0_TJMAX: sprintf(name, "MB_CPU0_TJMAX"); break; case MB_SENSOR_CPU0_PKG_POWER: sprintf(name, "MB_CPU0_PKG_POWER"); break; case MB_SENSOR_CPU1_TEMP: sprintf(name, "MB_CPU1_TEMP"); break; case MB_SENSOR_CPU1_TJMAX: sprintf(name, "MB_CPU1_TJMAX"); break; case MB_SENSOR_CPU1_PKG_POWER: sprintf(name, "MB_CPU1_PKG_POWER"); break; case MB_SENSOR_PCH_TEMP: sprintf(name, "MB_PCH_TEMP"); break; case MB_SENSOR_CPU0_DIMM_GRPA_TEMP: sprintf(name, "MB_CPU0_DIMM_GRPA_TEMP"); break; case MB_SENSOR_CPU0_DIMM_GRPB_TEMP: sprintf(name, "MB_CPU0_DIMM_GRPB_TEMP"); break; case MB_SENSOR_CPU1_DIMM_GRPC_TEMP: sprintf(name, "MB_CPU1_DIMM_GRPC_TEMP"); break; case MB_SENSOR_CPU1_DIMM_GRPD_TEMP: sprintf(name, "MB_CPU1_DIMM_GRPD_TEMP"); break; case MB_SENSOR_VR_CPU0_VCCIN_TEMP: sprintf(name, "MB_VR_CPU0_VCCIN_TEMP"); break; case MB_SENSOR_VR_CPU0_VCCIN_CURR: sprintf(name, "MB_VR_CPU0_VCCIN_CURR"); break; case MB_SENSOR_VR_CPU0_VCCIN_VOLT: sprintf(name, "MB_VR_CPU0_VCCIN_VOLT"); break; case MB_SENSOR_VR_CPU0_VCCIN_POWER: sprintf(name, "MB_VR_CPU0_VCCIN_POWER"); break; case MB_SENSOR_VR_CPU0_VSA_TEMP: sprintf(name, "MB_VR_CPU0_VSA_TEMP"); break; case MB_SENSOR_VR_CPU0_VSA_CURR: sprintf(name, "MB_VR_CPU0_VSA_CURR"); break; case MB_SENSOR_VR_CPU0_VSA_VOLT: sprintf(name, "MB_VR_CPU0_VSA_VOLT"); break; case MB_SENSOR_VR_CPU0_VSA_POWER: sprintf(name, "MB_VR_CPU0_VSA_POWER"); break; case MB_SENSOR_VR_CPU0_VCCIO_TEMP: sprintf(name, "MB_VR_CPU0_VCCIO_TEMP"); break; case MB_SENSOR_VR_CPU0_VCCIO_CURR: sprintf(name, "MB_VR_CPU0_VCCIO_CURR"); break; case MB_SENSOR_VR_CPU0_VCCIO_VOLT: sprintf(name, "MB_VR_CPU0_VCCIO_VOLT"); break; case MB_SENSOR_VR_CPU0_VCCIO_POWER: sprintf(name, "MB_VR_CPU0_VCCIO_POWER"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPA_TEMP: sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_TEMP"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPA_CURR: sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_CURR"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPA_VOLT: sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_VOLT"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPA_POWER: sprintf(name, "MB_VR_CPU0_VDDQ_GRPA_POWER"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPB_TEMP: sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_TEMP"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPB_CURR: sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_CURR"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPB_VOLT: sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_VOLT"); break; case MB_SENSOR_VR_CPU0_VDDQ_GRPB_POWER: sprintf(name, "MB_VR_CPU0_VDDQ_GRPB_POWER"); break; case MB_SENSOR_VR_CPU1_VCCIN_TEMP: sprintf(name, "MB_VR_CPU1_VCCIN_TEMP"); break; case MB_SENSOR_VR_CPU1_VCCIN_CURR: sprintf(name, "MB_VR_CPU1_VCCIN_CURR"); break; case MB_SENSOR_VR_CPU1_VCCIN_VOLT: sprintf(name, "MB_VR_CPU1_VCCIN_VOLT"); break; case MB_SENSOR_VR_CPU1_VCCIN_POWER: sprintf(name, "MB_VR_CPU1_VCCIN_POWER"); break; case MB_SENSOR_VR_CPU1_VSA_TEMP: sprintf(name, "MB_VR_CPU1_VSA_TEMP"); break; case MB_SENSOR_VR_CPU1_VSA_CURR: sprintf(name, "MB_VR_CPU1_VSA_CURR"); break; case MB_SENSOR_VR_CPU1_VSA_VOLT: sprintf(name, "MB_VR_CPU1_VSA_VOLT"); break; case MB_SENSOR_VR_CPU1_VSA_POWER: sprintf(name, "MB_VR_CPU1_VSA_POWER"); break; case MB_SENSOR_VR_CPU1_VCCIO_TEMP: sprintf(name, "MB_VR_CPU1_VCCIO_TEMP"); break; case MB_SENSOR_VR_CPU1_VCCIO_CURR: sprintf(name, "MB_VR_CPU1_VCCIO_CURR"); break; case MB_SENSOR_VR_CPU1_VCCIO_VOLT: sprintf(name, "MB_VR_CPU1_VCCIO_VOLT"); break; case MB_SENSOR_VR_CPU1_VCCIO_POWER: sprintf(name, "MB_VR_CPU1_VCCIO_POWER"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPC_TEMP: sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_TEMP"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPC_CURR: sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_CURR"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPC_VOLT: sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_VOLT"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPC_POWER: sprintf(name, "MB_VR_CPU1_VDDQ_GRPC_POWER"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPD_TEMP: sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_TEMP"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPD_CURR: sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_CURR"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPD_VOLT: sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_VOLT"); break; case MB_SENSOR_VR_CPU1_VDDQ_GRPD_POWER: sprintf(name, "MB_VR_CPU1_VDDQ_GRPD_POWER"); break; case MB_SENSOR_VR_PCH_PVNN_TEMP: sprintf(name, "MB_VR_PCH_PVNN_TEMP"); break; case MB_SENSOR_VR_PCH_PVNN_CURR: sprintf(name, "MB_VR_PCH_PVNN_CURR"); break; case MB_SENSOR_VR_PCH_PVNN_VOLT: sprintf(name, "MB_VR_PCH_PVNN_VOLT"); break; case MB_SENSOR_VR_PCH_PVNN_POWER: sprintf(name, "MB_VR_PCH_PVNN_POWER"); break; case MB_SENSOR_VR_PCH_P1V05_TEMP: sprintf(name, "MB_VR_PCH_P1V05_TEMP"); break; case MB_SENSOR_VR_PCH_P1V05_CURR: sprintf(name, "MB_VR_PCH_P1V05_CURR"); break; case MB_SENSOR_VR_PCH_P1V05_VOLT: sprintf(name, "MB_VR_PCH_P1V05_VOLT"); break; case MB_SENSOR_VR_PCH_P1V05_POWER: sprintf(name, "MB_VR_PCH_P1V05_POWER"); break; case MB_SENSOR_C2_AVA_FTEMP: sprintf(name, "MB_C2_AVA_FTEMP"); break; case MB_SENSOR_C2_AVA_RTEMP: sprintf(name, "MB_C2_AVA_RTEMP"); break; case MB_SENSOR_C2_1_NVME_CTEMP: sprintf(name, "MB_C2_0_NVME_CTEMP"); break; case MB_SENSOR_C2_2_NVME_CTEMP: sprintf(name, "MB_C2_1_NVME_CTEMP"); break; case MB_SENSOR_C2_3_NVME_CTEMP: sprintf(name, "MB_C2_2_NVME_CTEMP"); break; case MB_SENSOR_C2_4_NVME_CTEMP: sprintf(name, "MB_C2_3_NVME_CTEMP"); break; case MB_SENSOR_C3_AVA_FTEMP: sprintf(name, "MB_C3_AVA_FTEMP"); break; case MB_SENSOR_C3_AVA_RTEMP: sprintf(name, "MB_C3_AVA_RTEMP"); break; case MB_SENSOR_C3_1_NVME_CTEMP: sprintf(name, "MB_C3_0_NVME_CTEMP"); break; case MB_SENSOR_C3_2_NVME_CTEMP: sprintf(name, "MB_C3_1_NVME_CTEMP"); break; case MB_SENSOR_C3_3_NVME_CTEMP: sprintf(name, "MB_C3_2_NVME_CTEMP"); break; case MB_SENSOR_C3_4_NVME_CTEMP: sprintf(name, "MB_C3_3_NVME_CTEMP"); break; case MB_SENSOR_C4_AVA_FTEMP: sprintf(name, "MB_C4_AVA_FTEMP"); break; case MB_SENSOR_C4_AVA_RTEMP: sprintf(name, "MB_C4_AVA_RTEMP"); break; case MB_SENSOR_C4_1_NVME_CTEMP: sprintf(name, "MB_C4_0_NVME_CTEMP"); break; case MB_SENSOR_C4_2_NVME_CTEMP: sprintf(name, "MB_C4_1_NVME_CTEMP"); break; case MB_SENSOR_C4_3_NVME_CTEMP: sprintf(name, "MB_C4_2_NVME_CTEMP"); break; case MB_SENSOR_C4_4_NVME_CTEMP: sprintf(name, "MB_C4_3_NVME_CTEMP"); break; case MB_SENSOR_C2_P12V_INA230_VOL: sprintf(name, "MB_C2_P12V_INA230_VOL"); break; case MB_SENSOR_C2_P12V_INA230_CURR: sprintf(name, "MB_C2_P12V_INA230_CURR"); break; case MB_SENSOR_C2_P12V_INA230_PWR: sprintf(name, "MB_C2_P12V_INA230_PWR"); break; case MB_SENSOR_C3_P12V_INA230_VOL: sprintf(name, "MB_C3_P12V_INA230_VOL"); break; case MB_SENSOR_C3_P12V_INA230_CURR: sprintf(name, "MB_C3_P12V_INA230_CURR"); break; case MB_SENSOR_C3_P12V_INA230_PWR: sprintf(name, "MB_C3_P12V_INA230_PWR"); break; case MB_SENSOR_C4_P12V_INA230_VOL: sprintf(name, "MB_C4_P12V_INA230_VOL"); break; case MB_SENSOR_C4_P12V_INA230_CURR: sprintf(name, "MB_C4_P12V_INA230_CURR"); break; case MB_SENSOR_C4_P12V_INA230_PWR: sprintf(name, "MB_C4_P12V_INA230_PWR"); break; case MB_SENSOR_CONN_P12V_INA230_VOL: sprintf(name, "MB_CONN_P12V_INA230_VOL"); break; case MB_SENSOR_CONN_P12V_INA230_CURR: sprintf(name, "MB_CONN_P12V_INA230_CURR"); break; case MB_SENSOR_CONN_P12V_INA230_PWR: sprintf(name, "MB_CONN_P12V_INA230_PWR"); break; case MB_SENSOR_POWER_FAIL: sprintf(name, "MB_POWER_FAIL"); break; case MB_SENSOR_MEMORY_LOOP_FAIL: sprintf(name, "MB_MEMORY_LOOP_FAIL"); break; case MB_SENSOR_PROCESSOR_FAIL: sprintf(name, "MB_PROCESSOR_FAIL"); break; default: return -1; } break; case FRU_NIC: switch(sensor_num) { case MEZZ_SENSOR_TEMP: sprintf(name, "MEZZ_SENSOR_TEMP"); break; default: return -1; } break; default: return -1; } return 0; } static void _print_sensor_discrete_log(uint8_t fru, uint8_t snr_num, char *snr_name, uint8_t val, char *event) { if (val) { syslog(LOG_CRIT, "ASSERT: %s discrete - raised - FRU: %d, num: 0x%X," " snr: %-16s val: 0x%X", event, fru, snr_num, snr_name, val); } else { syslog(LOG_CRIT, "DEASSERT: %s discrete - settled - FRU: %d, num: 0x%X," " snr: %-16s val: 0x%X", event, fru, snr_num, snr_name, val); } pal_update_ts_sled(); } // Helper function for msleep void msleep(int msec) { struct timespec req; req.tv_sec = 0; req.tv_nsec = msec * 1000 * 1000; while(nanosleep(&req, &req) == -1 && errno == EINTR) { continue; } } void pal_update_ts_sled() { char key[MAX_KEY_LEN] = {0}; char tstr[MAX_VALUE_LEN] = {0}; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); sprintf(tstr, "%ld", ts.tv_sec); sprintf(key, "timestamp_sled"); pal_set_key_value(key, tstr); } int pal_get_pwm_value(uint8_t fan_num, uint8_t *value) { char path[LARGEST_DEVICE_NAME] = {0}; char device_name[LARGEST_DEVICE_NAME] = {0}; int val = 0; int pwm_enable = 0; if (fan_num < 0 || fan_num >= pal_pwm_cnt) { syslog(LOG_INFO, "pal_get_pwm_value: fan number is invalid - %d", fan_num); return -1; } // Need check pwmX_en to determine the PWM is 0 or 100. snprintf(device_name, LARGEST_DEVICE_NAME, "pwm%d_en", fan_num); snprintf(path, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name); if (read_device(path, &pwm_enable)) { syslog(LOG_INFO, "pal_get_pwm_value: read %s failed", path); return -1; } if(pwm_enable) { snprintf(device_name, LARGEST_DEVICE_NAME, "pwm%d_falling", fan_num); snprintf(path, LARGEST_DEVICE_NAME, "%s/%s", PWM_DIR, device_name); if (read_device_hex(path, &val)) { syslog(LOG_INFO, "pal_get_pwm_value: read %s failed", path); return -1; } if(val == 0) *value = 100; else *value = (100 * val + (PWM_UNIT_MAX-1)) / PWM_UNIT_MAX; } else { *value = 0; } return 0; } bool pal_is_cpu1_socket_occupy(void) { char path[64] = {0}; int val; sprintf(path, GPIO_VAL, GPIO_FM_CPU1_SKTOCC_LVT3_N); if (read_device(path, &val)) { return false; } if (val) { return false; } else { return true; } }