diff options
Diffstat (limited to 'src/usr/pnor/ast_mboxdd.C')
-rw-r--r-- | src/usr/pnor/ast_mboxdd.C | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/src/usr/pnor/ast_mboxdd.C b/src/usr/pnor/ast_mboxdd.C new file mode 100644 index 000000000..a515a81a9 --- /dev/null +++ b/src/usr/pnor/ast_mboxdd.C @@ -0,0 +1,486 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/ast_mboxdd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file ast_mboxdd.C + * + * @brief Implementation of the PNOR Device Driver on top of AST MBOX protocol + */ + +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ +#include <sys/mmio.h> +#include <sys/task.h> +#include <sys/sync.h> +#include <sys/time.h> +#include <string.h> +#include <stdio.h> +#include <devicefw/driverif.H> +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <errl/errludlogregister.H> +#include <errl/errludstring.H> +#include <targeting/common/targetservice.H> +#include <sio/sio.H> +#include "ast_mboxdd.H" +#include <pnor/pnor_reasoncodes.H> +#include <sys/time.h> +#include <initservice/initserviceif.H> +#include <util/align.H> +#include <lpc/lpcif.H> +#include <config.h> + +// Initialized in pnorrp.C +extern trace_desc_t* g_trac_pnor; + +errlHndl_t astMbox::mboxOut(uint64_t i_addr, uint8_t i_byte) +{ + size_t len = sizeof(i_byte); + /*iv_target is TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, */ + return deviceWrite(iv_target, + &i_byte, + len, + DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr + MBOX_IO_BASE)); +} + +errlHndl_t astMbox::mboxIn(uint64_t i_addr, uint8_t& o_byte) +{ + size_t len = sizeof(o_byte); + /*iv_target is TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, */ + return deviceRead(iv_target, + static_cast<uint8_t*>(&o_byte), + len, + DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr + MBOX_IO_BASE)); +} + +errlHndl_t astMbox::doMessage(mboxMessage& io_msg) +{ + uint8_t* l_data = reinterpret_cast <uint8_t*>((char*)&io_msg); + errlHndl_t l_err = NULL; + uint8_t l_stat1; + uint8_t l_flags; + uint32_t l_loops = 0; + bool l_prot_error = false; + int i; + + TRACFCOMP( g_trac_pnor, ENTER_MRK"astMboxDD::doMessage(0x%02x)", + io_msg.iv_cmd ); + io_msg.iv_seq = iv_mboxMsgSeq++; + + do + { + /* Write message out */ + for (i = 0; i < BMC_MBOX_DATA_REGS && !l_err; i++) + { + l_err = mboxOut(i, l_data[i]); + } + + if ( l_err ) + { + break; + } + + /* Clear status1 response bit as it was just set via reg write*/ + l_err = mboxOut(MBOX_STATUS_1, MBOX_STATUS1_RESP); + + if ( l_err ) + { + break; + } + + /* Ping BMC */ + l_err = mboxOut(MBOX_HOST_CTRL, MBOX_CTRL_INT_SEND); + + if ( l_err ) + { + break; + } + + TRACFCOMP( g_trac_pnor, "Command sent, waiting for response..."); + + /* Wait for response */ + while ( l_loops++ < MBOX_MAX_RESP_WAIT_US && !l_err ) + { + l_err = mboxIn(MBOX_STATUS_1, l_stat1); + + if ( l_err ) + { + break; + } + + l_err = mboxIn(MBOX_FLAG_REG, l_flags); + + if ( l_err ) + { + break; + } + + if ( l_stat1 & MBOX_STATUS1_RESP ) + { + break; + } + + nanosleep(0, 1000); + } + + TRACDCOMP( g_trac_pnor, "status=%02x flags=%02x", l_stat1, l_flags); + + if ( l_err ) + { + TRACFCOMP( g_trac_pnor, "Got error waiting for response !"); + break; + } + + if ( !(l_stat1 & MBOX_STATUS1_RESP) ) + { + TRACFCOMP( g_trac_pnor, + "Timeout waiting for response !"); + + // Don't try to interrupt the BMC anymore + l_err = mboxOut(MBOX_HOST_CTRL, 0); + + if ( l_err) + { + //Make a notie the command failed, and delete l_err to remove + // memory leak. Let error below be the one committed. + TRACFCOMP( g_trac_pnor, "Error communicating with MBOX daemon"); + delete l_err; + } + + /*@ + * @errortype + * @moduleid PNOR::MOD_ASTMBOXDD_DO_MESSAGE + * @reasoncode PNOR::RC_SFC_TIMEOUT + * @userdata1[48:55] mbox status 1 reg + * @userdata1[56:63] mbox flag reg + * @devdesc astMbox::doMessage> Timeout waiting for + * message response + * @custdesc BMC not responding while accessing the flash + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_ASTMBOXDD_DO_MESSAGE, + PNOR::RC_SFC_TIMEOUT, + TWO_UINT8_TO_UINT16(l_stat1, + l_flags), + 0); + + // Limited in callout: no PNOR target, so calling out + // Service Processor + l_err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE, + HWAS::SRCI_PRIORITY_HIGH); + l_err->collectTrace(PNOR_COMP_NAME); + + // Tell the code below that we generated the error + // (not an LPC error) + l_prot_error = true; + break; + } + + /* Clear status */ + l_err = mboxOut(MBOX_STATUS_1, MBOX_STATUS1_RESP); + + if (l_err) + { + TRACFCOMP( g_trac_pnor, "Got error clearing status"); + break; + } + + // Remember some message fields before they get overwritten + // by the response + uint8_t old_seq = io_msg.iv_seq; + uint8_t old_cmd = io_msg.iv_cmd; + + // Read response + TRACFCOMP( g_trac_pnor, "Reading response data..."); + + for (i = 0; i < BMC_MBOX_DATA_REGS && !l_err; i++) + { + l_err = mboxIn(i, l_data[i]); + } + + if ( l_err ) + { + TRACFCOMP( g_trac_pnor, "Got error reading response !"); + break; + } + + TRACFCOMP( g_trac_pnor, "Message: cmd:%02x seq:%02x a:%02x %02x %02x %02x %02x..resp:%02x", + io_msg.iv_cmd, io_msg.iv_seq, io_msg.iv_args[0], + io_msg.iv_args[1], io_msg.iv_args[2], io_msg.iv_args[3], + io_msg.iv_args[4], io_msg.iv_resp); + + if (old_seq != io_msg.iv_seq) + { + TRACFCOMP( g_trac_pnor, "bad sequence number in mbox message, got %d want %d", + io_msg.iv_seq, old_seq); + + /*@ + * @errortype + * @moduleid PNOR::MOD_ASTMBOXDD_DO_MESSAGE + * @reasoncode PNOR::RC_MBOX_BAD_SEQUENCE + * @userdata1[48:55] mbox status 1 reg + * @userdata1[56:63] mbox flag reg + * @userdata2[32:39] original command code + * @userdata2[40:47] response command code + * @userdata2[48:55] sequence wanted + * @userdata2[56:63] sequence obtained + * @devdesc astMbox::doMessage> Timeout waiting for + * message response + * @custdesc BMC not responding while accessing the flash + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_ASTMBOXDD_DO_MESSAGE, + PNOR::RC_MBOX_BAD_SEQUENCE, + TWO_UINT8_TO_UINT16(l_stat1, l_flags), + FOUR_UINT8_TO_UINT32(old_cmd, + io_msg.iv_cmd, + old_seq, + io_msg.iv_seq)); + + // Limited in callout: no PNOR target, so calling out + // Service Processor + l_err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE, + HWAS::SRCI_PRIORITY_HIGH); + + l_err->collectTrace(PNOR_COMP_NAME); + + // Tell code below that we generated the error (not an LPC error) + l_prot_error = true; + break; + } + + if (io_msg.iv_resp != MBOX_R_SUCCESS) + { + TRACFCOMP( g_trac_pnor, + "BMC mbox command failed with err %d", + io_msg.iv_resp); + + /*@ + * @errortype + * @moduleid PNOR::MOD_ASTMBOXDD_DO_MESSAGE + * @reasoncode PNOR::RC_MBOX_ERROR_STATUS + * @userdata1[48:55] mbox status 1 reg + * @userdata1[56:63] mbox flag reg + * @userdata2[32:39] original command code + * @userdata2[40:47] response command code + * @userdata2[48:55] sequence number + * @userdata2[56:63] status code + * @devdesc astMbox::doMessage> Timeout waiting for + * message response + * @custdesc BMC not responding while accessing the flash + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_ASTMBOXDD_DO_MESSAGE, + PNOR::RC_MBOX_ERROR_STATUS, + TWO_UINT8_TO_UINT16(l_stat1, l_flags), + FOUR_UINT8_TO_UINT32(old_cmd, + io_msg.iv_cmd, + old_seq, + io_msg.iv_resp)); + + // Limited in callout: no PNOR target, so calling out + // Service Processor + l_err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE, + HWAS::SRCI_PRIORITY_HIGH); + + l_err->collectTrace(PNOR_COMP_NAME); + + // Tell code below that we generated the error (not an LPC error) + l_prot_error = true; + break; + } + + } + while(0); + + // If we got an LPC error, commit it and generate our own + if ( l_err && !l_prot_error ) + { + errlHndl_t l_lpc_err = l_err; + + TRACFCOMP( g_trac_pnor, "LPC Error writing to mbox :: RC=%.4X", + ERRL_GETRC_SAFE(l_err) ); + + /*@ + * @errortype + * @moduleid PNOR::MOD_ASTMBOXDD_DO_MESSAGE + * @reasoncode PNOR::RC_LPC_ERROR + * @devdesc astMbox::doMessage> LPC Error communicating + with the mailbox + * @custdesc LPC bus error communicating with the BMC + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_ASTMBOXDD_DO_MESSAGE, + PNOR::RC_LPC_ERROR, 0, 0); + + // Limited in callout: no PNOR target, so calling out processor + l_err->addHwCallout( iv_target, + HWAS::SRCI_PRIORITY_HIGH, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL ); + + l_err->collectTrace(PNOR_COMP_NAME); + + l_err->plid(l_lpc_err->plid()); + l_lpc_err->setSev(ERRORLOG::ERRL_SEV_UNRECOVERABLE); + ERRORLOG::errlCommit(l_lpc_err, PNOR_COMP_ID); + } + + TRACFCOMP( g_trac_pnor, EXIT_MRK "astMboxDD::doMessage() resp=0x%02x", + io_msg.iv_resp ); + return l_err; +} + +errlHndl_t astMbox::initializeMbox(void) +{ + errlHndl_t l_errl = NULL; + uint8_t l_data; + size_t l_len = sizeof(uint8_t); + + TRACFCOMP(g_trac_pnor, ENTER_MRK"PnorDD::initializeMBOX()"); + + do + { + //First disable SIO Mailbox engine to configure it + // 0x30 - Enable/Disable Reg + l_data = SIO::DISABLE_DEVICE; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::MB, 0x30)); + + if (l_errl) + { + break; + } + + // Set MBOX Base Address + //Regs 0x60/0x61 are a BAR-like reg to configure the MBOX base address + l_data = (MBOX_IO_BASE >> 8) & 0xFF; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::MB, 0x60)); + + if (l_errl) + { + break; + } + + // Set other half of MBOX Base Address + l_data = MBOX_IO_BASE & 0xFF; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::MB, 0x61)); + + if (l_errl) + { + break; + } + + //Configure MBOX IRQs + //Regs 0x70 / 0x71 control that + l_data = MBOX_LPC_IRQ; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::MB, 0x70)); + + if (l_errl) + { + break; + } + + //Other half of MBOX IRQ Configuration + l_data = 1; /* Low level trigger */ + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::MB, 0x71)); + + if (l_errl) + { + break; + } + + //Re-enable Device now that base addr and IRQs are configured + l_data = SIO::ENABLE_DEVICE; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::MB, 0x30)); + + if (l_errl) + { + break; + } + + } + while(0); + + return l_errl; +} + +/** + * @brief Constructor + */ +astMbox::astMbox( TARGETING::Target* i_target ) + : iv_target(i_target) + , iv_mboxMsgSeq(1) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK "astMbox::astMbox()" ); + errlHndl_t l_err = NULL; + + l_err = initializeMbox(); + + if (l_err) + { + TRACFCOMP( g_trac_pnor, "Failure to initialize the MBOX logic, shutting down :: RC=%.4X", ERRL_GETRC_SAFE(l_err) ); + l_err->collectTrace(PNOR_COMP_NAME); + ERRORLOG::errlCommit(l_err, PNOR_COMP_ID); + INITSERVICE::doShutdown( PNOR::RC_PNOR_INIT_FAILURE ); + } + + //This Mbox Driver expects the target to be the master proc + assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + "Error in astMbox(), i_target != Master Proc"); + + TRACFCOMP(g_trac_pnor, EXIT_MRK "astMbox::astMbox()" ); +} + +/** + * @brief Destructor + */ +astMbox::~astMbox() +{ +} |