diff options
author | Dan Crowell <dcrowell@us.ibm.com> | 2011-09-08 16:08:26 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2011-10-05 12:49:57 -0500 |
commit | 336f6ac6abc1d5ee4efc1229be06a66baf06643b (patch) | |
tree | e3476d2423567ad81249cc215d195dbc36c4a04f /src/usr | |
parent | 485bb5c0e6d2c7c5df6560a996dc264e94f2058a (diff) | |
download | blackbird-hostboot-336f6ac6abc1d5ee4efc1229be06a66baf06643b.tar.gz blackbird-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/usr')
-rw-r--r-- | src/usr/fsi/fsidd.C | 937 | ||||
-rw-r--r-- | src/usr/fsi/fsidd.H | 296 | ||||
-rw-r--r-- | src/usr/fsi/test/fsiddtest.H | 79 |
3 files changed, 974 insertions, 338 deletions
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 ); }; }; |