summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDan Crowell <dcrowell@us.ibm.com>2011-09-08 16:08:26 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2011-10-05 12:49:57 -0500
commit336f6ac6abc1d5ee4efc1229be06a66baf06643b (patch)
treee3476d2423567ad81249cc215d195dbc36c4a04f /src
parent485bb5c0e6d2c7c5df6560a996dc264e94f2058a (diff)
downloadtalos-hostboot-336f6ac6abc1d5ee4efc1229be06a66baf06643b.tar.gz
talos-hostboot-336f6ac6abc1d5ee4efc1229be06a66baf06643b.zip
Initialize the FSI hardware - Story 3551
This code will initialize the FSI hardware and allow access to remote slaves. Note - current code is hardcoded to using the MFSI-0 port on the master processor wrapped back into its own CFAM. Note2 - One testcase is disabled pending integration of required fixes to the simics models. Contains work for - Task 3830 : FSI Master Regs - Task 3831 : FSI Slave Regs Change-Id: I8dd5f0e03cf083e35cf8241db22ad6d76ba85fac Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/359 Tested-by: Jenkins Server Reviewed-by: Thi N. Tran <thi@us.ibm.com> Reviewed-by: ADAM R. MUHLE <armuhle@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/usr/devicefw/driverif.H1
-rw-r--r--src/include/usr/devicefw/userif.H1
-rw-r--r--src/include/usr/fsi/fsi_reasoncodes.H10
-rw-r--r--src/include/usr/fsi/fsiif.H74
-rw-r--r--src/usr/fsi/fsidd.C937
-rw-r--r--src/usr/fsi/fsidd.H296
-rw-r--r--src/usr/fsi/test/fsiddtest.H79
7 files changed, 1056 insertions, 342 deletions
diff --git a/src/include/usr/devicefw/driverif.H b/src/include/usr/devicefw/driverif.H
index 82125c014..a7139db19 100644
--- a/src/include/usr/devicefw/driverif.H
+++ b/src/include/usr/devicefw/driverif.H
@@ -44,7 +44,6 @@ namespace DeviceFW
enum AccessType_DriverOnly
{
XSCOM = LAST_ACCESS_TYPE,
- FSI,
I2C,
FSISCOM,
diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H
index a71a7b4cb..adb46a418 100644
--- a/src/include/usr/devicefw/userif.H
+++ b/src/include/usr/devicefw/userif.H
@@ -46,6 +46,7 @@ namespace DeviceFW
PNOR,
MAILBOX,
PRESENT,
+ FSI,
LAST_ACCESS_TYPE,
};
diff --git a/src/include/usr/fsi/fsi_reasoncodes.H b/src/include/usr/fsi/fsi_reasoncodes.H
index a82da1133..24442062e 100644
--- a/src/include/usr/fsi/fsi_reasoncodes.H
+++ b/src/include/usr/fsi/fsi_reasoncodes.H
@@ -32,10 +32,12 @@ namespace FSI
MOD_FSIDD_INVALID = 0x00, /**< Zero is an invalid module id */
MOD_FSIDD_WRITE = 0x01, /**< fsidd.C : FsiDD::write */
MOD_FSIDD_READ = 0x02, /**< fsidd.C : FsiDD::read */
- MOD_FSIDD_VERIFYADDRESSRANGE = 0x03, /**< fsidd.C : verifyAddressRange */
- MOD_FSIDD_HANDLEOPBERRORS = 0x04, /**< fsidd.C : handleOpbErrors */
+ MOD_FSIDD_VERIFYADDRESSRANGE = 0x03, /**< fsidd.C : FsiDD::verifyAddressRange */
+ MOD_FSIDD_HANDLEOPBERRORS = 0x04, /**< fsidd.C : FsiDD::handleOpbErrors */
MOD_FSIDD_DDREAD = 0x05, /**< fsidd.C : ddRead */
MOD_FSIDD_DDWRITE = 0x06, /**< fsidd.C : ddWrite */
+ MOD_FSIDD_INITPORT = 0x07, /**< fsidd.C : FsiDD::initPort */
+ MOD_FSIDD_POLLFORCOMPLETE = 0x08, /**< fsidd.C : FsiDD::pollForComplete */
};
enum FSIReasonCode
@@ -44,7 +46,9 @@ namespace FSI
RC_INVALID_ADDRESS = FSI_COMP_ID | 0x02,
RC_OPB_TIMEOUT = FSI_COMP_ID | 0x03,
RC_OPB_ERROR = FSI_COMP_ID | 0x04,
- RC_INVALID_TARGET = FSI_COMP_ID | 0x05,
+ RC_INVALID_TARGET = FSI_COMP_ID | 0x05,
+ RC_OPB_NO_READ_VALID = FSI_COMP_ID | 0x06,
+ RC_ERROR_ENABLING_SLAVE = FSI_COMP_ID | 0x07,
};
};
diff --git a/src/include/usr/fsi/fsiif.H b/src/include/usr/fsi/fsiif.H
new file mode 100644
index 000000000..3c366fd9d
--- /dev/null
+++ b/src/include/usr/fsi/fsiif.H
@@ -0,0 +1,74 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/include/usr/fsi/fsiif.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// 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
+
+#ifndef __FSI_FSIIF_H
+#define __FSI_FSIIF_H
+
+#include <stdint.h>
+#include <builtins.h>
+#include <errl/errlentry.H>
+
+namespace FSI
+{
+
+/**
+ * Master or Cascaded Master
+ */
+enum MasterType {
+ MFSI_TYPE = 0,
+ CMFSI_TYPE = 1,
+ NO_MASTER = 2
+};
+
+
+//@todo - move this into attributes
+/**
+ * @brief Structure which defines info necessary to access a chip via FSI
+ *
+ * Structure which defines info necessary for FSI access. Only applicable
+ * for chip targets. Structure is read-only. Each chip will have 2 copies
+ * of this data, depending on which chip we boot from.
+ */
+struct FsiChipInfo_t
+{
+ TARGETING::Target* master; ///< FSI Master @fixme - convert to EntityPath
+ MasterType type; ///< Master or Cascaded Master
+ uint8_t port; ///< Which port is this chip hanging off of
+ uint8_t cascade; ///< Slave cascade position
+ uint64_t attributes; ///< Reserved for any special flags we might need
+};
+
+/**
+ * @brief Initialize the FSI hardware
+ *
+ * @param[out] o_numPorts Number of FSI ports that were
+ * successfully initialized
+ *
+ * @return errlHndl_t NULL on success
+ */
+errlHndl_t initializeHardware( uint64_t& o_numPorts );
+
+
+}
+
+#endif
diff --git a/src/usr/fsi/fsidd.C b/src/usr/fsi/fsidd.C
index 4333aed57..13beea3eb 100644
--- a/src/usr/fsi/fsidd.C
+++ b/src/usr/fsi/fsidd.C
@@ -29,18 +29,21 @@
/*****************************************************************************/
// I n c l u d e s
/*****************************************************************************/
-#include <string.h>
+#include "fsidd.H"
+#include <fsi/fsi_reasoncodes.H>
#include <devicefw/driverif.H>
#include <trace/interface.H>
#include <errl/errlentry.H>
#include <targeting/targetservice.H>
#include <errl/errlmanager.H>
-#include <fsi/fsi_reasoncodes.H>
-#include "fsidd.H"
-#include <kernel/console.H>
+#include <initservice/taskargs.H>
+#include <targeting/predicates/predicatectm.H>
#include <sys/time.h>
+#include <string.h>
#include <algorithm>
+//@todo : Create common id for master+type+port to use in error logs and traces
+
// Trace definition
trace_desc_t* g_trac_fsi = NULL;
@@ -70,53 +73,39 @@ uint64_t target_to_uint64(TARGETING::Target* i_target)
return id;
}
-// Initialize static variables
-mutex_t FsiDD::cv_mux = MUTEX_INITIALIZER;
-std::vector<FsiDD*> FsiDD::cv_instances;
-
-/**
- * @brief Select the instance for the given target
- */
-FsiDD* FsiDD::getInstance( TARGETING::Target* i_target )
+//@todo - remove this when attribute call is ready
+FSI::FsiChipInfo_t temp_attr_call(TARGETING::Target* i_target)
{
- FsiDD* inst = NULL;
- TRACUCOMP( g_trac_fsi, "FsiDD::getInstance> Looking for target : %llX", target_to_uint64(i_target) );
+ FSI::FsiChipInfo_t info;
- mutex_lock(&cv_mux);
+ // just defaulting everything to the local master for now
+ TARGETING::TargetService& targetService = TARGETING::targetService();
+ targetService.masterProcChipTargetHandle( info.master );
- for( std::vector<FsiDD*>::iterator dd = FsiDD::cv_instances.begin();
- dd != FsiDD::cv_instances.end();
- ++dd )
+ if( i_target->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_PROC )
{
- if( (*dd)->iv_target == i_target )
- {
- inst = *dd;
- break;
- }
+ info.type = FSI::MFSI_TYPE;
+ info.port = 0;
}
-
- // need to instantiate an object
- if( (inst == NULL)
- && (TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != i_target) )
+ else
{
- // only support processor targets
- //@todo - switch to PredicateCTM
- if( i_target->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_PROC )
- {
- TRACFCOMP( g_trac_fsi, "FsiDD::getInstance> Creating new instance for target : %llX", target_to_uint64(i_target) );
- inst = new FsiDD(i_target);
- FsiDD::cv_instances.push_back(inst);
- }
+ info.type = FSI::CMFSI_TYPE;
+ info.port = 0;
}
- mutex_unlock(&cv_mux);
- return inst;
+ info.cascade = 0;
+ info.attributes = 0;
+
+ TRACUCOMP( g_trac_fsi, "temp_attr_call> i_target=%llX : type=%X, port=%X, cascade=%X, attributes=%llX", target_to_uint64(i_target), info.type, info.port, info.cascade, info.attributes );
+ return info;
}
namespace FSI
{
+//@todo - combine ddRead/ddWrite into a single function ?
+
/**
* @brief Performs a FSI Read Operation
* This function performs a FSI Read operation. It follows a pre-defined
@@ -150,40 +139,37 @@ errlHndl_t ddRead(DeviceFW::OperationType i_opType,
TRACUCOMP( g_trac_fsi, "FSI::ddRead> i_addr=%llX, target=%llX", i_addr, target_to_uint64(i_target) );
do{
- FsiDD* driver = FsiDD::getInstance(i_target);
- if( driver )
- {
- // prefix the appropriate MFSI/cMFSI slave port
- uint64_t l_addr = driver->genFullFsiAddr( i_target, i_addr );
-
- // do the read
- l_err = driver->read(l_addr,
- io_buflen,
- (uint32_t*)io_buffer);
- if(l_err)
- {
- break;
- }
- }
- else
+ if( io_buflen != sizeof(uint32_t) )
{
- TRACFCOMP( g_trac_fsi, "FSI::ddRead> Invalid target : %llX", target_to_uint64(i_target) );
+ TRACFCOMP( g_trac_fsi, "FsiDD::ddRead> Invalid data length : io_buflen=%d", io_buflen );
/*@
* @errortype
* @moduleid FSI::MOD_FSIDD_DDREAD
- * @reasoncode FSI::RC_INVALID_TARGET
- * @userdata1 Target Id
- * @userdata2 FSI Address
- * @devdesc FSI::ddRead> Invalid target
+ * @reasoncode FSI::RC_INVALID_LENGTH
+ * @userdata1 FSI Address
+ * @userdata2 Data Length
+ * @devdesc FsiDD::ddRead> Invalid data length
*/
l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
FSI::MOD_FSIDD_DDREAD,
- FSI::RC_INVALID_TARGET,
- target_to_uint64(i_target),
- i_addr);
+ FSI::RC_INVALID_LENGTH,
+ i_addr,
+ TO_UINT64(io_buflen));
break;
+ }
+ // default to the fail path
+ io_buflen = 0;
+
+ // do the read
+ l_err = Singleton<FsiDD>::instance().read(i_target,
+ i_addr,
+ static_cast<uint32_t*>(io_buffer));
+ if(l_err)
+ {
+ break;
}
+ io_buflen = sizeof(uint32_t);
}while(0);
@@ -191,7 +177,7 @@ errlHndl_t ddRead(DeviceFW::OperationType i_opType,
}
/**
- * @brief Performs a FSI Write Operation
+ * @brief Perform a FSI Write Operation
* This function performs a FSI Write operation. It follows a pre-defined
* prototype functions in order to be registered with the device-driver
* framework.
@@ -223,40 +209,37 @@ errlHndl_t ddWrite(DeviceFW::OperationType i_opType,
TRACUCOMP( g_trac_fsi, "FSI::ddWrite> i_addr=%llX, target=%llX", i_addr, target_to_uint64(i_target) );
do{
- FsiDD* driver = FsiDD::getInstance(i_target);
- if( driver )
+ if( io_buflen != sizeof(uint32_t) )
{
- // prefix the appropriate MFSI/cMFSI slave port
- uint64_t l_addr = driver->genFullFsiAddr( i_target, i_addr );
-
- // do the write
- l_err = driver->write(l_addr,
- io_buflen,
- (uint32_t*)io_buffer);
- if(l_err)
- {
- break;
- }
- }
- else
- {
- TRACFCOMP( g_trac_fsi, "FSI::ddWrite> Invalid target : %llX", target_to_uint64(i_target) );
+ TRACFCOMP( g_trac_fsi, "FsiDD::ddWrite> Invalid data length : io_buflen=%d", io_buflen );
/*@
* @errortype
* @moduleid FSI::MOD_FSIDD_DDWRITE
- * @reasoncode FSI::RC_INVALID_TARGET
- * @userdata1 Target Id
- * @userdata2 FSI Address
- * @devdesc FSI::ddWrite> Invalid target
+ * @reasoncode FSI::RC_INVALID_LENGTH
+ * @userdata1 FSI Address
+ * @userdata2 Data Length
+ * @devdesc FsiDD::ddWrite> Invalid data length
*/
l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
FSI::MOD_FSIDD_DDWRITE,
- FSI::RC_INVALID_TARGET,
- target_to_uint64(i_target),
- i_addr);
+ FSI::RC_INVALID_LENGTH,
+ i_addr,
+ TO_UINT64(io_buflen));
break;
+ }
+ // default to the fail path
+ io_buflen = 0;
+
+ // do the write
+ l_err = Singleton<FsiDD>::instance().write(i_target,
+ i_addr,
+ static_cast<uint32_t*>(io_buffer));
+ if(l_err)
+ {
+ break;
}
+ io_buflen = sizeof(uint32_t);
}while(0);
@@ -268,39 +251,328 @@ DEVICE_REGISTER_ROUTE(DeviceFW::READ,
DeviceFW::FSI,
TARGETING::TYPE_PROC,
ddRead);
+DEVICE_REGISTER_ROUTE(DeviceFW::READ,
+ DeviceFW::FSI,
+ TARGETING::TYPE_MEMBUF,
+ ddRead);
// Register fsidd access functions to DD framework
DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
DeviceFW::FSI,
TARGETING::TYPE_PROC,
ddWrite);
+DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
+ DeviceFW::FSI,
+ TARGETING::TYPE_MEMBUF,
+ ddWrite);
+
+
+// Initialize all visible FSI masters
+errlHndl_t initializeHardware( uint64_t& o_numPorts )
+{
+ return Singleton<FsiDD>::instance().initializeHardware(o_numPorts);
+}
}; //end FSI namespace
+/**
+ * @brief set up _start() task entry procedure for PNOR daemon
+ */
+TASK_ENTRY_MACRO( FsiDD::init );
+/********************
+ Public Methods
+ ********************/
/**
- * @brief Read FSI Register
+ * STATIC
+ * @brief Static Initializer
*/
-errlHndl_t FsiDD::read(uint64_t i_address,
- size_t& io_buflen,
+void FsiDD::init( void* i_taskArgs )
+{
+ TRACFCOMP(g_trac_fsi, "FsiDD::init> " );
+ // nothing to do here...
+}
+
+
+
+
+/**
+ * @brief Performs an FSI Read Operation to a relative address
+ */
+errlHndl_t FsiDD::read(TARGETING::Target* i_target,
+ uint64_t i_address,
uint32_t* o_buffer)
{
- TRACDCOMP(g_trac_fsi, "FsiDD::read(i_address=0x%llx)> ", i_address);
+ TRACDCOMP(g_trac_fsi, "FsiDD::read(i_target=%llX,i_address=0x%llX)> ", target_to_uint64(i_target), i_address);
errlHndl_t l_err = NULL;
- bool need_unlock = false;
do {
+ // prefix the appropriate MFSI/cMFSI slave port offset
+ uint64_t l_addr = genFullFsiAddr( i_target, i_address );
+
// make sure we got a valid FSI address
- l_err = verifyAddressRange( i_address, io_buflen );
+ l_err = verifyAddressRange( l_addr );
if(l_err)
{
break;
}
+ // perform the read operation
+ l_err = read( l_addr, o_buffer );
+ if(l_err)
+ {
+ break;
+ }
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Performs an FSI Write Operation to a relative address
+ */
+errlHndl_t FsiDD::write(TARGETING::Target* i_target,
+ uint64_t i_address,
+ uint32_t* i_buffer)
+{
+ TRACDCOMP(g_trac_fsi, "FsiDD::write(i_target=%llX,i_address=0x%llX)> ", target_to_uint64(i_target), i_address);
+ errlHndl_t l_err = NULL;
+
+ do {
+ // prefix the appropriate MFSI/cMFSI slave port offset
+ uint64_t l_addr = genFullFsiAddr( i_target, i_address );
+
+ // make sure we got a valid FSI address
+ l_err = verifyAddressRange( l_addr );
+ if(l_err)
+ {
+ break;
+ }
+
+ // perform the write operation
+ l_err = write( l_addr, i_buffer );
+ if(l_err)
+ {
+ break;
+ }
+ } while(0);
+
+ return l_err;
+}
+
+// local type used inside FsiDD::initializeHardware()
+// must be declared outside the function to make compiler happy
+struct remote_info_t {
+ TARGETING::Target* master;
+ uint8_t slave_port;
+};
+
+/**
+ * @brief Initialize the FSI hardware
+ */
+errlHndl_t FsiDD::initializeHardware( uint64_t& o_numPorts )
+{
+ errlHndl_t l_err = NULL;
+ TRACUCOMP( g_trac_fsi, "FSI::initializeHardware>" );
+ o_numPorts = 0;
+
+ do{
+ // list of ports off of local MFSI
+ std::list<uint64_t> local_mfsi;
+
+ // list of ports off of local cMFSI
+ std::list<uint64_t> local_cmfsi;
+
+ // list of ports off of remote cMFSI
+ std::list<TARGETING::Target*> remote_masters;
+
+ // list of ports off of remote cMFSI
+ std::list<remote_info_t> remote_cmfsi;
+
+ FSI::FsiChipInfo_t info;
+
+ // loop through every CHIP target
+ TARGETING::PredicateCTM l_chipClass(TARGETING::CLASS_CHIP,
+ TARGETING::TYPE_NA,
+ TARGETING::MODEL_NA);
+ TARGETING::TargetService& targetService = TARGETING::targetService();
+ TARGETING::TargetIterator t_itr = targetService.begin();
+ while( t_itr != targetService.end() )
+ {
+ // Sorting into buckets because we must maintain the init order
+ // the MFSI port that goes out to a remove cMFSI driver
+ // must be initialized before we can deal with the cMFSI port
+ if( l_chipClass(*t_itr) )
+ {
+ info = temp_attr_call(*t_itr);
+
+ if( info.type == FSI::MFSI_TYPE )
+ {
+ local_mfsi.push_back(info.port);
+ }
+ else if( info.type == FSI::CMFSI_TYPE )
+ {
+ if( info.master == iv_master )
+ {
+ local_cmfsi.push_back(info.port);
+ }
+ else
+ {
+ // add all unique masters to the list
+ if( remote_masters.end() ==
+ std::find(remote_masters.begin(),
+ remote_masters.end(),
+ info.master) )
+ {
+ remote_masters.push_back( info.master );
+ }
+
+ remote_info_t tmp = {info.master,info.port};
+ remote_cmfsi.push_back( tmp );
+ }
+ }
+ }
+
+ ++t_itr;
+ }
+
+ // setup the local master control regs for the MFSI
+ l_err = initMasterControl(iv_master,FSI::MFSI_TYPE);
+ if( l_err )
+ {
+ break;
+ }
+
+ // initialize all of the local MFSI ports
+ for( std::list<uint64_t>::iterator itr = local_mfsi.begin();
+ itr != local_mfsi.end();
+ ++itr )
+ {
+ l_err = initPort( iv_master, FSI::MFSI_TYPE, *itr );
+ if( l_err )
+ {
+ //@todo - append the actual slave target to FFDC
+ // commit the log here so that we can move on to next port
+ errlCommit(l_err);
+ }
+ else
+ {
+ o_numPorts++;
+ }
+ }
+
+ // setup the local master control regs for the cMFSI
+ l_err = initMasterControl(iv_master,FSI::CMFSI_TYPE);
+ if( l_err )
+ {
+ break;
+ }
+
+ // initialize all of the local cMFSI ports
+ for( std::list<uint64_t>::iterator itr = local_cmfsi.begin();
+ itr != local_cmfsi.end();
+ ++itr )
+ {
+ l_err = initPort( iv_master, FSI::CMFSI_TYPE, *itr );
+ if( l_err )
+ {
+ //@todo - append the actual slave target to FFDC
+ // commit the log here so that we can move on to next port
+ errlCommit(l_err);
+ }
+ else
+ {
+ o_numPorts++;
+ }
+ }
+
+ // initialize all of the remote cMFSI masters
+ for( std::list<TARGETING::Target*>::iterator itr
+ = remote_masters.begin();
+ itr != remote_masters.end();
+ ++itr )
+ {
+ l_err = initMasterControl(*itr,FSI::CMFSI_TYPE);
+ if( l_err )
+ {
+ // commit the log here so that we can move on to next port
+ errlCommit(l_err);
+ }
+ }
+
+ // initialize all of the remote cMFSI ports
+ for( std::list<remote_info_t>::iterator itr = remote_cmfsi.begin();
+ itr != remote_cmfsi.end();
+ ++itr )
+ {
+ l_err = initPort( itr->master, FSI::CMFSI_TYPE, itr->slave_port );
+ if( l_err )
+ {
+ //@todo - append the actual slave target to FFDC
+ // commit the log here so that we can move on to next port
+ errlCommit(l_err);
+ }
+ else
+ {
+ o_numPorts++;
+ }
+ }
+
+ } while(0);
+
+ return l_err;
+}
+
+
+/********************
+ Internal Methods
+ ********************/
+
+/**
+ * @brief Constructor
+ */
+FsiDD::FsiDD()
+:iv_master(NULL)
+{
+ TRACFCOMP(g_trac_fsi, "FsiDD::FsiDD()>");
+
+ mutex_init(&iv_fsiMutex);
+
+ for( uint64_t x=0; x < (sizeof(iv_slaves)/sizeof(iv_slaves[0])); x++ )
+ {
+ iv_slaves[x] = 0;
+ }
+
+ // save away the master processor target
+ TARGETING::TargetService& targetService = TARGETING::targetService();
+ iv_master = NULL;
+ targetService.masterProcChipTargetHandle( iv_master );
+}
+
+/**
+ * @brief Destructor
+ */
+FsiDD::~FsiDD()
+{
+ //nothing to do right now...
+}
+
+
+/**
+ * @brief Performs an FSI Read Operation
+ */
+errlHndl_t FsiDD::read(uint64_t i_address,
+ uint32_t* o_buffer)
+{
+ TRACDCOMP(g_trac_fsi, "FsiDD::read(i_address=0x%llx)> ", i_address);
+ errlHndl_t l_err = NULL;
+ bool need_unlock = false;
+
+ do {
// setup the OPB command register
uint64_t fsicmd = i_address | 0x60000000; // 011=Read Full Word
fsicmd <<= 32; // Command is in the upper word
@@ -318,10 +590,10 @@ errlHndl_t FsiDD::read(uint64_t i_address,
// write the OPB command register to trigger the read
TRACUCOMP(g_trac_fsi, "FsiDD::read> ScomWRITE : opbaddr=%.16llX, data=%.16llX", opbaddr, fsicmd );
l_err = deviceOp( DeviceFW::WRITE,
- iv_target,
+ iv_master,
&fsicmd,
scom_size,
- DEVICE_SCOM_ADDRESS(opbaddr) );
+ DEVICE_XSCOM_ADDRESS(opbaddr) );
if( l_err )
{
TRACFCOMP(g_trac_fsi, "FsiDD::read> Error from device 1 : RC=%X", l_err->reasonCode() );
@@ -335,12 +607,11 @@ errlHndl_t FsiDD::read(uint64_t i_address,
break;
}
- io_buflen = 4;
-
// atomic section <<
need_unlock = false;
mutex_unlock(&iv_fsiMutex);
+ TRACSCOMP(g_trac_fsi, "FSI READ : %.6X = %.8X", i_address, *o_buffer );
} while(0);
if( need_unlock )
@@ -348,11 +619,6 @@ errlHndl_t FsiDD::read(uint64_t i_address,
mutex_unlock(&iv_fsiMutex);
}
- if( l_err )
- {
- io_buflen = 0;
- }
-
return l_err;
}
@@ -360,7 +626,6 @@ errlHndl_t FsiDD::read(uint64_t i_address,
* @brief Write FSI Register
*/
errlHndl_t FsiDD::write(uint64_t i_address,
- size_t& io_buflen,
uint32_t* i_buffer)
{
TRACDCOMP(g_trac_fsi, "FsiDD::write(i_address=0x%llx)> ", i_address);
@@ -368,12 +633,7 @@ errlHndl_t FsiDD::write(uint64_t i_address,
bool need_unlock = false;
do {
- // make sure we got an FSI address
- l_err = verifyAddressRange( i_address, io_buflen );
- if(l_err)
- {
- break;
- }
+ TRACSCOMP(g_trac_fsi, "FSI WRITE : %.6X = %.8X", i_address, *i_buffer );
// pull out the data to write (length has been verified)
uint32_t fsidata = *i_buffer;
@@ -394,10 +654,10 @@ errlHndl_t FsiDD::write(uint64_t i_address,
// write the OPB command register
TRACUCOMP(g_trac_fsi, "FsiDD::write> ScomWRITE : opbaddr=%.16llX, data=%.16llX", opbaddr, fsicmd );
l_err = deviceOp( DeviceFW::WRITE,
- iv_target,
+ iv_master,
&fsicmd,
scom_size,
- DEVICE_SCOM_ADDRESS(opbaddr) );
+ DEVICE_XSCOM_ADDRESS(opbaddr) );
if( l_err )
{
TRACFCOMP(g_trac_fsi, "FsiDD::write> Error from device : RC=%X", l_err->reasonCode() );
@@ -411,8 +671,6 @@ errlHndl_t FsiDD::write(uint64_t i_address,
break;
}
- io_buflen = 4;
-
// atomic section <<
need_unlock = false;
mutex_unlock(&iv_fsiMutex);
@@ -424,11 +682,6 @@ errlHndl_t FsiDD::write(uint64_t i_address,
mutex_unlock(&iv_fsiMutex);
}
- if( l_err )
- {
- io_buflen = 0;
- }
-
TRACDCOMP(g_trac_fsi, "< FsiDD::write() ", i_address);
return l_err;
@@ -436,39 +689,16 @@ errlHndl_t FsiDD::write(uint64_t i_address,
/**
- * @brief Constructor
- */
-FsiDD::FsiDD( TARGETING::Target* i_target )
-:iv_target(i_target)
-{
- TRACFCOMP(g_trac_fsi, "FsiDD::FsiDD()> target=%llX", target_to_uint64(i_target) );
-
- mutex_init(&iv_fsiMutex);
-}
-
-/**
- * @brief Destructor
- */
-FsiDD::~FsiDD()
-{
- // remove this instance from the global list
- FsiDD::cv_instances.erase(
- std::find(cv_instances.begin(),
- cv_instances.end(),
- this)
- );
-}
-
-/**
* @brief Verify Request is in appropriate address range
*/
-errlHndl_t FsiDD::verifyAddressRange(uint64_t i_address,
- size_t i_length)
+errlHndl_t FsiDD::verifyAddressRange(uint64_t i_address)
{
errlHndl_t l_err = NULL;
do{
- //@todo - add more address checks
+ //@fixme - is this needed at all???
+
+ //for every target except the master, only access CFAM addresses
// no port specified
if( (i_address & (MFSI_PORT_MASK|CMFSI_PORT_MASK|CONTROL_REG_MASK)) == 0 )
@@ -479,33 +709,14 @@ errlHndl_t FsiDD::verifyAddressRange(uint64_t i_address,
* @moduleid FSI::MOD_FSIDD_VERIFYADDRESSRANGE
* @reasoncode FSI::RC_INVALID_ADDRESS
* @userdata1 FSI Address
- * @userdata2 Data Length
+ * @userdata2 <unused>
* @devdesc FsiDD::verifyAddressRange> Invalid address
*/
l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
FSI::MOD_FSIDD_VERIFYADDRESSRANGE,
FSI::RC_INVALID_ADDRESS,
i_address,
- TO_UINT64(i_length));
- break;
- }
-
- if( i_length != 4 )
- {
- TRACFCOMP( g_trac_fsi, "FsiDD::verifyAddressRange> Invalid data length : i_length=%d", i_length );
- /*@
- * @errortype
- * @moduleid FSI::MOD_FSIDD_VERIFYADDRESSRANGE
- * @reasoncode FSI::RC_INVALID_LENGTH
- * @userdata1 FSI Address
- * @userdata2 Data Length
- * @devdesc FsiDD::verifyAddressRange> Invalid data length
- */
- l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- FSI::MOD_FSIDD_VERIFYADDRESSRANGE,
- FSI::RC_INVALID_LENGTH,
- i_address,
- TO_UINT64(i_length));
+ 0);
break;
}
@@ -530,7 +741,6 @@ errlHndl_t FsiDD::handleOpbErrors(TARGETING::Target* i_target,
{
TRACFCOMP( g_trac_fsi, "FsiDD::handleOpbErrors> Error during FSI access : i_address=0x%X, OPB Status=0x%.8X", i_address, i_opbStatReg );
-
/*@
* @errortype
* @moduleid FSI::MOD_FSIDD_HANDLEOPBERRORS
@@ -571,10 +781,10 @@ errlHndl_t FsiDD::pollForComplete(uint64_t i_address,
{
TRACUCOMP(g_trac_fsi, "FsiDD::pollForComplete> ScomREAD : opbaddr=%.16llX", opbaddr );
l_err = deviceOp( DeviceFW::READ,
- iv_target,
+ iv_master,
read_data,
scom_size,
- DEVICE_SCOM_ADDRESS(opbaddr) );
+ DEVICE_XSCOM_ADDRESS(opbaddr) );
if( l_err )
{
TRACFCOMP(g_trac_fsi, "FsiDD::pollForComplete> Error from device 2 : RC=%X", l_err->reasonCode() );
@@ -582,7 +792,7 @@ errlHndl_t FsiDD::pollForComplete(uint64_t i_address,
}
//@fixme - Simics model is broken on writes, just assume completion
- // See SW101420
+ // see Defect SW101420
if( !o_readData )
{
read_data[0] &= ~OPB_STAT_BUSY;
@@ -599,24 +809,36 @@ errlHndl_t FsiDD::pollForComplete(uint64_t i_address,
attempts++;
} while( attempts < MAX_OPB_ATTEMPTS );
if( l_err ) { break; }
- //@todo - hw has a 1ms watchdog, do I need to have a limit or just
- // loop until we hit an error
+
+ // we should never timeout because the hardware should set an error
+ assert( attempts < MAX_OPB_ATTEMPTS );
// check if we got an error
- l_err = handleOpbErrors( iv_target, i_address, read_data[0] );
+ l_err = handleOpbErrors( iv_master, i_address, read_data[0] );
if( l_err )
{
break;
}
- //@todo - is this possible? Ask hw team
// read valid isn't on
if( o_readData ) // only check if we're doing a read
{
if( !(read_data[0] & OPB_STAT_READ_VALID) )
{
TRACFCOMP( g_trac_fsi, "FsiDD::read> Read valid never came on : i_address=0x%X, OPB Status=0x%.8X", i_address, read_data[0] );
- //@todo - create error log
+ /*@
+ * @errortype
+ * @moduleid FSI::MOD_FSIDD_POLLFORCOMPLETE
+ * @reasoncode FSI::RC_OPB_NO_READ_VALID
+ * @userdata1 FSI Address being read
+ * @userdata2 OPB Status Register
+ * @devdesc FsiDD::handleOpbErrors> Error during FSI access
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ FSI::MOD_FSIDD_POLLFORCOMPLETE,
+ FSI::RC_OPB_NO_READ_VALID,
+ i_address,
+ TWO_UINT32_TO_UINT64(read_data[0],read_data[1]));
break;
}
@@ -635,33 +857,42 @@ errlHndl_t FsiDD::pollForComplete(uint64_t i_address,
uint64_t FsiDD::genFullFsiAddr(TARGETING::Target* i_target,
uint64_t i_address)
{
- //@todo - fill this in, for now just return the address as-is
- return i_address;
-
- //target matches my target so the address is correct as-is
- if( i_target == iv_target )
+ //target matches master so the address is correct as-is
+ if( i_target == iv_master )
{
return i_address;
}
- //target is another proc so need to use the appropriate MFSI port
- else if( i_target->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_PROC )
- {
- //@todo - use attribute to figure out which MFSI_PORT_x to use
- TRACFCOMP( g_trac_fsi, "FsiDD::genFullFsiAddr> MFSI targets aren't supported yet : i_target=%llX", target_to_uint64(i_target) );
- assert(0);
- }
- //target is a centaur so need to use the appropriate cMFSI port
- else if( i_target->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF )
+
+ uint64_t l_addr = i_address;
+
+ //pull the FSI info out for this target
+ FSI::FsiChipInfo_t fsi_info = temp_attr_call( i_target );
+
+ //FSI master is the master proc, find the port
+ if( fsi_info.master == iv_master )
{
- //@todo - use attribute to figure out which CMFSI_PORT_x to use
- TRACFCOMP( g_trac_fsi, "FsiDD::genFullFsiAddr> CMFSI targets aren't supported yet : i_target=%llX", target_to_uint64(i_target) );
- assert(0);
+ //append the appropriate offset
+ l_addr += getPortOffset(fsi_info.type,fsi_info.port);
}
- else
+ //target is another proc
+ else
{
- TRACFCOMP( g_trac_fsi, "FsiDD::genFullFsiAddr> Unknown target type : i_target=%llX", target_to_uint64(i_target) );
- assert(0);
+ //must be cMFSI or there are problems with system definition
+ assert( FSI::CMFSI_TYPE == fsi_info.type );
+
+ //append the CMFSI portion first
+ l_addr += getPortOffset(fsi_info.type,fsi_info.port);
+
+ //find this port's master and then get its port information
+ FSI::FsiChipInfo_t mfsi_info = temp_attr_call(fsi_info.master);
+ assert( mfsi_info.master == iv_master ); //invalid topology
+ assert( FSI::MFSI_TYPE == fsi_info.type ); //invalid topology
+
+ //append the MFSI port
+ l_addr += getPortOffset(mfsi_info.type,mfsi_info.port);
}
+
+ return l_addr;
}
/**
@@ -675,70 +906,328 @@ uint64_t FsiDD::genOpbScomAddr(uint64_t i_opbOffset)
return opbaddr;
}
-//@todo - IGNORE THIS FOR NOW
/**
- * @brief Initializes the FSI bus for the given slave
+ * @brief Initializes the FSI link to allow slave access
*/
-errlHndl_t FsiDD::initSlave(TARGETING::Target* i_target)
+errlHndl_t FsiDD::initPort(TARGETING::Target* i_master,
+ FSI::MasterType i_type,
+ uint64_t i_port)
{
errlHndl_t l_err = NULL;
- size_t regsize = sizeof(uint32_t);
+ TRACFCOMP( g_trac_fsi, ENTER_MRK"FsiDD::initPort> Initializing %llX, port %llX", target_to_uint64(i_master), i_port );
do {
- uint64_t masteroffset = MFSI_CONTROL_REG; //call some function to get this
+ uint32_t databuf = 0;
+
+ uint8_t portbit = 0x80 >> i_port;
+ // need to add the extra MFSI port offset for a remote cMFSI
+ uint64_t master_offset = 0;
+ if( (FSI::CMFSI_TYPE == i_type) && (i_master != iv_master) )
+ {
+ // look up the FSI information for this target's master
+ FSI::FsiChipInfo_t mfsi_info = temp_attr_call(i_master);
- //figure out which port this target is on
- uint64_t port = 0; //getAttr<TYPE_FSI_SLAVE_PORT>?
- uint32_t portbit = 0x80000000 >> port;
+ // append the master's port offset to the slave's
+ master_offset = getPortOffset( FSI::MFSI_TYPE, mfsi_info.port );
+ }
- //see if the slave is present
- uint32_t readbuf = 0;
- l_err = read( masteroffset|0x018, regsize, &readbuf );
- if( l_err ) { break; }
+ // control register is determined by the type of port
+ uint64_t master_ctl_reg = getControlReg(i_type);
+ master_ctl_reg += master_offset;
+
+ // slave offset is determined by which port it is on
+ uint64_t slave_offset = getPortOffset( i_type, i_port );
+ slave_offset += master_offset;
- if( !(readbuf & portbit) )
+
+ //Make sure this port has something on it
+ uint64_t slave_index = getSlaveEnableIndex(i_master,i_type);
+ if( !(iv_slaves[slave_index] & portbit) )
{
- TRACFCOMP( g_trac_fsi, "FsiDD::initSlave> Target %llX is not present : Reg 0x018=%lX", target_to_uint64(i_target), readbuf );
- //@todo - create error log for non-present slave?
+ TRACFCOMP( g_trac_fsi, "FsiDD::initPort> Target %llX is not present : sensebits=%.2X, portbit=%.2X", target_to_uint64(i_master), iv_slaves[slave_index], portbit );
+ /*@
+ * @errortype
+ * @moduleid FSI::MOD_FSIDD_INITPORT
+ * @reasoncode FSI::RC_INVALID_TARGET
+ * @userdata1 Target Id of Master
+ * @userdata2 Port bit | MLEVP0 from master
+ * @devdesc FsiDD::initPort> FSI slave port is not installed
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ FSI::MOD_FSIDD_INITPORT,
+ FSI::RC_INVALID_TARGET,
+ target_to_uint64(i_master),
+ TWO_UINT32_TO_UINT64(TO_UINT32(portbit),TO_UINT32(iv_slaves[slave_index])));
+ break;
}
- //choose clock ratio,delay selection
- l_err = write( masteroffset|0x008, regsize, &portbit );
+
+ //Write the port enable (enables clocks for FSI link)
+ databuf = static_cast<uint32_t>(portbit) << 24;
+ l_err = write( master_ctl_reg|FSI_MLEVP0_018, &databuf );
if( l_err ) { break; }
- //enable the port
- l_err = write( masteroffset|0x018, regsize, &portbit );
+ //Send the BREAK command to all slaves on this port (target slave0)
+ // part of FSI definition, write magic string into address zero
+ databuf = 0xC0DE0000;
+ l_err = write( slave_offset|0x00, &databuf );
if( l_err ) { break; }
- //reset the port
- l_err = write( masteroffset|0x008, regsize, &portbit );
+ //check for errors
+ l_err = read( master_ctl_reg|FSI_MAEB_070, &databuf );
+ if( l_err ) { break; }
+ if( databuf != 0 )
+ {
+ TRACFCOMP( g_trac_fsi, "FsiDD::initPort> Error after break to port %d:%d off %llX, MAEB=%lX", i_type, i_port, target_to_uint64(i_master), databuf );
+ /*@
+ * @errortype
+ * @moduleid FSI::MOD_FSIDD_INITPORT
+ * @reasoncode FSI::RC_ERROR_ENABLING_SLAVE
+ * @userdata1 Target Id of Master
+ * @userdata2 Port | MAEB from master
+ * @devdesc FsiDD::initPort> Error after sending BREAK
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ FSI::MOD_FSIDD_INITPORT,
+ FSI::RC_ERROR_ENABLING_SLAVE,
+ target_to_uint64(i_master),
+ TWO_UINT32_TO_UINT64(TO_UINT32(i_port),databuf));
+ break;
+ }
+
+ // Note: need to write to 3rd slave spot because the BREAK
+ // resets everything to that window
+ //@fixme - Simics doesn't agree with this...
+
+ //Setup the FSI slave to enable HW recovery, lbus ratio
+ // 2= Enable HW error recovery (bit 2)
+ // 6:7= Slave ID: 3 (default)
+ // 8:11= Echo delay: 0xF (default)
+ // 12:15= Send delay cycles: 0xF
+ // 20:23= Local bus ratio: 0x1
+ databuf = 0x23FF0100;
+ l_err = write( slave_offset|FSIS_MODE_00, &databuf );
if( l_err ) { break; }
+ //Note - this is a separate write because we want to have HW recovery
+ // enabled when we switch the window
+ //Set FSI slave ID to 0 (move slave to 1st 2MB address window)
+ // 6:7= Slave ID: 0
+ databuf = 0x20FF0100;
+ l_err = write( slave_offset|FSIS_MODE_00, &databuf );
+ if( l_err ) { break; }
+
+ //Note : from here on use the real cascade offset
+
+
+#if 0 // skipping the config space reading because we're hardcoding engines
+ //Read the config space
+ for( uint64_t config_addr = slave_offset|FSIS_CFG_TABLE;
+ config_addr < (slave_offset|FSIS_PEEK_TABLE);
+ config_addr += 4 )
+ {
+ // read the entry
+ l_err = read( config_addr, &databuf );
+ if( l_err ) { break; }
+
+ // if bit0==0 then we're through all of the engines
+ if( databuf & 0x80000000 )
+ {
+ break;
+ }
+ }
+#endif
+
+ // No support for slave cascades so we're done
+
} while(0);
+ TRACDCOMP( g_trac_fsi, EXIT_MRK"FsiDD::initPort" );
return l_err;
}
-//@todo - IGNORE THIS FOR NOW
/**
* @brief Initializes the FSI master control registers
- *
- * @return errlHndl_t NULL on success
*/
-errlHndl_t FsiDD::initMaster()
+errlHndl_t FsiDD::initMasterControl(TARGETING::Target* i_master,
+ FSI::MasterType i_type)
{
errlHndl_t l_err = NULL;
+ TRACFCOMP( g_trac_fsi, ENTER_MRK"FsiDD::initMasterControl> Initializing %llX:%d", target_to_uint64(i_master), i_type );
do {
- //@todo - loop to hit MFSI_CONTROL_REG and CMFSI_CONTROL_REG range?
+ uint32_t databuf = 0;
+
+ //find the full offset to the master control reg
+ // first get the address of the control reg to use
+ uint64_t ctl_reg = getControlReg(i_type);
+ // append the master port offset to get to the remote master
+ if( i_master != iv_master )
+ {
+ FSI::FsiChipInfo_t m_info = temp_attr_call(i_master);
+ ctl_reg += getPortOffset(FSI::MFSI_TYPE,m_info.port);
+ }
+
+
+ //Clear fsi port errors and general reset on all ports
+ for( uint32_t port = 0; port < MAX_SLAVE_PORTS; ++port )
+ {
+ // 2= General reset to all bridges
+ // 3= General reset to all port controllers
+ databuf = 0x30000000;
+ l_err = write( ctl_reg|FSI_MRESP0_0D0|port, &databuf );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+
+ //Freeze FSI Port on FSI/OPB bridge error (global)
+ // 18= Freeze FSI port on FSI/OPB bridge error
+ databuf = 0x00002000;
+ l_err = write( ctl_reg|FSI_MECTRL_2E0, &databuf );
+ if( l_err ) { break; }
+
+
+ //Set MMODE reg to enable HW recovery, parity checking, setup clock ratio
+ // 1= Enable hardware error recovery
+ // 3= Enable parity checking
+ // 4:13= FSI clock ratio 0 is 1:1
+ // 14:23= FSI clock ratio 1 is 4:1
+ databuf = 0x50040400;
+ l_err = write( ctl_reg|FSI_MMODE_000, &databuf );
+ if( l_err ) { break; }
+
+
+ //Determine which links are present
+ l_err = read( ctl_reg|FSI_MLEVP0_018, &databuf );
+ if( l_err ) { break; }
+
+ // Only looking at the top bits
+ uint64_t slave_index = getSlaveEnableIndex(i_master,i_type);
+ iv_slaves[slave_index] = (uint8_t)(databuf >> (32-MAX_SLAVE_PORTS));
+
+
+ //Clear FSI Slave Interrupt on ports 0-7
+ databuf = 0x00000000;
+ l_err = write( ctl_reg|FSI_MSIEP0_030, &databuf );
+ if( l_err ) { break; }
+
+
+ //Set the delay rates
+ // 0:3,8:11= Echo delay cycles is 15
+ // 4:7,12:15= Send delay cycles is 15
+ databuf = 0xFFFF0000;
+ l_err = write( ctl_reg|FSI_MDLYR_004, &databuf );
+ if( l_err ) { break; }
+
- // Mode Register
- // 1: Enable hardware error recovery
- //uint32_t clock_ratio0 = 100; //iv_target->getAttr<TARGETING::>()
- //uint32_t mode_reg = 0;
+ //Enable IPOLL
+ // 0= Enable IPOLL and DMA access
+ // 1= Enable hardware error recovery
+ // 3= Enable parity checking
+ // 4:13= FSI clock ratio 0 is 1:1
+ // 14:23= FSI clock ratio 1 is 4:1
+ databuf = 0xD0040400;
+ l_err = write( ctl_reg|FSI_MMODE_000, &databuf );
+ if( l_err ) { break; }
} while(0);
+ if( l_err )
+ {
+ TRACFCOMP( g_trac_fsi, "FsiDD::initMaster> Error during initialization of Target %llX : RC=%llX", target_to_uint64(iv_master), l_err->reasonCode() );
+ }
+
+ TRACDCOMP( g_trac_fsi, EXIT_MRK"FsiDD::initMaster" );
return l_err;
}
+
+
+/**
+ * @brief Compute a few useful FSI values based on the target of the
+ * FSI operation, this will look up some attributes under the covers.
+ */
+void FsiDD::getFsiInfo( TARGETING::Target* i_master,
+ FSI::MasterType i_type,
+ uint8_t i_port,
+ uint64_t& o_masterOffset,
+ uint64_t& o_slaveOffset,
+ uint32_t& o_portBit )
+{
+ o_portBit = 0x80000000 >> i_port;
+
+ // slave offset is determined by which port it is on
+ o_slaveOffset = getPortOffset( i_type, i_port );
+
+ // need to add the extra MFSI port offset for a remote cMFSI
+ if( (FSI::CMFSI_TYPE == i_type) && (i_master != iv_master) )
+ {
+ // look up the FSI information for this target's master
+ FSI::FsiChipInfo_t mfsi_info = temp_attr_call(i_master);
+
+ // append the master's port offset to the slave's
+ o_slaveOffset += getPortOffset( FSI::MFSI_TYPE, mfsi_info.port );
+ }
+
+
+ // master control regs are based on the type of master
+
+ if( FSI::MFSI_TYPE == i_type )
+ {
+ o_masterOffset = MFSI_CONTROL_REG;
+ }
+ else
+ {
+ o_masterOffset = CMFSI_CONTROL_REG;
+ }
+
+
+ TRACUCOMP( g_trac_fsi,
+ "FsiDD::getFsiInfo> i_master=%llX, i_type=%d, i_port=%d",
+ target_to_uint64(i_master), i_type, i_port );
+ TRACUCOMP( g_trac_fsi,
+ "o_masterOffset=%llX, o_slaveOffset=%llX, o_portBit=%lX",
+ o_masterOffset, o_slaveOffset, o_portBit );
+}
+
+
+/**
+ * @brief Convert a type/port pair into a FSI address offset
+ */
+uint64_t FsiDD::getPortOffset(FSI::MasterType i_type,
+ uint8_t i_port)
+{
+ uint64_t offset = 0;
+ if( FSI::MFSI_TYPE == i_type )
+ {
+ switch(i_port)
+ {
+ case(0): offset = MFSI_PORT_0; break;
+ case(1): offset = MFSI_PORT_1; break;
+ case(2): offset = MFSI_PORT_2; break;
+ case(3): offset = MFSI_PORT_3; break;
+ case(4): offset = MFSI_PORT_4; break;
+ case(5): offset = MFSI_PORT_5; break;
+ case(6): offset = MFSI_PORT_6; break;
+ case(7): offset = MFSI_PORT_7; break;
+ }
+ }
+ else if( FSI::CMFSI_TYPE == i_type )
+ {
+ switch(i_port)
+ {
+ case(0): offset = CMFSI_PORT_0; break;
+ case(1): offset = CMFSI_PORT_1; break;
+ case(2): offset = CMFSI_PORT_2; break;
+ case(3): offset = CMFSI_PORT_3; break;
+ case(4): offset = CMFSI_PORT_4; break;
+ case(5): offset = CMFSI_PORT_5; break;
+ case(6): offset = CMFSI_PORT_6; break;
+ case(7): offset = CMFSI_PORT_7; break;
+ }
+ }
+
+ return offset;
+}
+
diff --git a/src/usr/fsi/fsidd.H b/src/usr/fsi/fsidd.H
index f577f6571..d87ca4ed2 100644
--- a/src/usr/fsi/fsidd.H
+++ b/src/usr/fsi/fsidd.H
@@ -26,97 +26,135 @@
#include <sys/sync.h>
#include <util/locked/list.H>
#include <list>
+#include <errl/errlentry.H>
+#include <usr/devicefw/driverif.H>
+#include <fsi/fsiif.H>
/** @file fsidd.H
- * @brief Provides the interfaces to the FSI Device Driver
+ * @brief Provides the definition of the FSI Device Driver class
*/
-class FsiDD;
-
-// Predeclare these so we can make them friends
-namespace FSI {
-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 ddWrite(DeviceFW::OperationType i_opType,
- TARGETING::Target* i_target,
- void* io_buffer,
- size_t& io_buflen,
- int64_t i_accessType,
- va_list i_args);
-}
+//@todo - pre-declare fake attribute call
+FSI::FsiChipInfo_t temp_attr_call(TARGETING::Target* i_target);
/**
* Class to handle the FSI Master operations
- * there will be one instance per master
+ * there will be a single instance within hostboot
*/
class FsiDD
{
public:
/**
- * @brief Performs an FSI Read Operation
+ * @brief Static Initializer
+ * @param[in] Task Args pointer passed by init service
+ */
+ static void init( void* i_taskArgs );
+
+ /**
+ * @brief Initialize the FSI hardware
*
- * @param[in] i_address Address to read (relative to FSI Master chip)
- * @param[in] io_buflen Number of bytes to access, returns
- * number of bytes actually read
+ * @param[out] o_numPorts Number of FSI ports that were
+ * successfully initialized
+ *
+ * @return errlHndl_t NULL on success
+ */
+ errlHndl_t initializeHardware( uint64_t& o_numPorts );
+
+ /**
+ * @brief Performs an FSI Read Operation to an absolute address
+ *
+ * @param[in] i_target Chip target of FSI operation
+ * @param[in] i_address Address to read (relative to target)
* @param[out] o_buffer Destination buffer for data
*
* @return errlHndl_t NULL on success
*/
- errlHndl_t read(uint64_t i_address,
- size_t& io_buflen,
+ errlHndl_t read(TARGETING::Target* i_target,
+ uint64_t i_address,
uint32_t* o_buffer);
/**
* @brief Performs an FSI Write Operation
*
- * @param[in] i_address Address to read (relative to FSI Master chip)
- * @param[in] io_buflen Number of bytes to access, returns
- * number of bytes actually written
- * @param[out] o_buffer Source buffer for data
+ * @param[in] i_target Chip target of FSI operation
+ * @param[in] i_address Address to write (relative to target)
+ * @param[out] i_buffer Source buffer for data
*
* @return errlHndl_t NULL on success
*/
- errlHndl_t write(uint64_t i_address,
- size_t& io_buflen,
+ errlHndl_t write(TARGETING::Target* i_target,
+ uint64_t i_address,
uint32_t* i_buffer);
+
+ protected:
+ /**
+ * @brief Constructor
+ */
+ FsiDD();
+
+
+ /**
+ * @brief Destructor
+ */
+ ~FsiDD();
+
/**
- * @brief Initializes the FSI bus for the given slave
+ * @brief Performs an FSI Read Operation
*
- * @param[in] Chip target of FSI-slave
+ * @param[in] i_address Address to read (relative to FSI Master chip)
+ * @param[out] o_buffer Destination buffer for data
*
* @return errlHndl_t NULL on success
*/
- errlHndl_t initSlave(TARGETING::Target* i_target);
+ errlHndl_t read(uint64_t i_address,
+ uint32_t* o_buffer);
- protected:
/**
- * @brief Constructor
+ * @brief Performs an FSI Write Operation to an absolute address
+ *
+ * @param[in] i_address Absolute address to write
+ * @param[out] i_buffer Source buffer for data
+ *
+ * @return errlHndl_t NULL on success
+ */
+ errlHndl_t write(uint64_t i_address,
+ uint32_t* i_buffer);
+
+ /**
+ * @brief Initializes the FSI master control registers
*
- * @param[in] XSCOM target associated with this FSI Master instance
+ * @param[in] i_master Target of FSI master chip to initialize
+ * @param[in] i_type Type of FSI interface
+ *
+ * @return errlHndl_t NULL on success
*/
- FsiDD( TARGETING::Target* i_target );
+ errlHndl_t initMasterControl(TARGETING::Target* i_master,
+ FSI::MasterType i_type);
/**
- * @brief Destructor
+ * @brief Initializes the FSI link to allow slave access
+ *
+ * @param[in] Chip target of FSI-Master
+ * @param[in] Type of FSI-Master
+ * @param[in] FSI port (0-7) being initialized (relative to master)
+ *
+ * @return errlHndl_t NULL on success
*/
- ~FsiDD();
+ errlHndl_t initPort(TARGETING::Target* i_master,
+ FSI::MasterType i_type,
+ uint64_t i_port);
/**
* @brief Verify Request is in appropriate address range
*
* @param[in] i_address Starting address (relative to FSI Device)
- * @param[in] i_length Number of bytes being accessed
*
* @return errlHndl_t NULL on success
*/
- errlHndl_t verifyAddressRange(uint64_t i_address,
- size_t i_length);
+ errlHndl_t verifyAddressRange(uint64_t i_address);
+
/**
* @brief Analyze error bits and recover hardware as needed
@@ -167,26 +205,39 @@ class FsiDD
uint64_t genOpbScomAddr(uint64_t i_opbOffset);
/**
- * @brief Initializes the FSI master control registers
+ * @brief Compute a few useful FSI values based on the target of the
+ * FSI operation, this will look up some attributes under the covers.
*
- * @return errlHndl_t NULL on success
+ * @param[in] i_master Target of FSI Master
+ * @param[in] i_type Type of FSI interface
+ * @param[in] i_port FSI link number (relative to master)
+ * @param[out] o_masterOffset Address offset for master control regs
+ * @param[out] o_slaveOffset Address offset for slave regs
+ * @param[out] o_portBit 1-hot bitstring with this chip's port set
*/
- errlHndl_t initMaster();
+ void getFsiInfo( TARGETING::Target* i_master,
+ FSI::MasterType i_type,
+ uint8_t i_port,
+ uint64_t& o_masterOffset,
+ uint64_t& o_slaveOffset,
+ uint32_t& o_portBit );
+
/**
- * FSI Address Space
+ * @brief Convert a type/port pair into a FSI address offset
+ *
+ * @param[in] i_type Type of FSI interface
+ * @param[in] i_port FSI link number
+ * @return uint64_t FSI address offset
*/
- enum {
- // Local FSI Space
- CFAM_CONFIG_TABLE = 0x000000, /**< Configuration Table of CFAM */
- PEEK_TABLE = 0x000400, /**< Peek Table */
- FSI_SLAVE_REG = 0x000800, /**< FSI Slave Register */
- FSI_SHIFT_ENGINE = 0x000C00, /**< FSI Shift Engine (SCAN) */
- FSI2PIB_ENGINE = 0x001000, /**< FSI2PIB Engine (SCOM) */
- FSI_SCRATCHPAD = 0x001400, /**< FSI Scratchpad */
- FSI_I2C_MASTER = 0x001800, /**< FSI I2C-Master */
- FSI_GEMINI_MBOX = 0x002800, /**< FSI Gemini Mailbox with FSI GPx Registers */
+ uint64_t getPortOffset(FSI::MasterType i_type,
+ uint8_t i_port);
+
+ /**
+ * FSI Address Space
+ */
+ enum FsiAddressSpace {
// Master control registers
CMFSI_CONTROL_REG = 0x003000, /**< cMFSI Control Register */
MFSI_CONTROL_REG = 0x003400, /**< MFSI Control Register */
@@ -210,6 +261,7 @@ class FsiDD
CMFSI_SLAVE_3 = 0x006000, /**< cMFSI - Slave 3 */
// MFSI Ports (512KB each)
+ MFSI_PORT_LOCAL = 0x000000, /**< Local master (used for local cMFSI) */
MFSI_PORT_0 = 0x080000, /**< MFSI port 0 */
MFSI_PORT_1 = 0x100000, /**< MFSI port 1 */
MFSI_PORT_2 = 0x180000, /**< MFSI port 2 */
@@ -219,13 +271,19 @@ class FsiDD
MFSI_PORT_6 = 0x380000, /**< MFSI port 6 */
MFSI_PORT_7 = 0x400000, /**< MFSI port 7 */
MFSI_PORT_MASK = 0x780000, /**< Mask to look for a valid MFSI port */
+
+ // Offsets to cascaded slaves within a MFSI port
+ MFSI_SLAVE_0 = 0x000000, /**< MFSI - Slave 0 */
+ MFSI_SLAVE_1 = 0x020000, /**< MFSI - Slave 1 */
+ MFSI_SLAVE_2 = 0x040000, /**< MFSI - Slave 2 */
+ MFSI_SLAVE_3 = 0x060000, /**< MFSI - Slave 3 */
};
/**
* PIB2OPB Registers
*/
- enum {
+ enum Pib2OpbRegisters {
OPB_REG_CMD = 0x0000, /**< Command Register */
OPB_REG_STAT = 0x0001, /**< Status Register */
OPB_REG_LSTAT = 0x0002, /**< Locked Status */
@@ -244,7 +302,7 @@ class FsiDD
// Bit masks
OPB_STAT_BUSY = 0x00010000, /**< Bit 15 is the Busy bit */
- OPB_STAT_READ_VALID = 0x00020000, /**< Bit 15 is the Busy bit */
+ OPB_STAT_READ_VALID = 0x00020000, /**< Bit 14 is the Valid Read bit */
OPB_STAT_ERR_OPB = 0x09F00000, /**< 4,7-11 are OPB errors */
OPB_STAT_ERR_CMFSI = 0x0000FC00, /**< 16-21 are cMFSI errors */
OPB_STAT_ERR_MFSI = 0x000000FC, /**< 24-29 are MFSI errors */
@@ -253,60 +311,112 @@ class FsiDD
MAX_OPB_ATTEMPTS = 10, /**< Maximum number of attempts for OPB reg ops */
};
-
+ //@todo - move to external header?
/**
- * Global mutex @todo - make this per target for efficiency
+ * FSI Control Registers
*/
- mutex_t iv_fsiMutex;
+ enum FsiControlRegisters {
+ FSI_MMODE_000 = 0x000,
+ FSI_MDLYR_004 = 0x004,
+ FSI_MCRSP0_008 = 0x008,
+ FSI_MLEVP0_018 = 0x018,
+ FSI_MSIEP0_030 = 0x030,
+ FSI_MAEB_070 = 0x070,
+ FSI_MRESP0_0D0 = 0x0D0,
+ FSI_MRESP0_0D1 = 0x0D1,
+ FSI_MRESP0_0D2 = 0x0D2,
+ FSI_MRESP0_0D3 = 0x0D3,
+ FSI_MRESP0_0D4 = 0x0D4,
+ FSI_MRESP0_0D5 = 0x0D5,
+ FSI_MRESP0_0D6 = 0x0D6,
+ FSI_MRESP0_0D7 = 0x0D7,
+ FSI_MECTRL_2E0 = 0x2E0
+ };
+ //@todo - move to external header?
/**
- * Associated target of FSI Master, i.e. XSCOM target
+ * FSI Slave Registers
+ * These registers are repeated for every master+port+cascade combo
*/
- TARGETING::Target* iv_target;
+ enum FsiSlaveRegisters {
+ // Local FSI Space
+ FSIS_CFG_TABLE = 0x000000, /**< Configuration Table of CFAM */
+ FSIS_PEEK_TABLE = 0x000400, /**< Peek Table */
- private:
- // let my testcase poke around
- friend class FsiDDTest;
+ FSI_SLAVE_REGS = 0x000800, /**< FSI Slave Register */
+ FSIS_MODE_00 = FSI_SLAVE_REGS| 0x00,
+ FSI_SHIFT_ENGINE = 0x000C00, /**< FSI Shift Engine (SCAN) */
+ FSI2PIB_ENGINE = 0x001000, /**< FSI2PIB Engine (SCOM) */
+ FSI_SCRATCHPAD = 0x001400, /**< FSI Scratchpad */
+ FSI_I2C_MASTER = 0x001800, /**< FSI I2C-Master */
+ FSI_GEMINI_MBOX = 0x002800, /**< FSI Gemini Mailbox with FSI GPx Registers */
+ };
- friend errlHndl_t FSI::ddRead(DeviceFW::OperationType i_opType,
- TARGETING::Target* i_target,
- void* io_buffer,
- size_t& io_buflen,
- int64_t i_accessType,
- va_list i_args);
- friend errlHndl_t FSI::ddWrite(DeviceFW::OperationType i_opType,
- TARGETING::Target* i_target,
- void* io_buffer,
- size_t& io_buflen,
- int64_t i_accessType,
- va_list i_args);
+ /**
+ * General Constants
+ */
+ enum Constants {
+ MAX_SLAVE_PORTS = 8, /**< Maximum of 8 slave ports */
+ LOCAL_MFSI_PORT_SELECT = MAX_SLAVE_PORTS + FSI::MFSI_TYPE,
+ LOCAL_CMFSI_PORT_SELECT = MAX_SLAVE_PORTS + FSI::CMFSI_TYPE,
+ };
- /**********
- * STATIC
- **********/
+ /**
+ * @brief Retrieve the control register address based on type
+ * @param[in] i_type Type of FSI interface
+ * @return uint64_t FSI address offset
+ */
+ uint64_t getControlReg(FSI::MasterType i_type)
+ {
+ uint64_t ctl_reg = MFSI_CONTROL_REG;
+ if( FSI::CMFSI_TYPE == i_type )
+ {
+ ctl_reg = CMFSI_CONTROL_REG;
+ }
+ return ctl_reg;
+ };
/**
- * List of available instances
+ * @brief Retrieve the slave enable index
+ * @param[in] i_master Target of FSI Master
+ * @param[in] i_type Type of FSI interface
+ * @return uint64_t Index into iv_slaves array
*/
- static std::vector<FsiDD*> cv_instances;
+ uint64_t getSlaveEnableIndex( TARGETING::Target* i_master,
+ FSI::MasterType i_type )
+ {
+ //default to local slave ports
+ uint64_t slave_index = MAX_SLAVE_PORTS+i_type;
+ if( i_master != iv_master )
+ {
+ FSI::FsiChipInfo_t m_info = temp_attr_call(i_master);
+ slave_index = m_info.port;
+ }
+ return slave_index;
+ };
/**
- * Global mutex to handle updates to gv_instances
+ * Global mutex
*/
- static mutex_t cv_mux;
+ mutex_t iv_fsiMutex;
+ /**
+ * Active slaves, 1 bit per port, 1=active,
+ * one entry per MFSI port, plus local MFSI and local cMFSI
+ */
+ uint8_t iv_slaves[MAX_SLAVE_PORTS+2];
- public:
/**
- * @brief Select the instance for the given target
- *
- * @param[in] i_target TARGETING::Target* i_target
- *
- * @return FsiDD* Pointer to instance that matches the target
+ * Master processor target
*/
- static FsiDD* getInstance( TARGETING::Target* i_target );
+ TARGETING::Target* iv_master;
+
+ private:
+
+ // let my testcase poke around
+ friend class FsiDDTest;
};
diff --git a/src/usr/fsi/test/fsiddtest.H b/src/usr/fsi/test/fsiddtest.H
index 406d1b9d6..7ff02c448 100644
--- a/src/usr/fsi/test/fsiddtest.H
+++ b/src/usr/fsi/test/fsiddtest.H
@@ -35,6 +35,7 @@
#include <errl/errltypes.H>
#include <limits.h>
#include <devicefw/driverif.H>
+#include <fsi/fsiif.H>
#include "../fsidd.H"
extern trace_desc_t* g_trac_fsi;
@@ -43,12 +44,11 @@ extern trace_desc_t* g_trac_fsi;
class FsiDDTest : public CxxTest::TestSuite
{
public:
-
/**
* @brief FSI DD test - Read/Write
* Perform basic read/write operations
*/
- void test_readWrite(void)
+ void t_readWrite(void)
{
TRACFCOMP( g_trac_fsi, "FsiDDTest::test_readWrite> Start" );
uint64_t fails = 0;
@@ -63,21 +63,26 @@ class FsiDDTest : public CxxTest::TestSuite
} test_data[] = {
//** Master Control Space
// version number
- { FsiDD::CMFSI_CONTROL_REG | 0x000074, 0x91010800, false },
- { FsiDD::MFSI_CONTROL_REG | 0x000074, 0x91010800, false },
+ { 0x003074, 0x91010800, false }, //CMFSI MVER
+ { 0x003474, 0x91010800, false }, //MFSI MVER
// clock rate delay for ports 32-63 (unused ports)
- { FsiDD::MFSI_CONTROL_REG | 0x00000C, 0x11111111, true },
- { FsiDD::CMFSI_CONTROL_REG | 0x00000C, 0x22222222, true },
+ { 0x00340C, 0x11111111, true }, //MFSI MCRSP32
+ { 0x00300C, 0x22222222, true }, //CMFSI MCRSP32
- // port static level
- { FsiDD::MFSI_CONTROL_REG | 0x000018, 0x80000000, false }, //port0
- { FsiDD::MFSI_CONTROL_REG | 0x00001C, 0x00000000, false },
- { FsiDD::CMFSI_CONTROL_REG | 0x000018, 0x00000000, false },
- { FsiDD::CMFSI_CONTROL_REG | 0x00001C, 0x00000000, false },
+ // port static levels
+ { 0x003418, 0x80000000, false }, //MFSI MLEVP32 (port0 present)
+ { 0x00341C, 0x00000000, false }, //MFSI MLEVP32
+ { 0x003018, 0x00000000, false }, //CMFSI MLEVP0
+ { 0x00301C, 0x00000000, false }, //CMFSI MLEVP32
//** Master Control Regs in Port space
//{ FsiDD::MFSI_PORT_0 | 0x000000, 0x91010800, false }, //Slave Config Table
+
+ //** Slave Regs
+ { 0x080000, 0xC0000F90, false }, //Config Table entry for slave0 off MFSI-0
+ { 0x081000, 0x12345678, true }, //DATA_0 from FSI2PIB off MFSI-0
+ { 0x081004, 0xA5A5A5A5, true }, //DATA_1 from FSI2PIB off MFSI-0
};
const uint64_t NUM_ADDRS = sizeof(test_data)/sizeof(test_data[0]);
@@ -95,6 +100,7 @@ class FsiDDTest : public CxxTest::TestSuite
{
total++;
TRACFCOMP( g_trac_fsi, "FsiDDTest::test_readWrite> Reading %llX", test_data[x].addr );
+ op_size = sizeof(uint32_t);
l_err = DeviceFW::deviceOp( DeviceFW::READ,
fsi_target,
&(read_data[x]),
@@ -110,8 +116,6 @@ class FsiDDTest : public CxxTest::TestSuite
}
TRACFCOMP( g_trac_fsi, "READ Reg 0x%X = 0x%X", test_data[x].addr, read_data[x] );
-
- //@todo - check op_size
}
// write X=A, Y=B, Z=C
@@ -133,8 +137,6 @@ class FsiDDTest : public CxxTest::TestSuite
errlCommit(l_err);
delete l_err;
}
-
- //@todo - check op_size
}
}
@@ -142,6 +144,7 @@ class FsiDDTest : public CxxTest::TestSuite
for( uint64_t x = 0; x < NUM_ADDRS; x++ )
{
total++;
+ op_size = sizeof(uint32_t);
l_err = DeviceFW::deviceOp( DeviceFW::READ,
fsi_target,
&(read_data[x]),
@@ -155,8 +158,6 @@ class FsiDDTest : public CxxTest::TestSuite
errlCommit(l_err);
delete l_err;
}
-
- //@todo - check op_size
}
// verify X==A, Y==B, Z==C
@@ -171,18 +172,54 @@ class FsiDDTest : public CxxTest::TestSuite
}
}
- //@todo - repeat for each address space
-
TRACFCOMP( g_trac_fsi, "FsiDDTest::test_readWrite> %d/%d fails", fails, total );
};
/**
+ * @brief FSI DD test - Initialization
+ * Test FSI Master/Slave Initialization
+ */
+ void test_init(void)
+ {
+ //TRACFCOMP( g_trac_fsi, "FsiDDTest::test_init> Skipping until simics patches are ready" );
+ //return; //@fixme
+
+ TRACFCOMP( g_trac_fsi, "FsiDDTest::test_init> Start" );
+ uint64_t fails = 0;
+ uint64_t total = 1; //only 1 slave port in the config
+ errlHndl_t l_err = NULL;
+
+ uint64_t good_ports = 0;
+ l_err = FSI::initializeHardware(good_ports);
+ if( l_err )
+ {
+ TRACFCOMP(g_trac_fsi, "FsiDDTest::test_init> Error from device : RC=%X", l_err->reasonCode() );
+ TS_FAIL( "FsiDDTest::test_init> ERROR : Unexpected error log from initMaster" );
+ errlCommit(l_err);
+ delete l_err;
+ }
+
+ if( total != good_ports )
+ {
+ fails = total - good_ports;
+ TRACFCOMP( g_trac_fsi, "FsiDDTest::test_init> ERROR : Wrong number of ports were initialized : exp=%d, actual=%d", total, good_ports );
+ TS_FAIL( "FsiDDTest::test_init> ERROR : Wrong number of ports were initialized" );
+ }
+
+ TRACFCOMP( g_trac_fsi, "FsiDDTest::test_init> %d/%d fails", fails, total );
+
+ // Execute the reg read/write tests
+ //t_readWrite();
+ //@fixme - waiting for simics patches
+ };
+
+ /**
* @brief FSI DD test - verifyAddressRange
* Test output of verifyAddressRange
*/
void test_verifyAddressRange(void)
{
- TRACFCOMP( g_trac_fsi, "FsiDDTest::verifyAddressRange> Start" );
+ TRACFCOMP( g_trac_fsi, "FsiDDTest::test_verifyAddressRange> Start" );
uint64_t fails = 0;
uint64_t total = 0;
@@ -197,7 +234,7 @@ class FsiDDTest : public CxxTest::TestSuite
// -address before beginning (if not 0)
- TRACFCOMP( g_trac_fsi, "FsiDDTest::verifyAddressRange> %d/%d fails", fails, total );
+ TRACFCOMP( g_trac_fsi, "FsiDDTest::test_verifyAddressRange> %d/%d fails", fails, total );
};
};
OpenPOWER on IntegriCloud