summaryrefslogtreecommitdiffstats
path: root/src/usr/mbox/mboxdd.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/mbox/mboxdd.C')
-rw-r--r--src/usr/mbox/mboxdd.C541
1 files changed, 541 insertions, 0 deletions
diff --git a/src/usr/mbox/mboxdd.C b/src/usr/mbox/mboxdd.C
new file mode 100644
index 000000000..441925fd1
--- /dev/null
+++ b/src/usr/mbox/mboxdd.C
@@ -0,0 +1,541 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/mbox/mboxdd.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#include "mboxdd.H"
+#include <mbox/mboxif.H>
+#include <mbox/mbox_reasoncodes.H>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <targeting/targetservice.H>
+
+trace_desc_t* g_trac_mbox = NULL;
+TRAC_INIT(&g_trac_mbox, "MBOX", 4096); //4K
+
+//TODO - May or may not be necessary for MBOX error logs
+uint64_t target_to_uint64(const TARGETING::Target* i_target)
+{
+ uint64_t id = 0;
+ if( i_target == NULL )
+ {
+ id = 0x0;
+ }
+ else if( i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL )
+ {
+ id = 0xFFFFFFFFFFFFFFFF;
+ }
+ else
+ {
+ // physical path, 3 nibbles per type/instance pair
+ // TIITIITII... etc.
+ TARGETING::EntityPath epath;
+ i_target->tryGetAttr<TARGETING::ATTR_PHYS_PATH>(epath);
+ for( uint32_t x = 0; x < epath.size(); x++ )
+ {
+ id = id << 12;
+ id |= (uint64_t)((epath[x].type << 8) & 0xF00);
+ id |= (uint64_t)(epath[x].instance & 0x0FF);
+ }
+ }
+ return id;
+}
+
+namespace MBOX
+{
+
+/**
+ * @brief Performs an MBOX Read Operation
+ * This function performs a MBOX 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 MBOX 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 (userif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ *
+ * @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* o_status = va_arg(i_args,uint64_t*);
+
+ do
+ {
+ l_err = Singleton<MboxDD>::instance().read(i_target,io_buffer,
+ io_buflen,o_status);
+ if (l_err)
+ {
+ break;
+ }
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Performs an MBOX Write Operation
+ * This function performs a MBOX 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 MBOX 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 (userif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ *
+ * @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;
+
+ do
+ {
+ l_err = Singleton<MboxDD>::instance().write(i_target,io_buffer,
+ io_buflen);
+ if(l_err)
+ {
+ break;
+ }
+ } while(0);
+
+ return l_err;
+}
+
+// Register MBOXDD access functions to DD framework
+DEVICE_REGISTER_ROUTE(DeviceFW::READ,
+ DeviceFW::MAILBOX,
+ TARGETING::TYPE_PROC,
+ ddRead);
+
+DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
+ DeviceFW::MAILBOX,
+ TARGETING::TYPE_PROC,
+ ddWrite);
+
+}; //end MBOX namespace
+
+/**
+ * @brief Performs a mailbox read operation
+ */
+errlHndl_t MboxDD::read(TARGETING::Target* i_target,void *o_buffer,
+ size_t &io_buflen,uint64_t* o_status)
+{
+ uint64_t l_stat = 0;
+ errlHndl_t l_err = NULL;
+ uint32_t l_64bitBuf[2] = {0};
+ uint32_t l_IntReg[2] = {0};
+ size_t l_64bitSize = sizeof(uint64_t);
+
+ do
+ {
+ if (MBOX::MBOX_MAX_DATA_BYTES < io_buflen)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::read> Invalid data length : io_buflen=%d", io_buflen);
+ /*@
+ * @errortype
+ * @moduleid MBOX::MOD_MBOXDD_READ
+ * @reasoncode MBOX::RC_INVALID_LENGTH
+ * @userdata1 Target ID String...
+ * @userdata2 Data Length
+ * @devdesc MboxDD::read> Invalid data length (< msg_t size)
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MBOX::MOD_MBOXDD_READ,
+ MBOX::RC_INVALID_LENGTH,
+ target_to_uint64(i_target),
+ TO_UINT64(io_buflen));
+ l_err->collectTrace("MBOX",1024);
+ break;
+ }
+
+ l_err = deviceOp(DeviceFW::READ,i_target,
+ l_IntReg,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_REG_PIB));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::read> Unable to read PIB Interrupt Register");
+ break;
+ }
+ if ((l_IntReg[0] & MBOX::MBOX_DOORBELL_ERROR) ==
+ MBOX::MBOX_DOORBELL_ERROR)
+ {
+ TRACFCOMP(g_trac_mbox, INFO_MRK "MBOX::read> Found interrupt on error status register");
+ l_err = getErrStat(i_target,l_stat);
+ if (l_err)
+ {
+ break;
+ }
+ }
+
+ l_err = deviceOp(DeviceFW::READ,i_target,
+ l_64bitBuf,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::read> Unable to read Doorbell Status/Control Register");
+ break;
+ }
+ /*
+ * DB_STATUS_1A_REG: doorbell status and control 1a
+ * Bit31(MSB) : Permission to Send Doorbell 1
+ * Bit30 : Abort Doorbell 1
+ * Bit29 : PIB Slave B Pending Doorbell 1
+ * Bit28 : LBUS Slave A Pending Doorbell 1
+ * Bit27 : Reserved
+ * Bit26 : Xdn Doorbell 1
+ * Bit25 : Xup Doorbell 1
+ * Bit24 : Reserved
+ * Bit23-20 : Header Count LBUS Slave A Doorbell 1
+ * Bit19-12 : Data Count LBUS Slave A Doorbell 1
+ * Bit11-8 : Header Count PIB Slave B Doorbell 1
+ * Bit7-0 : Data Count PIB Slave B Doorbell 1
+ */
+ //Check for Abort
+ if ((l_IntReg[0] & MBOX::MBOX_ABORT_LAST_MSG) ==
+ MBOX::MBOX_ABORT_LAST_MSG &&
+ (l_64bitBuf[0] & 0x40000000) == 0x40000000)
+ {
+ l_stat |= MBOX::MBOX_ABORT_LAST_MSG;
+ }
+ //Check for Xdn
+ if ((l_IntReg[0] & MBOX::MBOX_XDN_ACK) ==
+ MBOX::MBOX_XDN_ACK &&
+ (l_64bitBuf[0] & 0x04000000) == 0x04000000)
+ {
+ l_stat |= MBOX::MBOX_XDN_ACK;
+ }
+ //Check for PIB Pending
+ if ((l_IntReg[0] & MBOX::MBOX_DATA_PENDING) ==
+ MBOX::MBOX_DATA_PENDING &&
+ (l_64bitBuf[0] & 0x20000000) == 0x20000000)
+ {
+ l_stat |= MBOX::MBOX_DATA_PENDING;
+ //Read how many bytes are significant
+ if (io_buflen < ((l_64bitBuf[0] & 0x000FF000) >> 12))
+ {
+ TRACFCOMP(g_trac_mbox, INFO_MRK "MBOX::read> Data truncated, input buffer length less than number of significant bytes");
+ }
+ uint32_t i = 0;
+ uint32_t l_data[2];
+ uint8_t l_numRegs = (io_buflen*sizeof(uint8_t))/sizeof(uint32_t);
+ if ((io_buflen*sizeof(uint8_t))%sizeof(uint32_t) != 0) l_numRegs++;
+ uint8_t *l_buf = static_cast<uint8_t *>(o_buffer);
+ //Extract Data
+ while (i < l_numRegs)
+ {
+ l_err = deviceOp(DeviceFW::READ,i_target,
+ l_data,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DATA_LBUS_START+i));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::read> Unable to read Data Area Register 0x%X",MBOX_DATA_LBUS_START+i);
+ break;
+ }
+ //TODO Use memcpy() since byte aligned?
+ for (uint8_t byteNum = 0;byteNum<sizeof(uint32_t);++byteNum)
+ {
+ *(l_buf+(byteNum+i*sizeof(uint32_t))) =
+ (l_data[0]>>(sizeof(uint32_t)*8-(byteNum+1)*8) & 0x000000FF);
+ }
+ i++;
+ }
+ if (l_err)
+ {
+ break;
+ }
+
+ //Write-to-Clear PIB Pending,Xup,and bits 23-12
+ l_64bitBuf[0] = 0x22FFF000;
+ l_err = deviceOp(DeviceFW::WRITE,i_target,
+ l_64bitBuf,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::read> Unable to clear Doorbell Status/Control Register");
+ break;
+ }
+ }
+
+ //Write-to-Clear 'on' bits of interrupt reg
+ l_err = deviceOp(DeviceFW::WRITE,i_target,
+ l_IntReg,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_REG_PIB));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::read> Unable to clear PIB Interrupt Register");
+ break;
+ }
+ (*o_status) = l_stat;
+
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Performs a mailbox write operation
+ */
+errlHndl_t MboxDD::write(TARGETING::Target* i_target,void* i_buffer,
+ size_t& i_buflen)
+{
+ errlHndl_t l_err = NULL;
+ uint32_t l_64bitBuf[2] = {0};
+ size_t l_64bitSize = sizeof(uint64_t);
+
+ do
+ {
+ //Expect size in bytes
+ if (i_buflen > MBOX::MBOX_MAX_DATA_BYTES)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Invalid data length : i_buflen=%d", i_buflen);
+ /*@
+ * @errortype
+ * @moduleid MBOX::MOD_MBOXDD_WRITE
+ * @reasoncode MBOX::RC_INVALID_LENGTH
+ * @userdata1 Target ID String...
+ * @userdata2 Data Length
+ * @devdesc MboxDD::write> Invalid data length (> msg_t size)
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MBOX::MOD_MBOXDD_WRITE,
+ MBOX::RC_INVALID_LENGTH,
+ target_to_uint64(i_target),
+ TO_UINT64(i_buflen));
+ l_err->collectTrace("MBOX",1024);
+ break;
+ }
+
+ l_err = deviceOp(DeviceFW::READ,i_target,
+ l_64bitBuf,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Unable to read Doorbell Status/Control Register");
+ break;
+ }
+
+ /*
+ * DB_STATUS_1A_REG: doorbell status and control 1a
+ * Bit31(MSB) : Permission to Send Doorbell 1
+ * Bit30 : Abort Doorbell 1
+ * Bit29 : PIB Slave B Pending Doorbell 1
+ * Bit28 : LBUS Slave A Pending Doorbell 1
+ * Bit27 : Reserved
+ * Bit26 : Xdn Doorbell 1
+ * Bit25 : Xup Doorbell 1
+ * Bit24 : Reserved
+ * Bit23-20 : Header Count LBUS Slave A Doorbell 1
+ * Bit19-12 : Data Count LBUS Slave A Doorbell 1
+ * Bit11-8 : Header Count PIB Slave B Doorbell 1
+ * Bit7-0 : Data Count PIB Slave B Doorbell 1
+ */
+ //Verify Permission-to-Send
+ if ((l_64bitBuf[0] & 0x80000000) == 0x80000000)
+ {
+ //Verify LBUS Pending,
+ if ((l_64bitBuf[0] & 0x10000FFF) == 0)
+ {
+ uint32_t i = 0;
+ uint32_t l_data[2] = {0};
+ uint8_t l_numRegs = (i_buflen*sizeof(uint8_t))/sizeof(uint32_t);
+ if ((i_buflen*sizeof(uint8_t))%sizeof(uint32_t) != 0) l_numRegs++;
+ uint32_t *l_buf = static_cast<uint32_t *>(i_buffer);
+ //Write Data registers
+ while (i < l_numRegs)
+ {
+ l_data[0] = *(l_buf+i);
+ l_err = deviceOp(DeviceFW::WRITE,i_target,
+ l_data,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DATA_PIB_START+i));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Unable to write Data Area Register 0x%X",MBOX_DATA_PIB_START+i);
+ break;
+ }
+ i++;
+ }
+ if (l_err)
+ {
+ break;
+ }
+
+ //Write LBUS Pending(28) and Data Count bits(11-0)
+ l_64bitBuf[0] = 0x10000000 | i_buflen;
+ l_err = deviceOp(DeviceFW::WRITE,i_target,
+ l_64bitBuf,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Unable to set Doorbell Status/Control Register");
+ break;
+ }
+ }
+ else
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Message still pending : MBOX_DB_STAT_CNTRL_1=%X", l_64bitBuf[0]);
+ /*@
+ * @errortype
+ * @moduleid MBOX::MOD_MBOXDD_WRITE
+ * @reasoncode MBOX::RC_MSG_PENDING
+ * @userdata1 Target ID String...
+ * @userdata2 Status/Control Register
+ * @devdesc MboxDD::write> Message still pending
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MBOX::MOD_MBOXDD_WRITE,
+ MBOX::RC_MSG_PENDING,
+ target_to_uint64(i_target),
+ reinterpret_cast<uint64_t>(l_64bitBuf));
+ l_err->collectTrace("MBOX",1024);
+ break;
+ }
+ }
+ else
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Permission-to-Send bit not set : MBOX_DB_STAT_CNTRL_1=%X", l_64bitBuf[0]);
+ /*@
+ * @errortype
+ * @moduleid MBOX::MOD_MBOXDD_WRITE
+ * @reasoncode MBOX::RC_NO_PERM_TO_SEND
+ * @userdata1 Target ID String...
+ * @userdata2 Status/Control Register
+ * @devdesc MboxDD::write> Permission-to-Send not set
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MBOX::MOD_MBOXDD_WRITE,
+ MBOX::RC_NO_PERM_TO_SEND,
+ target_to_uint64(i_target),
+ reinterpret_cast<uint64_t>(l_64bitBuf));
+ l_err->collectTrace("MBOX",1024);
+ break;
+ }
+
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Reads the mailbox PIB error status register
+ */
+errlHndl_t MboxDD::getErrStat(TARGETING::Target* i_target,uint64_t &o_status)
+{
+ errlHndl_t l_err = NULL;
+ uint32_t l_64bitBuf[2] = {0};
+ size_t l_64bitSize = sizeof(uint64_t);
+
+ do
+ {
+ l_err = deviceOp(DeviceFW::READ,i_target,
+ l_64bitBuf,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_ERR_STAT_PIB));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::getErrStat> Unable to read PIB Error Status");
+ break;
+ }
+ else
+ {
+ //Check for Illegal Op
+ if ((l_64bitBuf[0] & MBOX::MBOX_ILLEGAL_OP) ==
+ MBOX::MBOX_ILLEGAL_OP)
+ {
+ o_status |= MBOX::MBOX_ILLEGAL_OP;
+ }
+ //Check for Write Full
+ if ((l_64bitBuf[0] & MBOX::MBOX_DATA_WRITE_ERR) ==
+ MBOX::MBOX_DATA_WRITE_ERR)
+ {
+ o_status |= MBOX::MBOX_DATA_WRITE_ERR;
+ }
+ //Check for Read Empty
+ if ((l_64bitBuf[0] & MBOX::MBOX_DATA_READ_ERR) ==
+ MBOX::MBOX_DATA_READ_ERR)
+ {
+ o_status |= MBOX::MBOX_DATA_READ_ERR;
+ }
+ //Check for Parity Error & add address of parity error
+ if ((l_64bitBuf[0] & MBOX::MBOX_PARITY_ERR) ==
+ MBOX::MBOX_PARITY_ERR)
+ {
+ o_status |= MBOX::MBOX_PARITY_ERR;
+ uint64_t l_temp = (l_64bitBuf[0] & 0x00FF0000);
+ o_status |= (l_temp << 40);
+ }
+ }
+ //Write '1' to Clear Status(16)
+ l_64bitBuf[0] = 0x00010000;
+ l_err = deviceOp(DeviceFW::WRITE,i_target,
+ l_64bitBuf,l_64bitSize,
+ DEVICE_XSCOM_ADDRESS(MBOX_DB_ERR_STAT_PIB));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::getErrStat> Unable to clear PIB Error Status");
+ break;
+ }
+
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Constructor
+ */
+MboxDD::MboxDD()
+{
+ TRACFCOMP(g_trac_mbox, "MboxDD::MboxDD()> ");
+}
+
+/**
+ * @brief Destructor
+ */
+MboxDD::~MboxDD()
+{
+}
OpenPOWER on IntegriCloud