From b4eb096bd19d6b4aee4aa87424818bff1d5605eb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 7 Apr 2017 16:39:53 +1000 Subject: pnor: Add AST Mailbox protocol support This adds a new alternative PnorDD that uses the Asped AST Mbox protocol as supported by OpenBMC. To enable this, you need these changes to the config: @@ -1,10 +1,12 @@ -# The Serial Flash Controller is the AST2400 BMC. -set SFC_IS_AST2500 +# We use BMC MBOX protocol for flash accesses +set PNORDD_IS_BMCMBOX +unset PNORDD_IS_SFC +unset SFC_IS_AST2500 unset SFC_IS_AST2400 unset BMC_DOES_SFC_INIT unset SFC_IS_IBM_DPSS -set ALLOW_MICRON_PNOR -set ALLOW_MACRONIX_PNOR +unset ALLOW_MICRON_PNOR +unset ALLOW_MACRONIX_PNOR Other systems need to set PNORDD_IS_SFC Change-Id: I8901288c98d8d0fce8c9a0fb31267f0001b2a731 Not-yet-signed-off-by: Benjamin Herrenschmidt RTC: 170096 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39387 Tested-by: Jenkins Server Reviewed-by: Dean Sanner Tested-by: Jenkins OP Build CI Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell Reviewed-by: Matthew A. Ploetz --- src/usr/pnor/HBconfig | 20 +- src/usr/pnor/ast_mboxdd.C | 486 +++++++++++++++++++++++++++++ src/usr/pnor/ast_mboxdd.H | 214 +++++++++++++ src/usr/pnor/makefile | 7 +- src/usr/pnor/pnor_mboxdd.C | 676 +++++++++++++++++++++++++++++++++++++++++ src/usr/pnor/pnor_mboxdd.H | 258 ++++++++++++++++ src/usr/pnor/pnordd.H | 15 +- src/usr/pnor/pnorrp.C | 1 - src/usr/pnor/pnorvalid.C | 8 +- src/usr/pnor/test/pnorddtest.H | 6 +- 10 files changed, 1669 insertions(+), 22 deletions(-) create mode 100644 src/usr/pnor/ast_mboxdd.C create mode 100644 src/usr/pnor/ast_mboxdd.H create mode 100644 src/usr/pnor/pnor_mboxdd.C create mode 100644 src/usr/pnor/pnor_mboxdd.H (limited to 'src/usr/pnor') diff --git a/src/usr/pnor/HBconfig b/src/usr/pnor/HBconfig index 9ce13b13c..b256eaf00 100644 --- a/src/usr/pnor/HBconfig +++ b/src/usr/pnor/HBconfig @@ -1,24 +1,36 @@ +config PNORDD_IS_SFC + default y + depends on !PNORDD_IS_BMCMBOX + help + The Serial Flash Controller is based on the SFC backends + +config PNORDD_IS_BMCMBOX + default n + depends on !PNORDD_IS_SFC + help + The Serial Flash Controller is using the MBOX BMC protocol + config SFC_IS_IBM_DPSS default n - depends on !SFC_IS_AST2400 && !SFC_IS_FAKE && !SFC_IS_AST2500 + depends on !SFC_IS_AST2400 && !SFC_IS_FAKE && !SFC_IS_AST2500 && PNORDD_IS_SFC help The Serial Flash Controller is the IBM DPSS FPGA. config SFC_IS_AST2400 default y if !SFC_IS_AST2500 - depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE && !SFC_IS_AST2500 + depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE && !SFC_IS_AST2500 && PNORDD_IS_SFC help The Serial Flash Controller is the AST2400 BMC. config SFC_IS_AST2500 default n - depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE && !SFC_IS_AST2400 + depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE && !SFC_IS_AST2400 && PNORDD_IS_SFC help The Serial Flash Controller is the AST2500 BMC. config SFC_IS_FAKE default n - depends on !SFC_IS_IBM_DPSS && !SFC_IS_AST2400 && !SFC_IS_AST2500 + depends on !SFC_IS_IBM_DPSS && !SFC_IS_AST2400 && !SFC_IS_AST2500 && PNORDD_IS_SFC help The Serial Flash Controller is emulated using memory. 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ast_mboxdd.H" +#include +#include +#include +#include +#include +#include + +// 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(&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 ((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() +{ +} diff --git a/src/usr/pnor/ast_mboxdd.H b/src/usr/pnor/ast_mboxdd.H new file mode 100644 index 000000000..2d1aa48ad --- /dev/null +++ b/src/usr/pnor/ast_mboxdd.H @@ -0,0 +1,214 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/ast_mboxdd.H $ */ +/* */ +/* 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 */ +#ifndef __AST_MBOXDD_H +#define __AST_MBOXDD_H + +#include +#include + +/** @file ast_mboxdd.H + * @brief Provides the interfaces Aspeed MBOX hardware + */ + +/** + * @brief AST Mbox Device Driver Class + * Provides the interface to exchange Mbox + * messages with the BMC. + */ +class astMbox +{ + public: + + enum + { + BMC_MBOX_DATA_REGS = 14, + BMC_MBOX_ARGS_REGS = 11, + + /* Commands */ + MBOX_C_RESET_STATE = 0x01, + MBOX_C_GET_MBOX_INFO = 0x02, + MBOX_C_GET_FLASH_INFO = 0x03, + MBOX_C_CREATE_READ_WINDOW = 0x04, + MBOX_C_CLOSE_WINDOW = 0x05, + MBOX_C_CREATE_WRITE_WINDOW = 0x06, + MBOX_C_MARK_WRITE_DIRTY = 0x07, + MBOX_C_WRITE_FLUSH = 0x08, + MBOX_C_BMC_EVENT_ACK = 0x09, + MBOX_C_MARK_WRITE_ERASED = 0x0a, + + /* Responses */ + MBOX_R_SUCCESS = 0x01, + MBOX_R_PARAM_ERROR = 0x02, + MBOX_R_WRITE_ERROR = 0x03, + MBOX_R_SYSTEM_ERROR = 0x04, + MBOX_R_TIMEOUT = 0x05, + MBOX_R_BUSY = 0x06, + MBOX_R_WINDOW_ERROR = 0x07, + }; + + /** + * @brief AST Mbox message class. + * Encapsulates a mailbox message and provides + * accessors to read/write 8, 16 and 32-bit + * quantities in the right endianness at + * specified offsets of the "args" section. + */ + class mboxMessage + { + public: + + mboxMessage( uint8_t i_cmd ) + { + iv_cmd = i_cmd; + } + + uint8_t iv_cmd; + uint8_t iv_seq; + uint8_t iv_args[BMC_MBOX_ARGS_REGS]; + uint8_t iv_resp; + + inline uint8_t get8( uint8_t i_index ) + { + assert( i_index < BMC_MBOX_ARGS_REGS); + return iv_args[i_index]; + } + + inline void put8( uint8_t i_index, uint8_t i_value ) + { + assert( i_index < BMC_MBOX_ARGS_REGS); + iv_args[i_index] = i_value; + } + + inline uint16_t get16( uint8_t i_index ) + { + assert( i_index < (BMC_MBOX_ARGS_REGS - 1)); + return iv_args[i_index] | (iv_args[i_index + 1] << 8); + } + + inline void put16( uint8_t i_index, uint16_t i_value ) + { + assert( i_index < (BMC_MBOX_ARGS_REGS - 1)); + iv_args[i_index] = i_value & 0xff; + iv_args[i_index + 1] = i_value >> 8; + } + + inline uint32_t get32( uint8_t i_index ) + { + assert( i_index < (BMC_MBOX_ARGS_REGS - 3)); + return iv_args[i_index] | + (iv_args[i_index + 1] << 8) | + (iv_args[i_index + 2] << 16) | + (iv_args[i_index + 3] << 24); + } + + inline void put32( uint8_t i_index, uint32_t i_value ) + { + assert( i_index < (BMC_MBOX_ARGS_REGS - 3)); + iv_args[i_index] = i_value & 0xff; + iv_args[i_index + 1] = (i_value >> 8) & 0xff; + iv_args[i_index + 2] = (i_value >> 16) & 0xff; + iv_args[i_index + 3 ] = i_value >> 24; + } + }; + + /** + * @brief Send a message and receive the response + * + * @parm[in/out] io_msg Message to send, contains the response on exit + */ + errlHndl_t doMessage( mboxMessage& io_msg ); + + /** + * @brief Constructor + * + * @parm i_target Processor Target + * NOTE: i_target can only be used after targeting is loaded + */ + astMbox( TARGETING::Target* i_target = NULL ); + + /** + * @brief Destructor + */ + ~astMbox(); + + private: + + enum + { + MBOX_FLAG_REG = 0x0f, + MBOX_STATUS_0 = 0x10, + MBOX_STATUS_1 = 0x11, + MBOX_STATUS1_ATTN = 0x80, + MBOX_STATUS1_RESP = 0x20, + MBOX_BMC_CTRL = 0x12, + MBOX_CTRL_INT_STATUS = 0x80, + MBOX_CTRL_INT_MASK = 0x02, + MBOX_CTRL_INT_SEND = 0x01, + MBOX_HOST_CTRL = 0x13, + MBOX_BMC_INT_EN_0 = 0x14, + MBOX_BMC_INT_EN_1 = 0x15, + MBOX_HOST_INT_EN_0 = 0x16, + MBOX_HOST_INT_EN_1 = 0x17, + + MBOX_IO_BASE = 0x1000, + MBOX_LPC_IRQ = 0x9, + + MBOX_MAX_RESP_WAIT_US = 10000000, /* 10s timeout */ + }; + + /** + * @brief Initialize/Enable the MBox in the SIO + */ + errlHndl_t initializeMbox( void ); + + /** + * @brief Write a byte to the mBox + * + * @parm[in] i_addr: Register offset in the mbox + * @parm[in] i_byte: Byte to write + */ + errlHndl_t mboxOut( uint64_t i_addr, uint8_t i_byte ); + + /** + * @brief Read a byte from the mBox + * + * @parm[in] i_addr: Register offset in the mbox + * @parm[out] o_byte: Byte read + */ + errlHndl_t mboxIn( uint64_t i_addr, uint8_t& o_byte ); + + /** + * @brief Processor Target used to access LPC device + * + */ + TARGETING::Target* iv_target; + + /** + * @brief Sequence number for mailbox messages + */ + uint8_t iv_mboxMsgSeq; +}; + +#endif /* __AST_MBOXDD_H */ diff --git a/src/usr/pnor/makefile b/src/usr/pnor/makefile index b2c261a4b..d7609af13 100644 --- a/src/usr/pnor/makefile +++ b/src/usr/pnor/makefile @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2011,2016 +# Contributors Listed Below - COPYRIGHT 2011,2017 # [+] Google Inc. # [+] International Business Machines Corp. # @@ -30,7 +30,9 @@ MODULE = pnor OBJS += pnor_utils.o OBJS += pnorrp.o OBJS += $(if $(CONFIG_SECUREBOOT),spnorrp.o) -OBJS += pnordd.o +OBJS += $(if $(CONFIG_PNORDD_IS_SFC),pnordd.o) +OBJS += $(if $(CONFIG_PNORDD_IS_BMCMBOX),ast_mboxdd.o) +OBJS += $(if $(CONFIG_PNORDD_IS_BMCMBOX),pnor_mboxdd.o) OBJS += pnor_common.o OBJS += pnorvalid.o OBJS += ecc.o @@ -51,3 +53,4 @@ SUBDIRS += test.d SUBDIRS += runtime.d include ${ROOTPATH}/config.mk + diff --git a/src/usr/pnor/pnor_mboxdd.C b/src/usr/pnor/pnor_mboxdd.C new file mode 100644 index 000000000..4757ff120 --- /dev/null +++ b/src/usr/pnor/pnor_mboxdd.C @@ -0,0 +1,676 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/pnor_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ast_mboxdd.H" +#include "pnor_mboxdd.H" +#include "pnor_common.H" +#include +#include +#include +#include +#include +#include +#include +#include "sfcdd.H" + +// Initialized in pnorrp.C +extern trace_desc_t* g_trac_pnor; + +namespace PNOR +{ + +/** + * @brief Performs an PNOR Read Operation + * This function performs a PNOR Read operation. It follows a pre-defined + * prototype functions in order to be registered with the device-driver + * framework. + * + * @param[in] i_opType Operation type, see DeviceFW::OperationType + * in driverif.H + * @param[in] i_target PNOR target + * @param[in/out] io_buffer Read: Pointer to output data storage + * Write: Pointer to input data storage + * @param[in/out] io_buflen Input: size of io_buffer (in bytes) + * Output: + * Read: Size of output data + * Write: Size of data written + * @param[in] i_accessType DeviceFW::AccessType enum (usrif.H) + * @param[in] i_args This is an argument list for DD framework. + * In this function, there's only one argument, + * containing the PNOR address and chip select + * @return errlHndl_t + */ +errlHndl_t ddRead(DeviceFW::OperationType i_opType, + TARGETING::Target* i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + va_list i_args) +{ + errlHndl_t l_err = NULL; + uint64_t l_addr = va_arg(i_args, uint64_t); + + do + { + //@todo (RTC:36951) - add support for unaligned data + // Ensure we are operating on a 32-bit (4-byte) boundary + assert( reinterpret_cast(io_buffer) % 4 == 0 ); + assert( io_buflen % 4 == 0 ); + + // The PNOR device driver interface is initialized with the + // MASTER_PROCESSOR_CHIP_TARGET_SENTINEL. Other target + // access requires a separate PnorDD class created + assert( i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ); + + // Read the flash + l_err = Singleton::instance().readFlash(io_buffer, + io_buflen, + l_addr); + + if(l_err) + { + break; + } + + } + while(0); + + return l_err; +} + +/** + * @brief Performs an PNOR Write Operation + * This function performs a PNOR Write operation. It follows a pre-defined + * prototype functions in order to be registered with the device-driver + * framework. + * + * @param[in] i_opType Operation type, see DeviceFW::OperationType + * in driverif.H + * @param[in] i_target PNOR target + * @param[in/out] io_buffer Read: Pointer to output data storage + * Write: Pointer to input data storage + * @param[in/out] io_buflen Input: size of io_buffer (in bytes) + * Output: + * Read: Size of output data + * Write: Size of data written + * @param[in] i_accessType DeviceFW::AccessType enum (usrif.H) + * @param[in] i_args This is an argument list for DD framework. + * In this function, there's only one argument, + * containing the PNOR address and chip select + * @return errlHndl_t + */ +errlHndl_t ddWrite(DeviceFW::OperationType i_opType, + TARGETING::Target* i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + va_list i_args) +{ + errlHndl_t l_err = NULL; + uint64_t l_addr = va_arg(i_args, uint64_t); + + do + { + //@todo (RTC:36951) - add support for unaligned data + // Ensure we are operating on a 32-bit (4-byte) boundary + assert( reinterpret_cast(io_buffer) % 4 == 0 ); + assert( io_buflen % 4 == 0 ); + + // The PNOR device driver interface is initialized with the + // MASTER_PROCESSOR_CHIP_TARGET_SENTINEL. Other target + // access requires a separate PnorDD class created + assert( i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ); + + // Write the flash + l_err = Singleton::instance().writeFlash(io_buffer, + io_buflen, + l_addr); + + if(l_err) + { + break; + } + + } + while(0); + + return l_err; +} + +/** + * @brief Informs caller if the driver is using + * L3 Cache for fake PNOR or not. + * + * @return Indicate state of fake PNOR + * true = PNOR DD is using L3 Cache for fake PNOR + * false = PNOR DD not using L3 Cache for fake PNOR + */ +bool usingL3Cache() +{ + return false; +} + +/** + * @brief Retrieve some information about the PNOR/SFC hardware + */ +void getPnorInfo( PnorInfo_t& o_pnorInfo ) +{ + o_pnorInfo.mmioOffset = LPC_SFC_MMIO_OFFSET | LPC_FW_SPACE; + o_pnorInfo.norWorkarounds = + Singleton::instance().getNorWorkarounds(); + o_pnorInfo.flashSize = + Singleton::instance().getNorSize(); +} + + + +// Register MBOXDD access functions to DD framework +DEVICE_REGISTER_ROUTE(DeviceFW::READ, + DeviceFW::PNOR, + TARGETING::TYPE_PROC, + ddRead); + +DEVICE_REGISTER_ROUTE(DeviceFW::WRITE, + DeviceFW::PNOR, + TARGETING::TYPE_PROC, + ddWrite); + +}; //namespace PNOR + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +/** + * @brief Performs a PNOR Read Operation + */ +errlHndl_t PnorDD::readFlash(void* o_buffer, + size_t& io_buflen, + uint64_t i_address) +{ + /* We support 256M max */ + uint32_t l_address = i_address & 0x0fffffff; + + mutex_lock(iv_mutex_ptr); + errlHndl_t l_err = _readFlash( l_address, io_buflen, o_buffer ); + mutex_unlock(iv_mutex_ptr); + + return l_err; +} + +/** + * @brief Performs a PNOR Write Operation + */ +errlHndl_t PnorDD::writeFlash(const void* i_buffer, + size_t& io_buflen, + uint64_t i_address) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"PnorDD::writeFlash(i_address=0x%llx)> ", i_address); + errlHndl_t l_err = NULL; + + uint32_t l_address = i_address & 0x0fffffff; + + mutex_lock(iv_mutex_ptr); + l_err = _writeFlash( l_address, io_buflen, i_buffer ); + mutex_unlock(iv_mutex_ptr); + + if( l_err ) + { + io_buflen = 0; + } + + TRACFCOMP(g_trac_pnor, EXIT_MRK"PnorDD::writeFlash(i_address=0x%llx)> io_buflen=%.8X", i_address, io_buflen); + + return l_err; +} + + +/******************** + Private/Protected Methods + ********************/ +mutex_t PnorDD::cv_mutex = MUTEX_INITIALIZER; + +/** + * LPC FW space accessors + */ +errlHndl_t PnorDD::readLpcFw(uint32_t i_offset, size_t i_size, void* o_buf) +{ + // Exploit new LPC large read facility + return deviceOp(DeviceFW::READ, iv_target, o_buf, i_size, + DEVICE_LPC_ADDRESS(LPC::TRANS_FW, i_offset)); +} + +errlHndl_t PnorDD::writeLpcFw(uint32_t i_offset, size_t i_size, + const void* i_buf) +{ + // Exploit new LPC large write facility + return deviceOp(DeviceFW::WRITE, iv_target, (void*)i_buf, i_size, + DEVICE_LPC_ADDRESS(LPC::TRANS_FW, i_offset)); +} + +errlHndl_t PnorDD::adjustMboxWindow(bool i_isWrite, uint32_t i_reqAddr, + size_t i_reqSize, uint32_t& o_lpcAddr, + size_t& o_chunkLen) +{ + errlHndl_t l_err = NULL; + uint32_t l_pos, l_wSize, l_reqSize; + + do + { + /* + * Handle the case where the window is already opened, is of + * the right type and contains the requested address. + */ + uint32_t l_wEnd = iv_curWindowOffset + iv_curWindowSize; + + /* A read request can be serviced by a write window */ + if (iv_curWindowOpen && + (iv_curWindowWrite || !i_isWrite) && + i_reqAddr >= iv_curWindowOffset && i_reqAddr < l_wEnd) + { + size_t l_gap = (l_wEnd - i_reqAddr); + + o_lpcAddr = iv_curWindowLpcOffset +(i_reqAddr - iv_curWindowOffset); + o_chunkLen = std::min(i_reqSize, l_gap); + return NULL; + } + + /* + * We need a window change, mark it closed first + */ + iv_curWindowOpen = false; + + /* + * Then open the new one at the right position. The required + * alignment differs between protocol versions + */ + TRACFCOMP(g_trac_pnor, + "astMboxDD::adjustMboxWindow using protocol version: %d", + iv_protocolVersion); + if (iv_protocolVersion == 1) + { + l_wSize = i_isWrite ? iv_writeWindowSize : iv_readWindowSize; + l_pos = i_reqAddr & ~(l_wSize - 1); + l_reqSize = 0; + } + else + { + uint32_t l_blockMask = (1u << iv_blockShift) - 1; + l_wSize = 0; + l_pos = i_reqAddr & ~l_blockMask; + l_reqSize = (((i_reqAddr + i_reqSize) + l_blockMask) & ~l_blockMask) + - l_pos; + } + + TRACFCOMP(g_trac_pnor, "astMboxDD::adjustMboxWindow opening %s window at 0x%08x" + " for addr 0x%08x req_size 0x%08x", + i_isWrite ? "write" : "read", l_pos, i_reqAddr, l_reqSize); + + astMbox::mboxMessage winMsg(i_isWrite + ? astMbox::MBOX_C_CREATE_WRITE_WINDOW : + astMbox::MBOX_C_CREATE_READ_WINDOW); + winMsg.put16(0, l_pos >> iv_blockShift); + winMsg.put16(2, l_reqSize >> iv_blockShift); + l_err = iv_mbox->doMessage(winMsg); + + if (l_err) + { + break; + } + + iv_curWindowLpcOffset = winMsg.get16(0) << iv_blockShift; + + if (iv_protocolVersion == 1) + { + iv_curWindowOffset = l_pos; + iv_curWindowLpcOffset = winMsg.get16(0) << iv_blockShift; + iv_curWindowSize = l_wSize; + } + else + { + iv_curWindowLpcOffset = winMsg.get16(0) << iv_blockShift; + iv_curWindowSize = winMsg.get16(2) << iv_blockShift; + iv_curWindowOffset = winMsg.get16(4) << iv_blockShift; + } + + iv_curWindowOpen = true; + iv_curWindowWrite = i_isWrite; + + TRACFCOMP(g_trac_pnor, " curWindowOffset = %08x", iv_curWindowOffset); + TRACFCOMP(g_trac_pnor, " curWindowSize = %08x", iv_curWindowSize); + TRACFCOMP(g_trac_pnor, " curWindowLpcOffset = %08x", iv_curWindowLpcOffset); + + } + while (true); + + return l_err; +} + +errlHndl_t PnorDD::writeDirty(uint32_t i_addr, size_t i_size) +{ + /* To pass a correct "size" for both protocol versions, we + * calculate the block-aligned start and end. + */ + uint32_t l_blockMask = (1u << iv_blockShift) - 1; + uint32_t l_start = i_addr & ~l_blockMask; + uint32_t l_end = ((i_addr + i_size) + l_blockMask) & ~l_blockMask; + + astMbox::mboxMessage dirtyMsg(astMbox::MBOX_C_MARK_WRITE_DIRTY); + + if (iv_protocolVersion == 1) + { + dirtyMsg.put16(0, i_addr >> iv_blockShift); + dirtyMsg.put32(2, l_end - l_start); + } + else + { + dirtyMsg.put16(0, (i_addr - iv_curWindowOffset) >> iv_blockShift); + dirtyMsg.put16(2, (l_end - l_start) >> iv_blockShift); + } + + return iv_mbox->doMessage(dirtyMsg); +} + +errlHndl_t PnorDD::writeFlush(void) +{ + astMbox::mboxMessage flushMsg(astMbox::MBOX_C_WRITE_FLUSH); + + flushMsg.put16(0, 0); + flushMsg.put32(2, 0); + return iv_mbox->doMessage(flushMsg); +} + +/** + * @brief Write data to PNOR using Mbox LPC windows + */ +errlHndl_t PnorDD::_writeFlash( uint32_t i_addr, + size_t i_size, + const void* i_data ) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK"PnorDD::_writeFlash(i_addr=0x%.8X)> ", i_addr); + errlHndl_t l_err = NULL, l_flushErr = NULL; + + while (i_size) + { + uint32_t l_lpcAddr; + size_t l_chunkLen; + + l_err = adjustMboxWindow(true, i_addr, i_size, l_lpcAddr, l_chunkLen); + + if (l_err) + { + break; + } + + l_err = writeLpcFw(l_lpcAddr, l_chunkLen, i_data); + + if (l_err) + { + break; + } + + l_err = writeDirty(i_addr, l_chunkLen); + + if (l_err) + { + break; + } + + i_addr += l_chunkLen; + i_size -= l_chunkLen; + i_data = (char*)i_data + l_chunkLen; + } + + /* We flush whether we had an error or not. + * + * NOTE: It would help the daemon a lot if we moved that out of here + * and instead had a single flush call over a series of writes. + * + * @todo (RTC:173513) + * Investigate erasing & re-writing the same pages at least 3 times + * in a row during a boot. + */ + l_flushErr = writeFlush(); + + if ( l_err == NULL ) + { + l_err = l_flushErr; + } + else + { + delete l_flushErr; + l_flushErr = NULL; + } + + if( l_err ) + { + l_err->collectTrace(PNOR_COMP_NAME); + } + + return l_err; +} + +/** + * @brief Read data from PNOR using Mbox LPC windows + */ +errlHndl_t PnorDD::_readFlash( uint32_t i_addr, + size_t i_size, + void* o_data ) +{ + TRACFCOMP(g_trac_pnor, "PnorDD::_readFlash(i_addr=0x%.8X)> ", i_addr); + errlHndl_t l_err = NULL; + + while (i_size) + { + uint32_t l_lpcAddr; + size_t l_chunkLen; + + l_err = adjustMboxWindow(false, i_addr, i_size, l_lpcAddr, l_chunkLen); + + if (l_err) + { + break; + } + + l_err = readLpcFw(l_lpcAddr, l_chunkLen, o_data); + + if (l_err) + { + break; + } + + i_addr += l_chunkLen; + i_size -= l_chunkLen; + o_data = (char*)o_data + l_chunkLen; + } + + if( l_err ) + { + l_err->collectTrace(PNOR_COMP_NAME); + } + + return l_err; +} + +/** + * @brief Retrieve size of NOR flash + */ +uint32_t PnorDD::getNorSize( void ) +{ + return iv_flashSize; +} + +/** + * @brief Retrieve bitstring of NOR workarounds + */ +uint32_t PnorDD::getNorWorkarounds( void ) +{ + return 0; +} + +/** + * @brief Constructor + */ +PnorDD::PnorDD( TARGETING::Target* i_target ) +{ + TRACFCOMP(g_trac_pnor, ENTER_MRK "PnorDD::PnorDD()" ); + errlHndl_t l_err = NULL; + + // Use i_target if all of these apply + // 1) not NULL + // 2) not MASTER_PROCESSOR_CHIP_TARGET_SENTINEL + // 3) i_target does not correspond to Master processor (ie the + // same processor as MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) + // otherwise, use MASTER_PROCESSOR_CHIP_TARGET_SENTINEL + // NOTE: i_target can only be used when targeting is loaded + if ( ( i_target != NULL ) && + ( i_target != TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ) ) + { + + iv_target = i_target; + + // Check if processor is MASTER + TARGETING::ATTR_PROC_MASTER_TYPE_type type_enum = + iv_target->getAttr(); + + // Master target could collide and cause deadlocks with PnorDD singleton + // used for ddRead/ddWrite with MASTER_PROCESSOR_CHIP_TARGET_SENTINEL + assert( type_enum != TARGETING::PROC_MASTER_TYPE_ACTING_MASTER ); + + // Initialize and use class-specific mutex + iv_mutex_ptr = &iv_mutex; + mutex_init(iv_mutex_ptr); + TRACFCOMP(g_trac_pnor, "PnorDD::PnorDD()> Using i_target=0x%X (non-master) and iv_mutex_ptr", + TARGETING::get_huid(i_target)); + } + else + { + iv_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; + iv_mutex_ptr = &(cv_mutex); + } + + /* Instanciate MboxDD */ + iv_mbox = new astMbox(iv_target); + + iv_curWindowOpen = false; + + do + { + astMbox::mboxMessage mbInfoMsg(astMbox::MBOX_C_GET_MBOX_INFO); + + /* Initialize MBOX protocol, try protocol v2 */ + mbInfoMsg.put8(0, 2); + l_err = iv_mbox->doMessage(mbInfoMsg); + + if (l_err) + { + TRACFCOMP( g_trac_pnor, "Error getting MBOX info :: RC=%.4X", ERRL_GETRC_SAFE(l_err) ); + break; + } + + /* Check protocol */ + iv_protocolVersion = mbInfoMsg.get8(0); + + if (iv_protocolVersion == 1) + { + iv_blockShift = 12; + iv_readWindowSize = mbInfoMsg.get16(1) << iv_blockShift; + iv_writeWindowSize = mbInfoMsg.get16(3) << iv_blockShift; + } + else + { + iv_blockShift = mbInfoMsg.get8(5); + } + + TRACFCOMP( g_trac_pnor, "mboxPnor: protocolVersion=%d blockShift=%d", + iv_protocolVersion, iv_blockShift); + + /* Get flash info */ + astMbox::mboxMessage flInfoMsg(astMbox::MBOX_C_GET_FLASH_INFO); + l_err = iv_mbox->doMessage(flInfoMsg); + + if (l_err) + { + TRACFCOMP( g_trac_pnor, "Error getting flash info :: RC=%.4X", ERRL_GETRC_SAFE(l_err) ); + break; + } + + /* Intepretation changes with protocol v2 */ + if (iv_protocolVersion == 1) + { + iv_flashSize = flInfoMsg.get32(0); + iv_flashEraseSize = flInfoMsg.get32(4); + } + else + { + iv_flashSize = flInfoMsg.get16(0) << iv_blockShift; + iv_flashEraseSize = flInfoMsg.get16(2) << iv_blockShift; + } + + TRACFCOMP( g_trac_pnor, "mboxPnor: flashSize=0x%08x, eraseSize=0x%08x", + iv_blockShift, iv_flashSize, iv_flashEraseSize); + } + while(0); + + if( l_err ) + { + TRACFCOMP( g_trac_pnor, "Failure to initialize the PNOR 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 ); + } + + TRACFCOMP(g_trac_pnor, EXIT_MRK "PnorDD::PnorDD()" ); +} + +/** + * @brief Destructor + */ +PnorDD::~PnorDD() +{ +} diff --git a/src/usr/pnor/pnor_mboxdd.H b/src/usr/pnor/pnor_mboxdd.H new file mode 100644 index 000000000..e92b25f47 --- /dev/null +++ b/src/usr/pnor/pnor_mboxdd.H @@ -0,0 +1,258 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/pnor_mboxdd.H $ */ +/* */ +/* 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 */ +#ifndef __PNOR_MBOXDD_H +#define __PNOR_MBOXDD_H + +#include +#include +namespace PNOR +{ +class UdPnorDDParms; +} + +//NOTE: Protocol Definition is here: +// https://github.com/openbmc/mboxbridge/blob/master/Documentation/mbox_protocol.md + +class astMbox; + +/** @file pnor_mboxdd.H + * @brief Provides the interfaces to the PNOR via the + * MBOX protocol + */ + +/** + * @brief PNOR Device Driver Class + * Provides access to the PNOR flash via the LPC MBOX hardware + */ +class PnorDD +{ + + public: + /** + * @brief Performs a PNOR Read Operation + * + * @parm o_buffer Buffer to read data into + * @parm io_buflen Input: Number of bytes to read, + * Output: Number of bytes actually read + * @parm i_address Offset into flash to read + * + * @return Error from operation + */ + errlHndl_t readFlash(void* o_buffer, + size_t& io_buflen, + uint64_t i_address); + + /** + * @brief Performs a PNOR Write Operation + * + * @parm i_buffer Buffer to write data from + * @parm io_buflen Input: Number of bytes to write, + * Output: Number of bytes actually written + * @parm i_address Offset into flash to write + * + * @return Error from operation + */ + errlHndl_t writeFlash(const void* i_buffer, + size_t& io_buflen, + uint64_t i_address); + + /** + * @brief Informs caller if PNORDD is using + * L3 Cache for fake PNOR or not. + * + * @return Indicate state of fake PNOR + * true = PNOR DD is using L3 Cache for fake PNOR + * false = PNOR DD not using L3 Cache for fake PNOR + */ + bool usingL3Cache( ); + + /** + * @brief Retrieve size of NOR flash + * @return Size of PNOR in bytes + */ + uint32_t getNorSize( void ); + + /** + * @brief Retrieve bitstring of NOR workarounds + * @return NOR workarounds (see VendorWorkarounds in norflash.H) + */ + uint32_t getNorWorkarounds( void ); + + /** + * @brief Constructor + * + * @parm i_target Processor Target connected to PNOR + * NOTE: i_target can only be used after targeting is loaded + */ + PnorDD( TARGETING::Target* i_target = NULL ); + + /** + * @brief Destructor + */ + ~PnorDD(); + + protected: + + /** + * @brief Write data to PNOR using Mbox LPC windows + * @pre Mutex should already be locked before calling + * + * @parm[in] i_addr PNOR flash Address to write + * @parm[in] i_size Amount of data to write, in bytes. + * @parm[in] i_data Buffer containing data to write + * + * @return Error from operation + */ + errlHndl_t _writeFlash( uint32_t i_addr, + size_t i_size, + const void* i_data ); + + /** + * @brief Read data from PNOR using Mbox LPC windows + * @pre Mutex should already be locked before calling + * + * @parm[in] i_addr PNOR flash Address to read + * @parm[in] i_size Amount of data to read, in bytes. + * @parm[out] o_data Buffer to read data into + * + * @return Error from operation + */ + errlHndl_t _readFlash( uint32_t i_addr, + size_t i_size, + void* o_data ); + + /** + * @brief Open a window if necessary and return adjusted + * LPC address and chunk size + * @parm[in] i_isWrite Write or read window + * @parm[in] i_reqAddr Requested flash offset + * @parm[in] i_reqSize Requested size + * @parm[out] o_lpcAddr LPC offset for the requested offset + * @parm[out] o_chunkLen i_reqSize adjusted to fit in the window + * + * @return Error from operation + */ + errlHndl_t adjustMboxWindow(bool i_isWrite, + uint32_t i_reqAddr, + size_t i_reqSize, + uint32_t& o_lpcAddr, + size_t& o_chunkLen); + + /** + * @brief Mark a range dirty in a write window + * @parm[in] i_addr Flash offset of the range + * @parm[in] i_size Size of the range + * + * @return Error from operation + */ + errlHndl_t writeDirty(uint32_t i_addr, size_t i_size); + + /** + * @brief Flush all pending dirty data to the flash + * + * @return Error from operation + */ + errlHndl_t writeFlush(void); + + /** + * @brief Read from LPC FW space + * + * @parm[in] i_offset LPC offset + * @parm[in] i_size Size to read + * @parm[out] o_buf Output buffer + * + * @return Error from operation + */ + + errlHndl_t readLpcFw(uint32_t i_offset, size_t i_size, void* o_buf); + /** + * @brief Write to LPC FW space + * + * @parm[in] i_offset LPC offset + * @parm[in] i_size Size to read + * @parm[in] i_buf Input buffer + * + * @return Error from operation + */ + errlHndl_t writeLpcFw(uint32_t i_offset, + size_t i_size, + const void* i_buf); + + private: // Variables + + astMbox* iv_mbox; + uint32_t iv_protocolVersion; + //Block size is either 4k (V1) or BMC defined (V2) + // the iv_blockShift parm is a representation of that size + // as a power of 2. Most command and response args are specified + // in some multiple of block size + uint32_t iv_blockShift; + uint32_t iv_flashSize; + uint32_t iv_flashEraseSize; + + // Current window + bool iv_curWindowOpen; // Currently open + bool iv_curWindowWrite; // Write vs Read window + uint32_t iv_curWindowOffset; // Offset into flash + uint32_t iv_curWindowSize; // Size + uint32_t iv_curWindowLpcOffset; // Offset into LPC FW space + + // Legacy v1 protocol + uint32_t iv_readWindowSize; + uint32_t iv_writeWindowSize; + + /** + * @brief Global Mutex to prevent concurrent PNOR accesses to Master + * Proc. This needs to be static so we can mutex across multiple + * instances of PnorDD + */ + static mutex_t cv_mutex; + + /** + * @brief Class Mutex used to prevent concurrent PNOR accesses + */ + mutex_t iv_mutex; + + /** + * @brief Mutex pointer to either class-specific or global mutex to + * prevent concurrent PNOR accesses. + * Each class uses a mutex; some share the static cv_mutex + */ + mutex_t* iv_mutex_ptr; + + /** + * @brief Processor Target used to access PNOR device + * + */ + TARGETING::Target* iv_target; + + // Needed for testcases + friend class PnorDdTest; + + // let the UserDetails classes see internal structures + friend class PNOR::UdPnorDDParms; +}; + +#endif /* __PNOR_MBOXDD_H */ diff --git a/src/usr/pnor/pnordd.H b/src/usr/pnor/pnordd.H index 437a0c10e..e82cf5005 100644 --- a/src/usr/pnor/pnordd.H +++ b/src/usr/pnor/pnordd.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -28,6 +28,8 @@ #include #include +#include + namespace PNOR { class UdPnorDDParms; } class SfcDD; @@ -94,16 +96,6 @@ class PnorDD */ uint32_t getNorSize( void ); - - // Enumeration values must match those in debug framework. - enum PnorMode_t { - MODEL_UNKNOWN, /**< Invalid */ - MODEL_MEMCPY, /**< No LPC logic, just do memcpy into cache area */ - MODEL_LPC_MEM, /**< Break into 32-bit LPC ops but use fake-PNOR */ - MODEL_REAL_CMD, /**< Code for real HW using Command based reads */ - MODEL_REAL_MMIO, /**< Code for real hardware using MMIO reads */ - }; - /** * @brief Constructor * @@ -112,7 +104,6 @@ class PnorDD */ PnorDD( TARGETING::Target* i_target = NULL ); - /** * @brief Destructor */ diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C index 52ba22b57..6d56efa8c 100644 --- a/src/usr/pnor/pnorrp.C +++ b/src/usr/pnor/pnorrp.C @@ -37,7 +37,6 @@ #include #include #include -#include "pnordd.H" #include "ffs.h" //Common header file with BuildingBlock. #include "common/ffs_hb.H"//Hostboot definition of user data in ffs_entry struct #include diff --git a/src/usr/pnor/pnorvalid.C b/src/usr/pnor/pnorvalid.C index 46204caac..58e3f71e0 100644 --- a/src/usr/pnor/pnorvalid.C +++ b/src/usr/pnor/pnorvalid.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2014,2015 */ +/* Contributors Listed Below - COPYRIGHT 2014,2017 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -44,10 +44,14 @@ #include "ffs.h" #include "common/ffs_hb.H" #include "pnorrp.H" -#include "pnordd.H" #include #include #include +#ifdef CONFIG_PNORDD_IS_SFC +#include "pnordd.H" +#else +#include "pnor_mboxdd.H" +#endif // Used for creating an Invalid TOC ("PNOR") diff --git a/src/usr/pnor/test/pnorddtest.H b/src/usr/pnor/test/pnorddtest.H index eb1fa793e..eb444e53d 100644 --- a/src/usr/pnor/test/pnorddtest.H +++ b/src/usr/pnor/test/pnorddtest.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -40,7 +40,11 @@ #include #include #include +#ifdef CONFIG_PNORDD_IS_SFC #include "../pnordd.H" +#else +#include "../pnor_mboxdd.H" +#endif #include "../pnorrp.H" #include #include -- cgit v1.2.1