// SPDX-License-Identifier: GPL-2.0+ /* * ipmi_smic_sm.c * * The state-machine driver for an IPMI SMIC driver * * It started as a copy of Corey Minyard's driver for the KSC interface * and the kernel patch "mmcdev-patch-245" by HP * * modified by: Hannes Schulz <schulz@schwaar.com> * ipmi@schwaar.com * * * Corey Minyard's driver for the KSC interface has the following * copyright notice: * Copyright 2002 MontaVista Software Inc. * * the kernel patch "mmcdev-patch-245" by HP has the following * copyright notice: * (c) Copyright 2001 Grant Grundler (c) Copyright * 2001 Hewlett-Packard Company
*/
#define DEBUG /* So dev_dbg() is always available. */
#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"
/* smic_debug is a bit-field * SMIC_DEBUG_ENABLE - turned on for now * SMIC_DEBUG_MSG - commands and their responses * SMIC_DEBUG_STATES - state machine
*/ #define SMIC_DEBUG_STATES 4 #define SMIC_DEBUG_MSG 2 #define SMIC_DEBUG_ENABLE 1
/* * SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by * a few systems, and then only by Systems Management * Interrupts, not by the OS. Always ignore these bits. *
*/ #define SMIC_SMI 0x10 #define SMIC_EVM_DATA_AVAIL 0x08 #define SMIC_SMS_DATA_AVAIL 0x04 #define SMIC_FLAG_BSY 0x01
struct si_sm_data { enum smic_states state; struct si_sm_io *io; unsignedchar write_data[MAX_SMIC_WRITE_SIZE]; int write_pos; int write_count; int orig_write_count; unsignedchar read_data[MAX_SMIC_READ_SIZE]; int read_pos; int truncated; unsignedint error_retries; long smic_timeout;
};
/* these are the control/status codes we actually use SMIC_CC_SMS_GET_STATUS 0x40 SMIC_CC_SMS_WR_START 0x41 SMIC_CC_SMS_WR_NEXT 0x42 SMIC_CC_SMS_WR_END 0x43 SMIC_CC_SMS_RD_START 0x44 SMIC_CC_SMS_RD_NEXT 0x45 SMIC_CC_SMS_RD_END 0x46
if (smic->state == SMIC_HOSED) {
init_smic_data(smic, smic->io); return SI_SM_HOSED;
} if (smic->state != SMIC_IDLE) { if (smic_debug & SMIC_DEBUG_STATES)
dev_dbg(smic->io->dev, "%s - smic->smic_timeout = %ld, time = %ld\n",
__func__, smic->smic_timeout, time); /* * FIXME: smic_event is sometimes called with time > * SMIC_RETRY_TIMEOUT
*/ if (time < SMIC_RETRY_TIMEOUT) {
smic->smic_timeout -= time; if (smic->smic_timeout < 0) {
start_error_recovery(smic, "smic timed out."); return SI_SM_CALL_WITH_DELAY;
}
}
}
flags = read_smic_flags(smic); if (flags & SMIC_FLAG_BSY) return SI_SM_CALL_WITH_DELAY;
status = read_smic_status(smic); if (smic_debug & SMIC_DEBUG_STATES)
dev_dbg(smic->io->dev, "%s - state = %d, flags = 0x%02x, status = 0x%02x\n",
__func__, smic->state, flags, status);
switch (smic->state) { case SMIC_IDLE: /* in IDLE we check for available messages */ if (flags & SMIC_SMS_DATA_AVAIL) return SI_SM_ATTN; return SI_SM_IDLE;
case SMIC_OP_OK: if (status != SMIC_SC_SMS_READY) { /* this should not happen */
start_error_recovery(smic, "state = SMIC_OP_OK," " status != SMIC_SC_SMS_READY"); return SI_SM_CALL_WITH_DELAY;
} /* OK so far; smic is idle let us start ... */
write_smic_control(smic, SMIC_CC_SMS_WR_START);
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_WRITE_START; break;
case SMIC_WRITE_START: if (status != SMIC_SC_SMS_WR_START) {
start_error_recovery(smic, "state = SMIC_WRITE_START, " "status != SMIC_SC_SMS_WR_START"); return SI_SM_CALL_WITH_DELAY;
} /* * we must not issue WR_(NEXT|END) unless * TX_DATA_READY is set
* */ if (flags & SMIC_TX_DATA_READY) { if (smic->write_count == 1) { /* last byte */
write_smic_control(smic, SMIC_CC_SMS_WR_END);
smic->state = SMIC_WRITE_END;
} else {
write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
smic->state = SMIC_WRITE_NEXT;
}
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
} else return SI_SM_CALL_WITH_DELAY; break;
case SMIC_WRITE_NEXT: if (status != SMIC_SC_SMS_WR_NEXT) {
start_error_recovery(smic, "state = SMIC_WRITE_NEXT, " "status != SMIC_SC_SMS_WR_NEXT"); return SI_SM_CALL_WITH_DELAY;
} /* this is the same code as in SMIC_WRITE_START */ if (flags & SMIC_TX_DATA_READY) { if (smic->write_count == 1) {
write_smic_control(smic, SMIC_CC_SMS_WR_END);
smic->state = SMIC_WRITE_END;
} else {
write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
smic->state = SMIC_WRITE_NEXT;
}
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
} else return SI_SM_CALL_WITH_DELAY; break;
case SMIC_WRITE_END: if (status != SMIC_SC_SMS_WR_END) {
start_error_recovery(smic, "state = SMIC_WRITE_END, " "status != SMIC_SC_SMS_WR_END"); return SI_SM_CALL_WITH_DELAY;
} /* data register holds an error code */
data = read_smic_data(smic); if (data != 0) { if (smic_debug & SMIC_DEBUG_ENABLE)
dev_dbg(smic->io->dev, "SMIC_WRITE_END: data = %02x\n",
data);
start_error_recovery(smic, "state = SMIC_WRITE_END, " "data != SUCCESS"); return SI_SM_CALL_WITH_DELAY;
} else
smic->state = SMIC_WRITE2READ; break;
case SMIC_WRITE2READ: /* * we must wait for RX_DATA_READY to be set before we * can continue
*/ if (flags & SMIC_RX_DATA_READY) {
write_smic_control(smic, SMIC_CC_SMS_RD_START);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_START;
} else return SI_SM_CALL_WITH_DELAY; break;
case SMIC_READ_START: if (status != SMIC_SC_SMS_RD_START) {
start_error_recovery(smic, "state = SMIC_READ_START, " "status != SMIC_SC_SMS_RD_START"); return SI_SM_CALL_WITH_DELAY;
} if (flags & SMIC_RX_DATA_READY) {
read_next_byte(smic);
write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_NEXT;
} else return SI_SM_CALL_WITH_DELAY; break;
case SMIC_READ_NEXT: switch (status) { /* * smic tells us that this is the last byte to be read * --> clean up
*/ case SMIC_SC_SMS_RD_END:
read_next_byte(smic);
write_smic_control(smic, SMIC_CC_SMS_RD_END);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_END; break; case SMIC_SC_SMS_RD_NEXT: if (flags & SMIC_RX_DATA_READY) {
read_next_byte(smic);
write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_NEXT;
} else return SI_SM_CALL_WITH_DELAY; break; default:
start_error_recovery(
smic, "state = SMIC_READ_NEXT, " "status != SMIC_SC_SMS_RD_(NEXT|END)"); return SI_SM_CALL_WITH_DELAY;
} break;
case SMIC_READ_END: if (status != SMIC_SC_SMS_READY) {
start_error_recovery(smic, "state = SMIC_READ_END, " "status != SMIC_SC_SMS_READY"); return SI_SM_CALL_WITH_DELAY;
}
data = read_smic_data(smic); /* data register holds an error code */ if (data != 0) { if (smic_debug & SMIC_DEBUG_ENABLE)
dev_dbg(smic->io->dev, "SMIC_READ_END: data = %02x\n",
data);
start_error_recovery(smic, "state = SMIC_READ_END, " "data != SUCCESS"); return SI_SM_CALL_WITH_DELAY;
} else {
smic->state = SMIC_IDLE; return SI_SM_TRANSACTION_COMPLETE;
}
case SMIC_HOSED:
init_smic_data(smic, smic->io); return SI_SM_HOSED;
staticint smic_detect(struct si_sm_data *smic)
{ /* * It's impossible for the SMIC fnags 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_smic_flags(smic) == 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.