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/fsi/fsidd.C | |
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/fsi/fsidd.C')
-rw-r--r-- | src/usr/fsi/fsidd.C | 937 |
1 files changed, 713 insertions, 224 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; +} + |