summaryrefslogtreecommitdiffstats
path: root/src/usr/pnor
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <bherren@au1.ibm.com>2017-04-07 16:39:53 +1000
committerMatthew A. Ploetz <maploetz@us.ibm.com>2017-05-01 19:23:06 -0400
commitb4eb096bd19d6b4aee4aa87424818bff1d5605eb (patch)
tree1810a26913a5a0a6a6ecb0609cea9d26f902e785 /src/usr/pnor
parent863b78e70f9b11e9948c380e1d5cd5790d8d9962 (diff)
downloadtalos-hostboot-b4eb096bd19d6b4aee4aa87424818bff1d5605eb.tar.gz
talos-hostboot-b4eb096bd19d6b4aee4aa87424818bff1d5605eb.zip
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 <benh@kernel.crashing.org> RTC: 170096 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39387 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: Dean Sanner <dsanner@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: Matthew A. Ploetz <maploetz@us.ibm.com>
Diffstat (limited to 'src/usr/pnor')
-rw-r--r--src/usr/pnor/HBconfig20
-rw-r--r--src/usr/pnor/ast_mboxdd.C486
-rw-r--r--src/usr/pnor/ast_mboxdd.H214
-rw-r--r--src/usr/pnor/makefile7
-rw-r--r--src/usr/pnor/pnor_mboxdd.C676
-rw-r--r--src/usr/pnor/pnor_mboxdd.H258
-rw-r--r--src/usr/pnor/pnordd.H15
-rw-r--r--src/usr/pnor/pnorrp.C1
-rw-r--r--src/usr/pnor/pnorvalid.C8
-rw-r--r--src/usr/pnor/test/pnorddtest.H6
10 files changed, 1669 insertions, 22 deletions
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 <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()
+{
+}
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 <limits.h>
+#include <config.h>
+
+/** @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 <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_mboxdd.H"
+#include "pnor_common.H"
+#include <pnor/pnorif.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>
+#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<uint64_t>(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<PnorDD>::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<uint64_t>(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<PnorDD>::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<PnorDD>::instance().getNorWorkarounds();
+ o_pnorInfo.flashSize =
+ Singleton<PnorDD>::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<TARGETING::ATTR_PROC_MASTER_TYPE>();
+
+ // 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 <limits.h>
+#include <config.h>
+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 <limits.h>
#include <config.h>
+#include <pnor/pnor_const.H>
+
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 <sys/mm.h>
#include <errno.h>
#include <initservice/initserviceif.H>
-#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 <pnor/ecc.H>
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 <pnor/pnorif.H>
#include <pnor/pnor_reasoncodes.H>
#include <lpc/lpcif.H>
+#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 <devicefw/userif.H>
#include <kernel/console.H>
#include <sys/time.h>
+#ifdef CONFIG_PNORDD_IS_SFC
#include "../pnordd.H"
+#else
+#include "../pnor_mboxdd.H"
+#endif
#include "../pnorrp.H"
#include <list>
#include <targeting/common/attributes.H>
OpenPOWER on IntegriCloud