// SPDX-License-Identifier: GPL-2.0+ /* * ipmi_kcs_sm.c * * State machine for handling IPMI KCS interfaces. * * Author: MontaVista Software, Inc. * Corey Minyard <minyard@mvista.com> * source@mvista.com * * Copyright 2002 MontaVista Software Inc.
*/
/* * This state machine is taken from the state machine in the IPMI spec, * pretty much verbatim. If you have questions about the states, see * that document.
*/
#define DEBUG /* So dev_dbg() is always available. */
/* kcs_debug is a bit-field * KCS_DEBUG_ENABLE - turned on for now * KCS_DEBUG_MSG - commands and their responses * KCS_DEBUG_STATES - state machine
*/ #define KCS_DEBUG_STATES 4 #define KCS_DEBUG_MSG 2 #define KCS_DEBUG_ENABLE 1
/* The states the KCS driver may be in. */ enum kcs_states { /* The KCS interface is currently doing nothing. */
KCS_IDLE,
/* * We are starting an operation. The data is in the output * buffer, but nothing has been done to the interface yet. This * was added to the state machine in the spec to wait for the * initial IBF.
*/
KCS_START_OP,
/* We have written a write cmd to the interface. */
KCS_WAIT_WRITE_START,
/* We are writing bytes to the interface. */
KCS_WAIT_WRITE,
/* * We have written the write end cmd to the interface, and * still need to write the last byte.
*/
KCS_WAIT_WRITE_END,
/* We are waiting to read data from the interface. */
KCS_WAIT_READ,
/* * State to transition to the error handler, this was added to * the state machine in the spec to be sure IBF was there.
*/
KCS_ERROR0,
/* * First stage error handler, wait for the interface to * respond.
*/
KCS_ERROR1,
/* * The abort cmd has been written, wait for the interface to * respond.
*/
KCS_ERROR2,
/* * We wrote some data to the interface, wait for it to switch * to read mode.
*/
KCS_ERROR3,
/* The hardware failed to follow the state machine. */
KCS_HOSED
};
struct si_sm_data { enum kcs_states state; struct si_sm_io *io; unsignedchar write_data[MAX_KCS_WRITE_SIZE]; int write_pos; int write_count; int orig_write_count; unsignedchar read_data[MAX_KCS_READ_SIZE]; int read_pos; int truncated;
unsignedint error_retries; long ibf_timeout; long obf_timeout; unsignedlong error0_timeout;
};
if ((length >= 3) && (kcs->read_pos < 3)) { /* Guarantee that we return at least 3 bytes, with an
error in the third byte if it is too short. */
data[2] = IPMI_ERR_UNSPECIFIED;
kcs->read_pos = 3;
} if (kcs->truncated) { /* * Report a truncated error. We might overwrite * another error, but that's too bad, the user needs * to know it was truncated.
*/
data[2] = IPMI_ERR_MSG_TRUNCATED;
kcs->truncated = 0;
}
return kcs->read_pos;
}
/* * This implements the state machine defined in the IPMI manual, see * that for details on how this works. Divide that flowchart into * sections delimited by "Wait for IBF" and this will become clear.
*/ staticenum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
{ unsignedchar status; unsignedchar state;
status = read_status(kcs);
if (kcs_debug & KCS_DEBUG_STATES)
dev_dbg(kcs->io->dev, "KCS: State = %d, %x\n", kcs->state, status);
/* All states wait for ibf, so just do it here. */ if (!check_ibf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY;
/* Just about everything looks at the KCS state, so grab that, too. */
state = GET_STATUS_STATE(status);
switch (kcs->state) { case KCS_IDLE: /* If there's and interrupt source, turn it off. */
clear_obf(kcs, status);
if (GET_STATUS_ATN(status)) return SI_SM_ATTN; else return SI_SM_IDLE;
case KCS_START_OP: if (state != KCS_IDLE_STATE) {
start_error_recovery(kcs, "State machine not idle at start"); break;
}
case KCS_WAIT_WRITE_START: if (state != KCS_WRITE_STATE) {
start_error_recovery(
kcs, "Not in write state at write start"); break;
}
read_data(kcs); if (kcs->write_count == 1) {
write_cmd(kcs, KCS_WRITE_END);
kcs->state = KCS_WAIT_WRITE_END;
} else {
write_next_byte(kcs);
kcs->state = KCS_WAIT_WRITE;
} break;
case KCS_WAIT_WRITE: if (state != KCS_WRITE_STATE) {
start_error_recovery(kcs, "Not in write state for write"); break;
}
clear_obf(kcs, status); if (kcs->write_count == 1) {
write_cmd(kcs, KCS_WRITE_END);
kcs->state = KCS_WAIT_WRITE_END;
} else {
write_next_byte(kcs);
} break;
case KCS_WAIT_WRITE_END: if (state != KCS_WRITE_STATE) {
start_error_recovery(kcs, "Not in write state" " for write end"); break;
}
clear_obf(kcs, status);
write_next_byte(kcs);
kcs->state = KCS_WAIT_READ; break;
case KCS_WAIT_READ: if ((state != KCS_READ_STATE) && (state != KCS_IDLE_STATE)) {
start_error_recovery(
kcs, "Not in read or idle in read state"); break;
}
if (state == KCS_READ_STATE) { if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY;
read_next_byte(kcs);
} else { /* * We don't implement this exactly like the state * machine in the spec. Some broken hardware * does not write the final dummy byte to the * read register. Thus obf will never go high * here. We just go straight to idle, and we * handle clearing out obf in idle state if it * happens to come in.
*/
clear_obf(kcs, status);
kcs->orig_write_count = 0;
kcs->state = KCS_IDLE; return SI_SM_TRANSACTION_COMPLETE;
} break;
case KCS_ERROR0:
clear_obf(kcs, status);
status = read_status(kcs); if (GET_STATUS_OBF(status)) /* controller isn't responding */ if (time_before(jiffies, kcs->error0_timeout)) return SI_SM_CALL_WITH_TICK_DELAY;
write_cmd(kcs, KCS_GET_STATUS_ABORT);
kcs->state = KCS_ERROR1; break;
case KCS_ERROR1:
clear_obf(kcs, status);
write_data(kcs, 0);
kcs->state = KCS_ERROR2; break;
case KCS_ERROR2: if (state != KCS_READ_STATE) {
start_error_recovery(kcs, "Not in read state for error2"); break;
} if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY;
staticint kcs_detect(struct si_sm_data *kcs)
{ /* * It's impossible for the KCS status register to be all 1's, * (assuming a properly functioning, self-initialized BMC) * but that's what you get from reading a bogus address, so we * test that first.
*/ if (read_status(kcs) == 0xff) return 1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.