meta-facebook/meta-fbtp/recipes-fbtp/gpiod/files/gpiod.c (602 lines of code) (raw):
/*
* sensord
*
* Copyright 2015-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 <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <pthread.h>
#include <assert.h>
#include <sys/un.h>
#include <sys/file.h>
#include <openbmc/pal.h>
#include <openbmc/libgpio.h>
#include <openbmc/mcu.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#define POWER_ON_STR "on"
#define POWER_OFF_STR "off"
//#define SMI_DEBUG
#define TOUCH(path) \
{\
int fd = creat(path, 0644);\
if (fd) close(fd);\
}
extern int usleep(useconds_t usec);
extern void daemon(int, int);
#define POLL_TIMEOUT -1 /* Forever */
static uint8_t CATERR_irq = 0;
static uint8_t MSMI_irq = 0;
static long int reset_sec = 0, power_on_sec = 0;
static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
static bool MCERR_IERR_assert = false;
static int g_uart_switch_count = 0;
static void set_fault_led(bool on)
{
static gpio_desc_t *gpio = NULL;
if (!gpio) {
gpio = gpio_open_by_shadow("BMC_FAULT_N"); // GPIOU5
if (!gpio)
return;
}
gpio_set_value(gpio, on ? GPIO_VALUE_LOW : GPIO_VALUE_HIGH);
}
static void trigger_ppin(void)
{
static bool is_ppin_triggered = false;
static gpio_desc_t *gpio = NULL;
if (!gpio) {
gpio = gpio_open_by_shadow("BMC_PPIN"); // GPIOB5
if (!gpio)
return;
}
if( !is_ppin_triggered )
{
gpio_set_value(gpio, GPIO_VALUE_LOW);
usleep(1000);
gpio_set_value(gpio, GPIO_VALUE_HIGH);
is_ppin_triggered = true;
}
}
static inline long int reset_timer(long int *val) {
pthread_mutex_lock(&timer_mutex);
*val = 0;
pthread_mutex_unlock(&timer_mutex);
return *val;
}
static inline long int increase_timer(long int *val) {
pthread_mutex_lock(&timer_mutex);
(*val)++;
pthread_mutex_unlock(&timer_mutex);
return *val;
}
static inline long int decrease_timer(long int *val) {
pthread_mutex_lock(&timer_mutex);
(*val)--;
pthread_mutex_unlock(&timer_mutex);
return *val;
}
struct delayed_log {
useconds_t usec;
char msg[1024];
};
// Thread for delay event
static void *
delay_log(void *arg)
{
struct delayed_log* log = (struct delayed_log*)arg;
pthread_detach(pthread_self());
if (arg) {
usleep(log->usec);
syslog(LOG_CRIT, "%s", log->msg);
free(arg);
}
pthread_exit(NULL);
}
static void log_gpio_change(gpiopoll_pin_t *gp, gpio_value_t value, useconds_t log_delay)
{
const struct gpiopoll_config *cfg = gpio_poll_get_config(gp);
assert(cfg);
if (log_delay == 0) {
syslog(LOG_CRIT, "%s: %s - %s\n", value ? "DEASSERT": "ASSERT", cfg->description, cfg->shadow);
} else {
pthread_t tid_delay_log;
struct delayed_log *log = (struct delayed_log *)malloc(sizeof(struct delayed_log));
if (log) {
log->usec = log_delay;
snprintf(log->msg, 1024, "%s: %s - %s\n", value ? "DEASSERT" : "ASSERT", cfg->description, cfg->shadow);
if (pthread_create(&tid_delay_log, NULL, delay_log, (void *)log)) {
free(log);
log = NULL;
}
}
if (!log) {
syslog(LOG_CRIT, "%s: %s - %s\n", value ? "DEASSERT": "ASSERT", cfg->description, cfg->shadow);
}
}
}
// On some board versions, we need to reset the IO expander
// as a software workaround for issues in the CPLD.
static void usb_debug_card_check_hotfix(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t value)
{
static uint8_t odm_id = 0xff;
static uint8_t board_rev = 0xff;
if (odm_id == 0xff) {
pal_get_platform_id(&odm_id);
odm_id = odm_id & 0x1;
}
if (board_rev == 0xff) {
pal_get_board_rev_id(&board_rev);
}
if (odm_id == 0 && board_rev <= BOARD_REV_DVT) {
if (value == GPIO_VALUE_HIGH)
usb_dbg_reset_ioexp(9, 0x4E);
}
log_gpio_change(desc, value, 0);
}
// Event Handler for GPIOR5 platform reset changes
static void platform_reset_event_handle(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
// Use GPIOR5 to filter some gpio logging
reset_timer(&reset_sec);
TOUCH("/tmp/rst_touch");
log_gpio_change(gp, curr, 0);
if (MCERR_IERR_assert == true) {
pal_second_crashdump_chk();
MCERR_IERR_assert = false;
}
}
static void cpu0_thermtrip(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
if (curr == GPIO_VALUE_HIGH) {
pal_add_cri_sel("CPU0 thermtrip DEASSERT");
} else {
pal_add_cri_sel("CPU0 thermtrip ASSERT");
}
log_gpio_change(desc, curr, 0);
}
static void cpu1_thermtrip(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
if (curr == GPIO_VALUE_HIGH) {
pal_add_cri_sel("CPU1 thermtrip DEASSERT");
} else {
pal_add_cri_sel("CPU1 thermtrip ASSERT");
}
log_gpio_change(desc, curr, 0);
}
static void irq_uv_detect(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
log_gpio_change(gp, curr, 20*1000);
}
static void power_ok(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
reset_timer(&power_on_sec);
log_gpio_change(gp, curr, 0);
}
static void slps4(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
pal_check_power_sts();
}
//FM_UARTSW_MSB_N, FM_UARTSW_LSB_N
static void uart_switch(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
g_uart_switch_count = 2;
pal_uart_switch_for_led_ctrl();
}
static void pwr_on_push_button(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
pal_set_restart_cause(FRU_MB, RESTART_CAUSE_PWR_ON_PUSH_BUTTON);
log_gpio_change(gp, curr, 0);
}
static void pwr_on_reset(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
pal_set_restart_cause(FRU_MB, RESTART_CAUSE_RESET_PUSH_BUTTON);
log_gpio_change(desc, curr, 0);
}
// Generic Event Handler for GPIO changes
static void gpio_event_handle(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
log_gpio_change(gp, curr, 0);
}
static void
*smi_timer()
{
int smi_timeout_count = 1;
int smi_timeout_threshold = 90;
bool is_issue_event = false;
gpio_desc_t *gpio = gpio_open_by_shadow("FM_BIOS_SMI_ACTIVE_N"); // GPIOG7
gpio_value_t value;
if (!gpio) {
syslog(LOG_CRIT, "SMI PIN monitoring not functional");
return NULL;
}
#ifdef SMI_DEBUG
syslog(LOG_WARNING, "[%s][%lu] Timer is started.\n", __func__, pthread_self());
syslog(LOG_WARNING, "[%s] Get GPIO Num: %d", __func__, pin_num);
#endif
while(1)
{
if (gpio_get_value(gpio, &value)) {
syslog(LOG_WARNING, "Could not get current SMI GPIO value");
sleep(1);
continue;
}
if ( GPIO_VALUE_LOW == value)
{
smi_timeout_count++;
}
else if ( GPIO_VALUE_HIGH == value)
{
smi_timeout_count = 0;
}
#ifdef SMI_DEBUG
syslog(LOG_WARNING, "[%s][%lu] smi_timeout_count[%d] == smi_timeout_threshold[%d]\n", __func__, pthread_self(), smi_timeout_count, smi_timeout_threshold);
#endif
if ( smi_timeout_count == smi_timeout_threshold )
{
syslog(LOG_CRIT, "ASSERT: GPIOG7-FM_BIOS_SMI_ACTIVE_N\n");
is_issue_event = true;
}
else if ( (true == is_issue_event) && (0 == smi_timeout_count) )
{
syslog(LOG_CRIT, "DEASSERT: GPIOG7-FM_BIOS_SMI_ACTIVE_N\n");
is_issue_event = false;
}
//sleep periodically.
sleep(1);
#ifdef SMI_DEBUG
syslog(LOG_WARNING, "[%s][%lu] count=%d\n", __func__, pthread_self(), smi_timeout_count);
#endif
}
return NULL;
}
#define SERVER_POWER_CHECK(power_on_time) \
do { \
uint8_t status = 0; \
pal_get_server_power(FRU_MB, &status); \
if (status != SERVER_POWER_ON) { \
return; \
} \
if (power_on_sec < power_on_time) { \
return; \
} \
}while(0)
static gpio_value_t gpio_get(const char *shadow)
{
gpio_value_t value = GPIO_VALUE_INVALID;
gpio_desc_t *desc = gpio_open_by_shadow(shadow);
if (!desc) {
syslog(LOG_CRIT, "Open failed for GPIO: %s\n", shadow);
return GPIO_VALUE_INVALID;
}
if (gpio_get_value(desc, &value)) {
syslog(LOG_CRIT, "Get failed for GPIO: %s\n", shadow);
value = GPIO_VALUE_INVALID;
}
gpio_close(desc);
return value;
}
static void prochot_reason(char *reason)
{
if (gpio_get("IRQ_UV_DETECT_N") == GPIO_VALUE_LOW)
strcpy(reason, "UV");
if (gpio_get("IRQ_OC_DETECT_N") == GPIO_VALUE_LOW)
strcpy(reason, "OC");
if (gpio_get("FM_HSC_TIMER_EXP_N") == GPIO_VALUE_LOW)
strcpy(reason, "timer exp");
if (gpio_get("IRQ_SML1_PMBUS_ALERT_N") == GPIO_VALUE_LOW)
strcpy(reason, "PMBus alert");
}
static void cpu_prochot(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
char cmd[128] = {0};
const struct gpiopoll_config *cfg = gpio_poll_get_config(desc);
assert(cfg);
SERVER_POWER_CHECK(3);
//LCD debug card critical SEL support
strcat(cmd, "CPU FPH");
if (curr) {
strcat(cmd, " DEASSERT");
syslog(LOG_CRIT, "DEASSERT: %s - %s\n",
cfg->description, cfg->shadow);
} else {
char reason[32] = "";
strcat(cmd, " by ");
prochot_reason(reason);
strcat(cmd, reason);
syslog(LOG_CRIT, "ASSERT: %s - %s (reason: %s)\n",
cfg->description, cfg->shadow, reason);
strcat(cmd, " ASSERT");
}
pal_add_cri_sel(cmd);
}
void caterr(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
SERVER_POWER_CHECK(3);
CATERR_irq++;
}
void msmi(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
SERVER_POWER_CHECK(3);
MSMI_irq++;
}
void server_power_on_errors(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
SERVER_POWER_CHECK(3);
log_gpio_change(desc, curr, 0);
}
void server_power_on_errors_late(gpiopoll_pin_t *desc, gpio_value_t last, gpio_value_t curr)
{
SERVER_POWER_CHECK(5);
log_gpio_change(desc, curr, 0);
}
// Generic Event Handler for GPIO changes, but only logs event when MB is ON
static void gpio_event_handle_power(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
SERVER_POWER_CHECK(0);
log_gpio_change(gp, curr, 0);
}
static void gpio_event_handle_thermtrip(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
uint8_t status = 0;
if (gpio_get("RST_BMC_PLTRST_BUF_N") == GPIO_VALUE_LOW)
return;
pal_get_server_power(FRU_MB, &status);
if (status != SERVER_POWER_ON)
return;
// Filter false positives during reset.
if (reset_sec < 10)
return;
log_gpio_change(gp, curr, 0);
}
// Generic Event Handler for GPIO changes, but only logs event when PLTRST_N is high and power on
static void gpio_event_handle_PLTRST(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
uint8_t status = 0;
if (gpio_get("RST_BMC_PLTRST_BUF_N") == GPIO_VALUE_LOW)
return;
pal_get_server_power(FRU_MB, &status);
if (status != SERVER_POWER_ON)
return;
log_gpio_change(gp, curr, 0);
}
static void gpio_event_handle_hsc_fault(gpiopoll_pin_t *gp, gpio_value_t last, gpio_value_t curr)
{
if (gpio_get("IRQ_HSC_FAULT_N") == GPIO_VALUE_HIGH)
return;
// log the event
log_gpio_change(gp, curr, 0);
// if it's low, turn off 12V to protect the sled
turn_off_p12v_stby("IRQ_HSC_FAULT_N");
return;
}
void cpu_present(gpiopoll_pin_t *gpdesc, gpio_value_t value)
{
log_gpio_change(gpdesc, value, 0);
}
void por_caterr(gpiopoll_pin_t *gpdesc, gpio_value_t value)
{
uint8_t status = 0;
pal_get_server_power(FRU_MB, &status);
if (status && value == GPIO_VALUE_LOW) {
CATERR_irq++;
}
}
void por_msmi(gpiopoll_pin_t *gpdesc, gpio_value_t value)
{
uint8_t status = 0;
pal_get_server_power(FRU_MB, &status);
if (status && value == GPIO_VALUE_LOW) {
MSMI_irq++;
}
}
// GPIO table to be monitored
static struct gpiopoll_config g_gpios[] = {
// shadow, description, edge, handler, oneshot
{"PWRGD_SYS_PWROK", "GPIOB6", GPIO_EDGE_BOTH, power_ok, NULL},
{"IRQ_PVDDQ_GHJ_VRHOT_LVT3_N", "GPIOB7", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_CPU_ERR0_LVT3_BMC_N", "GPIOD6", GPIO_EDGE_BOTH, server_power_on_errors, NULL},
{"FM_CPU_ERR1_LVT3_BMC_N", "GPIOD7", GPIO_EDGE_BOTH, server_power_on_errors, NULL},
{"RST_SYSTEM_BTN_N", "GPIOE0", GPIO_EDGE_BOTH, pwr_on_reset, NULL},
{"FM_PWR_BTN_N", "GPIOE2", GPIO_EDGE_BOTH, pwr_on_push_button, NULL},
{"FP_NMI_BTN_N", "GPIOE4", GPIO_EDGE_BOTH, gpio_event_handle, NULL},
{"FM_CPU0_PROCHOT_LVT3_BMC_N", "GPIOE6", GPIO_EDGE_BOTH, cpu_prochot, NULL},
{"FM_CPU1_PROCHOT_LVT3_BMC_N", "GPIOE7", GPIO_EDGE_BOTH, cpu_prochot, NULL},
{"IRQ_PVDDQ_ABC_VRHOT_LVT3_N", "GPIOF0", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"IRQ_PVCCIN_CPU0_VRHOT_LVC3_N", "GPIOF2", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"IRQ_PVCCIN_CPU1_VRHOT_LVC3_N", "GPIOF3", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"IRQ_PVDDQ_KLM_VRHOT_LVT3_N", "GPIOF4", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_CPU_ERR2_LVT3_N", "GPIOG0", GPIO_EDGE_BOTH, server_power_on_errors, NULL},
{"FM_CPU_CATERR_LVT3_N", "GPIOG1", GPIO_EDGE_FALLING, caterr, por_caterr},
{"FM_PCH_BMC_THERMTRIP_N", "GPIOG2", GPIO_EDGE_BOTH, gpio_event_handle_thermtrip, NULL},
{"FM_CPU0_SKTOCC_LVT3_N", "GPIOG3", GPIO_EDGE_BOTH, gpio_event_handle_power, cpu_present},
{"FM_CPU0_FIVR_FAULT_LVT3_N", "GPIOI0", GPIO_EDGE_BOTH, gpio_event_handle_PLTRST, NULL},
{"FM_CPU1_FIVR_FAULT_LVT3_N", "GPIOI1", GPIO_EDGE_BOTH, gpio_event_handle_PLTRST, NULL},
{"IRQ_UV_DETECT_N", "GPIOL0", GPIO_EDGE_BOTH, irq_uv_detect, NULL},
{"IRQ_OC_DETECT_N", "GPIOL1", GPIO_EDGE_BOTH, gpio_event_handle, NULL},
{"FM_HSC_TIMER_EXP_N", "GPIOL2", GPIO_EDGE_BOTH, gpio_event_handle, NULL},
{"FM_MEM_THERM_EVENT_PCH_N", "GPIOL4", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_CPU0_RC_ERROR_N", "GPIOM0", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_CPU1_RC_ERROR_N", "GPIOM1", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_CPU0_THERMTRIP_LATCH_LVT3_N", "GPIOM4", GPIO_EDGE_BOTH, cpu0_thermtrip, NULL},
{"FM_CPU1_THERMTRIP_LATCH_LVT3_N", "GPIOM5", GPIO_EDGE_BOTH, cpu1_thermtrip, NULL},
{"FM_CPU_MSMI_LVT3_N", "GPION3", GPIO_EDGE_FALLING, msmi, por_msmi},
{"FM_POST_CARD_PRES_BMC_N", "GPIOQ6", GPIO_EDGE_BOTH, usb_debug_card_check_hotfix, NULL},
{"RST_BMC_PLTRST_BUF_N", "GPIOR5", GPIO_EDGE_BOTH, platform_reset_event_handle, NULL},
{"FM_THROTTLE_N", "GPIOS0", GPIO_EDGE_BOTH, server_power_on_errors_late, NULL},
{"H_CPU0_MEMABC_MEMHOT_LVT3_BMC_N", "GPIOX4", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"H_CPU0_MEMDEF_MEMHOT_LVT3_BMC_N", "GPIOX5", GPIO_EDGE_BOTH, server_power_on_errors, NULL},
{"H_CPU1_MEMGHJ_MEMHOT_LVT3_BMC_N", "GPIOX6", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"H_CPU1_MEMKLM_MEMHOT_LVT3_BMC_N", "GPIOX7", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_SLPS4_N", "GPIOY1", GPIO_EDGE_FALLING, slps4, NULL},
{"IRQ_PVDDQ_DEF_VRHOT_LVT3_N", "GPIOZ2", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_CPU1_SKTOCC_LVT3_N", "GPIOAA0", GPIO_EDGE_BOTH, gpio_event_handle_power, cpu_present},
{"IRQ_SML1_PMBUS_ALERT_N", "GPIOAA1", GPIO_EDGE_BOTH, gpio_event_handle, NULL},
{"IRQ_HSC_FAULT_N", "GPIOAB0", GPIO_EDGE_BOTH, gpio_event_handle_hsc_fault, NULL},
{"IRQ_DIMM_SAVE_LVT3_N", "GPIOD4", GPIO_EDGE_BOTH, gpio_event_handle_power, NULL},
{"FM_UARTSW_LSB_N", "GPIOQ4", GPIO_EDGE_BOTH, uart_switch, NULL},
{"FM_UARTSW_MSB_N", "GPIOQ5", GPIO_EDGE_BOTH, uart_switch, NULL},
};
// Thread for gpio timer
static void *
gpio_timer() {
uint8_t status = 0;
uint8_t fru = 1;
long int pot;
char str[MAX_VALUE_LEN] = {0};
int tread_time = 0 ;
while (1) {
sleep(1);
pal_get_server_power(fru, &status);
if (status == SERVER_POWER_ON) {
increase_timer(&reset_sec);
pot = increase_timer(&power_on_sec);
} else {
pot = decrease_timer(&power_on_sec);
}
// Wait power-on.sh finished, then update pwr_server_last_state
if (tread_time < 20) {
tread_time++;
} else {
if (pal_get_last_pwr_state(fru, str) < 0)
str[0] = '\0';
if (status == SERVER_POWER_ON) {
if (strncmp(str, POWER_ON_STR, strlen(POWER_ON_STR)) != 0) {
pal_set_last_pwr_state(fru, POWER_ON_STR);
syslog(LOG_INFO, "last pwr state updated to on\n");
}
} else {
// wait until PowerOnTime < -2 to make sure it's not AC lost
// Handle corner case during sled-cycle due to BMC residual electricity (1.2sec)
if (pot < -2 && strncmp(str, POWER_OFF_STR, strlen(POWER_OFF_STR)) != 0) {
pal_set_last_pwr_state(fru, POWER_OFF_STR);
syslog(LOG_INFO, "last pwr state updated to off\n");
}
}
trigger_ppin();
}
if ( g_uart_switch_count > 0) {
if ( --g_uart_switch_count == 0 )
pal_mmap(AST_GPIO_BASE, UARTSW_OFFSET, UARTSW_BY_DEBUG, 0);
}
}
return NULL;
}
static void ierr_mcerr_event_log(bool is_caterr, const char *err_type)
{
char temp_log[128] = {0};
char temp_syslog[128] = {0};
char cpu_str[32] = "";
int CPU_num = pal_CPU_error_num_chk( is_caterr );
if (CPU_num == 2)
strcpy(cpu_str, "0/1");
else if (CPU_num != -1)
sprintf(cpu_str, "%d", CPU_num);
sprintf(temp_syslog, "ASSERT: CPU%s %s\n", cpu_str, err_type);
sprintf(temp_log, "CPU%s %s", cpu_str, err_type);
syslog(LOG_CRIT, "%s", temp_syslog);
pal_add_cri_sel(temp_log);
}
// Thread for IERR/MCERR event detect
static void *
ierr_mcerr_event_handler() {
uint8_t CATERR_ierr_time_count = 0;
uint8_t MSMI_ierr_time_count = 0;
gpio_value_t value;
gpio_desc_t *caterr = gpio_open_by_shadow("FM_CPU_CATERR_LVT3_N");
gpio_desc_t *msmi = gpio_open_by_shadow("FM_CPU_MSMI_LVT3_N");
if (!caterr) {
return NULL;
}
if (!msmi) {
gpio_close(caterr);
return NULL;
}
while (1) {
if (CATERR_irq > 0) {
CATERR_ierr_time_count++;
if (CATERR_ierr_time_count == 2) {
if (CATERR_irq == 1) {
//FM_CPU_CATERR_LVT3_N
MCERR_IERR_assert = true;
if (gpio_get_value(caterr, &value)) {
syslog(LOG_CRIT, "Getting CATERR GPIO failed");
break;
}
if (value == GPIO_VALUE_LOW) {
ierr_mcerr_event_log(true, "IERR/CATERR");
} else {
ierr_mcerr_event_log(true, "MCERR/CATERR");
}
CATERR_irq--;
CATERR_ierr_time_count = 0;
set_fault_led(true);
if (system("/usr/local/bin/autodump.sh &") != 0) {
syslog(LOG_CRIT, "Starting crashdump on CATERR failed\n");
}
} else if (CATERR_irq > 1) {
while (CATERR_irq > 1) {
ierr_mcerr_event_log(true, "MCERR/CATERR");
CATERR_irq = CATERR_irq - 1;
}
CATERR_ierr_time_count = 1;
}
}
}
if (MSMI_irq > 0) {
MSMI_ierr_time_count++;
if (MSMI_ierr_time_count == 2) {
if (MSMI_irq == 1) {
//FM_CPU_MSMI_LVT3_N
MCERR_IERR_assert = true;
if (gpio_get_value(msmi, &value)) {
syslog(LOG_CRIT, "Getting MSMI GPIO failed");
break;
}
if (value == GPIO_VALUE_LOW) {
ierr_mcerr_event_log(false, "IERR/MSMI");
} else {
ierr_mcerr_event_log(false, "MCERR/MSMI");
}
MSMI_irq--;
MSMI_ierr_time_count = 0;
set_fault_led(true);
if (system("/usr/local/bin/autodump.sh &") != 0) {
syslog(LOG_CRIT, "Starting crashdump on MCERR failed\n");
}
} else if (MSMI_irq > 1) {
while (MSMI_irq > 1) {
ierr_mcerr_event_log(false, "MCERR/MSMI");
MSMI_irq = MSMI_irq - 1;
}
MSMI_ierr_time_count = 1;
}
}
}
usleep(25000); //25ms
}
gpio_close(caterr);
gpio_close(msmi);
return NULL;
}
int
main(int argc, char **argv) {
int rc, pid_file;
pthread_t tid_ierr_mcerr_event;
pthread_t tid_gpio_timer;
pthread_t tid_smi_timer;
gpiopoll_desc_t *polldesc;
pid_file = open("/var/run/gpiod.pid", O_CREAT | O_RDWR, 0666);
rc = flock(pid_file, LOCK_EX | LOCK_NB);
if(rc) {
if(EWOULDBLOCK == errno) {
syslog(LOG_ERR, "Another gpiod instance is running...\n");
exit(-1);
}
} else {
daemon(0,1);
openlog("gpiod", LOG_CONS, LOG_DAEMON);
syslog(LOG_INFO, "gpiod: daemon started");
//Create thread for IERR/MCERR event detect
if (pthread_create(&tid_ierr_mcerr_event, NULL, ierr_mcerr_event_handler, NULL) < 0) {
syslog(LOG_WARNING, "pthread_create for ierr_mcerr_event_handler\n");
exit(1);
}
//Create thread for platform reset event filter check
if (pthread_create(&tid_gpio_timer, NULL, gpio_timer, NULL) < 0) {
syslog(LOG_WARNING, "pthread_create for platform_reset_filter_handler\n");
exit(1);
}
//Create thread for SMI check
if (pthread_create(&tid_smi_timer, NULL, smi_timer, NULL) < 0)
{
syslog(LOG_WARNING, "pthread_create for smi_handler fail\n");
exit(1);
}
polldesc = gpio_poll_open(g_gpios, sizeof(g_gpios)/sizeof(g_gpios[0]));
if (!polldesc) {
syslog(LOG_CRIT, "Cannot start poll operation on GPIOs");
} else {
if (gpio_poll(polldesc, POLL_TIMEOUT)) {
syslog(LOG_CRIT, "Poll returned error");
}
gpio_poll_close(polldesc);
}
}
return 0;
}