// SPDX-License-Identifier: GPL-2.0+ /* * ipmi_bt_sm.c * * The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part * of the driver architecture at http://sourceforge.net/projects/openipmi * * Author: Rocky Craig <[email protected]> */ #define DEBUG … #include <linux/kernel.h> /* For printk. */ #include <linux/string.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ipmi_msgdefs.h> /* for completion codes */ #include "ipmi_si_sm.h" #define BT_DEBUG_OFF … #define BT_DEBUG_ENABLE … #define BT_DEBUG_MSG … #define BT_DEBUG_STATES … /* * BT_DEBUG_OFF must be zero to correspond to the default uninitialized * value */ static int bt_debug; /* 0 == BT_DEBUG_OFF */ module_param(bt_debug, int, 0644); MODULE_PARM_DESC(…) …; /* * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, * and 64 byte buffers. However, one HP implementation wants 255 bytes of * buffer (with a documented message of 160 bytes) so go for the max. * Since the Open IPMI architecture is single-message oriented at this * stage, the queue depth of BT is of no concern. */ #define BT_NORMAL_TIMEOUT … #define BT_NORMAL_RETRY_LIMIT … #define BT_RESET_DELAY … /* * States are written in chronological order and usually cover * multiple rows of the state table discussion in the IPMI spec. */ enum bt_states { … }; /* * Macros seen at the end of state "case" blocks. They help with legibility * and debugging. */ #define BT_STATE_CHANGE(X, Y) … #define BT_SI_SM_RETURN(Y) … struct si_sm_data { … }; #define BT_CLR_WR_PTR … #define BT_CLR_RD_PTR … #define BT_H2B_ATN … #define BT_B2H_ATN … #define BT_SMS_ATN … #define BT_OEM0 … #define BT_H_BUSY … #define BT_B_BUSY … /* * Some bits are toggled on each write: write once to set it, once * more to clear it; writing a zero does nothing. To absolutely * clear it, check its state and write if set. This avoids the "get * current then use as mask" scheme to modify one bit. Note that the * variable "bt" is hardcoded into these macros. */ #define BT_STATUS … #define BT_CONTROL(x) … #define BMC2HOST … #define HOST2BMC(x) … #define BT_INTMASK_R … #define BT_INTMASK_W(x) … /* * Convenience routines for debugging. These are not multi-open safe! * Note the macros have hardcoded variables in them. */ static char *state2txt(unsigned char state) { … } #define STATE2TXT … static char *status2txt(unsigned char status) { … } #define STATUS2TXT … /* called externally at insmod time, and internally on cleanup */ static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) { … } /* Jam a completion code (probably an error) into a response */ static void force_result(struct si_sm_data *bt, unsigned char completion_code) { … } /* The upper state machine starts here */ static int bt_start_transaction(struct si_sm_data *bt, unsigned char *data, unsigned int size) { … } /* * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE * it calls this. Strip out the length and seq bytes. */ static int bt_get_result(struct si_sm_data *bt, unsigned char *data, unsigned int length) { … } /* This bit's functionality is optional */ #define BT_BMC_HWRST … static void reset_flags(struct si_sm_data *bt) { … } /* * Get rid of an unwanted/stale response. This should only be needed for * BMCs that support multiple outstanding requests. */ static void drain_BMC2HOST(struct si_sm_data *bt) { … } static inline void write_all_bytes(struct si_sm_data *bt) { … } static inline int read_all_bytes(struct si_sm_data *bt) { … } /* Restart if retries are left, or return an error completion code */ static enum si_sm_result error_recovery(struct si_sm_data *bt, unsigned char status, unsigned char cCode) { … } /* Check status and (usually) take action and change this state machine. */ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { … } static int bt_detect(struct si_sm_data *bt) { … } static void bt_cleanup(struct si_sm_data *bt) { … } static int bt_size(void) { … } const struct si_sm_handlers bt_smi_handlers = …;