diff options
author | Adam Muhle <armuhle@us.ibm.com> | 2011-10-13 14:44:55 -0500 |
---|---|---|
committer | ADAM R. MUHLE <armuhle@us.ibm.com> | 2011-10-25 15:17:19 -0500 |
commit | 7344f3b265fe12da99ad0a032e558e7cc7fe1cb2 (patch) | |
tree | ff7bd2d0d9ac139e63a0f8bda778e3dac1b290f8 /src/usr/fsiscom/fsiscom.C | |
parent | 0ad20184aec21ef0560a9eee7e7c26a36ace07e1 (diff) | |
download | talos-hostboot-7344f3b265fe12da99ad0a032e558e7cc7fe1cb2.tar.gz talos-hostboot-7344f3b265fe12da99ad0a032e558e7cc7fe1cb2.zip |
Base FSISCOM Support and test Cases. (Story 3880)
Change-Id: Ia65187cd475da725250a17cec59b1aa6ff805f84
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/453
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Tested-by: Jenkins Server
Diffstat (limited to 'src/usr/fsiscom/fsiscom.C')
-rw-r--r-- | src/usr/fsiscom/fsiscom.C | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/usr/fsiscom/fsiscom.C b/src/usr/fsiscom/fsiscom.C new file mode 100644 index 000000000..2788614ed --- /dev/null +++ b/src/usr/fsiscom/fsiscom.C @@ -0,0 +1,347 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/fsiscom/fsiscom.C $ +// +// 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 +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ +#include <string.h> +#include <devicefw/driverif.H> +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <fsiscom/fsiscom_reasoncodes.H> +#include "fsiscom.H" + +//Globals/Constants +// @todo - change to target-specific MUTEX so devices can be accessed in parallel. +static mutex_t g_fsiScomMutex = MUTEX_INITIALIZER; + +// Trace definition +trace_desc_t* g_trac_fsiscom = NULL; +TRAC_INIT(&g_trac_fsiscom, "FSISCOM", 4096); //4K + +// Easy macro replace for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + + +namespace FSISCOM +{ + +union ioData6432 +{ + uint64_t data64; + struct { + uint32_t data32_0; + uint32_t data32_1; + }; +}; + +//@fixme - not full tested due to simics instability. Will full test when +// enabling the scom test cases. + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +errlHndl_t fsiScomPerformOp(DeviceFW::OperationType i_opType, + TARGETING::Target* i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + va_list i_args) +{ + errlHndl_t l_err = NULL; + + uint64_t l_scomAddr = va_arg(i_args,uint64_t); + ioData6432 scratchData; + uint32_t l_command = 0; + uint32_t l_status = 0; + bool need_unlock = false; + size_t op_size = sizeof(uint32_t); + + do{ + + if( io_buflen != sizeof(uint64_t) ) + { + TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Invalid data length : io_buflen=%d", io_buflen ); + /*@ + * @errortype + * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP + * @reasoncode FSISCOM::RC_INVALID_LENGTH + * @userdata1 SCOM Address + * @userdata2 Data Length + * @devdesc FSISCOM: fsiScomPerformOp> Invalid data length (!= 8 bytes) + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + FSISCOM::MOD_FSISCOM_PERFORMOP, + FSISCOM::RC_INVALID_LENGTH, + l_scomAddr, + TO_UINT64(io_buflen)); + //@fixme: Need to callout target somehow. Need to decide how to callout target and where + // it should be done (this layer or somewhere higher in the call stack?) + break; + } + + if( (l_scomAddr & 0xFFFFFFFF80000000) != 0) + { + TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Address contains more than 31 bits : l_scomAddr=0x%.8x", l_scomAddr ); + /*@ + * @errortype + * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP + * @reasoncode FSISCOM::RC_INVALID_ADDRESS + * @userdata1 SCOM Address + * @userdata2 0 + * @devdesc FSISCOM: fsiScomPerformOp> Address contains more than 31 bits. + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + FSISCOM::MOD_FSISCOM_PERFORMOP, + FSISCOM::RC_INVALID_ADDRESS, + l_scomAddr, + 0); + //@fixme: Need to callout target somehow. Need to decide how to callout target and where + // it should be done (this layer or somewhere higher in the call stack?) + break; + } + + l_command = static_cast<uint32_t>(l_scomAddr & 0x000000007FFFFFFF); + + + if(i_opType == DeviceFW::WRITE) + { + memcpy(&(scratchData.data64), io_buffer, 8); + + TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp> Write(l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X)", l_scomAddr, scratchData.data32_0, scratchData.data32_1); + + + // atomic section >> + mutex_lock(&g_fsiScomMutex); + need_unlock = true; + + + //write bits 0-31 to data0 + l_err = DeviceFW::deviceOp( DeviceFW::WRITE, + i_target, + &scratchData.data32_0, + op_size, + DEVICE_FSI_ADDRESS(DATA0_REG)); + if(l_err) + { + break; + } + + //write bits 32-63 to data1 + l_err = DeviceFW::deviceOp( DeviceFW::WRITE, + i_target, + &scratchData.data32_1, + op_size, + DEVICE_FSI_ADDRESS(DATA1_REG)); + if(l_err) + { + break; + } + + //write to FSI2PIB command reg starts write operation + //bit 0 high => write command + l_command = 0x80000000 | l_command; + l_err = DeviceFW::deviceOp( DeviceFW::WRITE, + i_target, + &l_command, + op_size, + DEVICE_FSI_ADDRESS(COMMAND_REG)); + if(l_err) + { + break; + } + + //check status reg to see result + l_err = DeviceFW::deviceOp( DeviceFW::READ, + i_target, + &l_status, + op_size, + DEVICE_FSI_ADDRESS(STATUS_REG)); + if(l_err) + { + break; + } + + // atomic section << + need_unlock = false; + mutex_unlock(&g_fsiScomMutex); + + //bits 17-19 indicates PCB/PIB error + if(l_status & 0x00007000) + { + TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Write: PCB/PIB error received: l_status=0x%X)", l_status); + /*@ + * @errortype + * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP + * @reasoncode FSISCOM::RC_WRITE_ERROR + * @userdata1 SCOM Addr + * @userdata2 SCOM Status Reg + * @devdesc fsiScomPerformOp> Error returned from SCOM Engine after write + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + FSISCOM::MOD_FSISCOM_PERFORMOP, + FSISCOM::RC_WRITE_ERROR, + l_scomAddr, + TO_UINT64(l_status)); + + //@fixme: Need to callout target somehow. Need to decide how to callout target and where + // it should be done (this layer or somewhere higher in the call stack?) + //@todo: May add recover actions later. Currently undefined + + break; + } + + + + } + else if(i_opType == DeviceFW::READ) + { + TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read(l_scomAddr=0x%.8X)", l_scomAddr); + + // atomic section >> + mutex_lock(&g_fsiScomMutex); + need_unlock = true; + + + //write to FSI2PIB command reg starts read operation + // bit 0 low -> read command + l_err = DeviceFW::deviceOp( DeviceFW::WRITE, + i_target, + &l_command, + op_size, + DEVICE_FSI_ADDRESS(COMMAND_REG)); + if(l_err) + { + break; + } + + //check ststus reg to see result + l_err = DeviceFW::deviceOp( DeviceFW::READ, + i_target, + &l_status, + op_size, + DEVICE_FSI_ADDRESS(STATUS_REG)); + if(l_err) + { + break; + } + + //bits 17-19 indicates PCB/PIB error + if((l_status & 0x00007000) != 0) + { + TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Read: PCB/PIB error received: l_status=0x%.8X)", l_status); + + /*@ + * @errortype + * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP + * @reasoncode FSISCOM::RC_READ_ERROR + * @userdata1 SCOM Addr + * @userdata2 SCOM Status Reg + * @devdesc fsiScomPerformOp> Error returned from SCOM Engine after read. + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + FSISCOM::MOD_FSISCOM_PERFORMOP, + FSISCOM::RC_READ_ERROR, + l_scomAddr, + TO_UINT64(l_status)); + + //@fixme: Need to callout target somehow. Need to decide how to callout target and where + // it should be done (this layer or somewhere higher in the call stack?) + //@todo: May add recover actions later. Currently undefined + break; + } + + //read bits 0-31 to data0 + l_err = DeviceFW::deviceOp( DeviceFW::READ, + i_target, + &scratchData.data32_0, + op_size, + DEVICE_FSI_ADDRESS(DATA0_REG)); + if(l_err) + { + break; + } + + //read bits 32-63 to data1 + l_err = DeviceFW::deviceOp( DeviceFW::READ, + i_target, + &scratchData.data32_1, + op_size, + DEVICE_FSI_ADDRESS(DATA1_REG)); + if(l_err) + { + break; + } + + // atomic section << + need_unlock = false; + mutex_unlock(&g_fsiScomMutex); + + TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read: l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X", l_scomAddr, scratchData.data32_0, scratchData.data32_1); + + memcpy(io_buffer, &(scratchData.data64), 8); + } + else + { + TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Read: PCB/PIB error received: l_status=0x%.8X)", l_status); + + /*@ + * @errortype + * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP + * @reasoncode FSISCOM::RC_READ_ERROR + * @userdata1 Operation Type (i_opType) : 0=READ, 1=WRITE + * @userdata2 0 + * @devdesc fsiScomPerformOp> Unsupported Operation Type specified + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + FSISCOM::MOD_FSISCOM_PERFORMOP, + FSISCOM::RC_READ_ERROR, + TO_UINT64(i_opType), + 0); + + //@fixme: Need to callout target somehow. Need to decide how to callout target and where + // it should be done (this layer or somewhere higher in the call stack?) + break; + + } + + }while(0); + + if( need_unlock ) + { + mutex_unlock(&g_fsiScomMutex); + } + + + return l_err; + +} + +// Register SCom access functions to DD framework +DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD, + DeviceFW::FSISCOM, + TARGETING::TYPE_PROC, + fsiScomPerformOp); + + +} // end namespace |