diff options
author | Missy Connell <missyc@us.ibm.com> | 2011-12-06 13:06:18 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-01-24 14:43:04 -0600 |
commit | 52b60aea13ffc9a8d67a6714e1416402fd203139 (patch) | |
tree | 209e89b8fdeb35126712c2d75bb49b6eb396be36 /src | |
parent | 8514ef2acf01728b5a07fbd3c94999375cc0aec6 (diff) | |
download | talos-hostboot-52b60aea13ffc9a8d67a6714e1416402fd203139.tar.gz talos-hostboot-52b60aea13ffc9a8d67a6714e1416402fd203139.zip |
Indirect SCOM support
Added locking
Change-Id: If2b3c2d69bb533a65cd9b41c1eaf595e979f93aa
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/562
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/usr/scom/scom.C | 113 | ||||
-rw-r--r-- | src/usr/scom/scom.H | 36 | ||||
-rw-r--r-- | src/usr/scom/test/scomtest.H | 142 | ||||
-rw-r--r-- | src/usr/targeting/xmltohb/attribute_types.xml | 13 | ||||
-rw-r--r-- | src/usr/targeting/xmltohb/target_types.xml | 8 |
5 files changed, 303 insertions, 9 deletions
diff --git a/src/usr/scom/scom.C b/src/usr/scom/scom.C index ed5ffb306..8bfdbf004 100644 --- a/src/usr/scom/scom.C +++ b/src/usr/scom/scom.C @@ -55,6 +55,8 @@ DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD, TARGETING::TYPE_MEMBUF, scomPerformOp); + + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType, @@ -65,6 +67,112 @@ errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType, va_list i_args) { errlHndl_t l_err = NULL; + mutex_t* l_mutex = NULL; + + uint64_t l_scomAddr = va_arg(i_args,uint64_t); + + // If the indirect scom bit is 0, then doing a regular scom + if( (l_scomAddr & 0x8000000000000000) == 0) + { + l_err = doScomOp(i_opType, + i_target, + io_buffer, + io_buflen, + i_accessType, + l_scomAddr); + } + // We are performing an indirect scom. + else + { + uint64_t l_io_buffer; + uint64_t temp_scomAddr; + + memcpy(&l_io_buffer, io_buffer, 8); + memcpy(&temp_scomAddr, &l_scomAddr, 8); + + // Get the 20bit indirect scom address + temp_scomAddr = temp_scomAddr & 0x001FFFFF00000000; + + // Zero out the indirect address location.. leave the 16bits of data + l_io_buffer = l_io_buffer & 0x000000000000FFFF; + + // OR in the 20bit indirect address + l_io_buffer = l_io_buffer | temp_scomAddr; + + // zero out the indirect address from the buffer.. + l_scomAddr = l_scomAddr & 0x00000000EFFFFFFFF; + + // If we are doing a read. We need to do a write first.. + if(i_opType == DeviceFW::READ) + { + + // use the chip-specific mutex attribute + l_mutex = i_target->getHbMutexAttr<TARGETING::ATTR_SCOM_IND_MUTEX>(); + + mutex_lock(l_mutex); + + // turn the read bit on. + l_io_buffer = l_io_buffer | 0x8000000000000000; + + // perform write before the read with the new + // IO_buffer with the imbedded indirect scom addr. + l_err = doScomOp(DeviceFW::WRITE, + i_target, + & l_io_buffer, + io_buflen, + i_accessType, + l_scomAddr); + + if (l_err != NULL) + { + mutex_unlock(l_mutex); + return l_err; + } + + // Now perform the op requested using the passed in + // IO_Buffer to pass the read data back to caller. + l_err = doScomOp(i_opType, + i_target, + io_buffer, + io_buflen, + i_accessType, + l_scomAddr); + + mutex_unlock(l_mutex); + + } + else //write + { + + // Turn the read bit off. + l_io_buffer = l_io_buffer & 0x7FFFFFFFFFFFFFFF; + + // Now perform the op requested using the + // locai io_buffer with the indirect addr imbedded. + l_err = doScomOp(i_opType, + i_target, + & l_io_buffer, + io_buflen, + i_accessType, + l_scomAddr); + } + } + + return l_err; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +errlHndl_t doScomOp(DeviceFW::OperationType i_opType, + TARGETING::Target* i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + uint64_t i_addr) +{ + + errlHndl_t l_err = NULL; do{ //Always XSCOM the Master Sentinel @@ -76,7 +184,7 @@ errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType, i_target, io_buffer, io_buflen, - DEVICE_XSCOM_ADDRESS(va_arg(i_args,uint64_t))); + DEVICE_XSCOM_ADDRESS(i_addr)); break; } else if(i_target->getAttr<TARGETING::ATTR_SCOM_SWITCHES>().useFsiScom) @@ -85,7 +193,7 @@ errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType, i_target, io_buffer, io_buflen, - DEVICE_FSISCOM_ADDRESS(va_arg(i_args,uint64_t))); + DEVICE_FSISCOM_ADDRESS(i_addr)); if( l_err ) { break; } } else @@ -101,5 +209,4 @@ errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType, } - } // end namespace diff --git a/src/usr/scom/scom.H b/src/usr/scom/scom.H index d91eb41ee..f39720aae 100644 --- a/src/usr/scom/scom.H +++ b/src/usr/scom/scom.H @@ -34,10 +34,9 @@ namespace SCOM /** - * @brief Performs an SCom operation - * This function performs an SCom Read/Write operation. It follows a - * pre-defined prototype functions in order to be registered with the - * device-driver framework. + * @brief Performs a SCom operation + * This function performs a SCOM operation by calling doScomOP. It + * handles whether the address a regular or an indirect SCOM address * * @param[in] i_opType Operation type, see DeviceFW::OperationType * in driverif.H @@ -63,6 +62,35 @@ errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType, va_list i_args); +/** + * @brief Performs a SCom operation + * This function performs an SCom Read/Write operation. It follows a + * pre-defined prototype functions in order to be registered with the + * device-driver framework. + * + * @param[in] i_opType Operation type, see DeviceFW::OperationType + * in driverif.H + * @param[in] i_target SCom target + * @param[in/out] io_buffer Read: pointer to output data storage + * Write: pointer to data to be written + * @param[in/out] io_buflen Input: size of io_buffer (in bytes) + * Output: Read: size of output data + * Write: size of data written + * @param[in] i_accessType Select from DeviceFW::AccessType enum + * (usrif.H) + * @param[in] i_args This is an argument list for DD framework. + * In this function, there's only one argument, + * which is the SCom address value. + * + * @return errlHndl_t + */ +errlHndl_t doScomOp(DeviceFW::OperationType i_opType, + TARGETING::Target* i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + uint64_t i_addr); + }; // End namespace diff --git a/src/usr/scom/test/scomtest.H b/src/usr/scom/test/scomtest.H index 5c8fab902..7545b795b 100644 --- a/src/usr/scom/test/scomtest.H +++ b/src/usr/scom/test/scomtest.H @@ -35,7 +35,7 @@ #include <errl/errltypes.H> #include <devicefw/userif.H> #include <fsi/fsiif.H> - +#include <sys/time.h> //mc99 remove extern trace_desc_t* g_trac_scom; @@ -336,11 +336,149 @@ public: } + /** + * @brief SCOM test Indirect SCOM + * + */ + + void test_IndirectScom(void) + { + TRACFCOMP( g_trac_scom, "ScomTest::test_IndirectScomReadWrite> Start" ); + + uint64_t fails = 0; + uint64_t total = 0; + errlHndl_t l_err = NULL; + + + // Setup some targets to use + enum { + myPROC9, + NUM_TARGETS + }; + TARGETING::Target* scom_targets[NUM_TARGETS]; + for( uint64_t x = 0; x < NUM_TARGETS; x++ ) + { + scom_targets[x] = NULL; + } + + + // Target Proc 9 - the FSI wrap-back connection in simics + TARGETING::EntityPath epath(TARGETING::EntityPath::PATH_PHYSICAL); + epath.addLast(TARGETING::TYPE_SYS,0); + epath.addLast(TARGETING::TYPE_NODE,0); + epath.addLast(TARGETING::TYPE_PROC,9); + + scom_targets[myPROC9] = TARGETING::targetService().toTarget(epath); + + for( uint64_t x = 0; x < NUM_TARGETS; x++ ) + { + //only run if the target exists + if(scom_targets[x] == NULL) + { + TRACFCOMP( g_trac_scom, "ScomTest - TARGET = NULL - 1 x = %d", x); + continue; + } + else if ((scom_targets[x]->getAttr<TARGETING::ATTR_SCOM_SWITCHES>().useXscom == 0) && + (scom_targets[x]->getAttr<TARGETING::ATTR_SCOM_SWITCHES>().useFsiScom == 0)) + { + // If both FSI and XSCOM are not enabled.. then ignore.. + TRACFCOMP(g_trac_scom, "INDIRECT SCOM>> SKIPPING "); + scom_targets[x] = NULL; //remove from our list + } + + } + + // scratch data to use + //@fixme: Need to either fabricate some fake registers to use or save off data before modifying SCOMs to avoid + // corrupting the HW. + + struct { + TARGETING::Target* target; + uint64_t addr; + uint64_t data; + } test_data[] = { + { scom_targets[myPROC9], 0x80040C0102011A3F ,0x1234432112344321}, + { scom_targets[myPROC9], 0x800C140002011E3F, 0x123443211234ABAB}, + }; + const uint64_t NUM_ADDRS = sizeof(test_data)/sizeof(test_data[0]); + + + size_t op_size = sizeof(uint32_t); + + // write all the test registers + for( uint64_t x = 0; x < NUM_ADDRS; x++ ) + { + //only run if the target exists + if(test_data[x].target == NULL) + { + continue; + } + + op_size = sizeof(uint64_t); + + total++; + l_err = deviceWrite( test_data[x].target, + &(test_data[x].data), + op_size, + DEVICE_SCOM_ADDRESS(test_data[x].addr) ); + if( l_err ) + { + TRACFCOMP(g_trac_scom, "ScomTest::test_IndirectScom_proc> [%d] Write: Error from device : addr=0x%X, RC=%X", x, test_data[x].addr, l_err->reasonCode() ); + TS_FAIL( "ScomTest::test_IndirectScom_proc> ERROR : Unexpected error log from write1" ); + fails++; + errlCommit(l_err,SCOM_COMP_ID); + delete l_err; + } + } + + // allocate space for read data + uint64_t read_data[NUM_ADDRS]; + + memset(read_data, 0, sizeof read_data); + + // read all the test registers + for( uint64_t x = 0; x < NUM_ADDRS; x++ ) + { + //only run if the target exists + if(test_data[x].target == NULL) + { + continue; + } + + op_size = sizeof(uint64_t); + + total++; + l_err = deviceRead( test_data[x].target, + &(read_data[x]), + op_size, + DEVICE_SCOM_ADDRESS(test_data[x].addr) ); + + if( l_err ) + { + TRACFCOMP(g_trac_scom, "ScomTest::test_IndirectScomreadWrite_proc> [%d] Read: Error from device : addr=0x%X, RC=%X", x, test_data[x].addr, l_err->reasonCode() ); + TS_FAIL( "ScomTest::test_IndirectScomreadWrite_proc> ERROR : Unexpected error log from write1" ); + fails++; + errlCommit(l_err,SCOM_COMP_ID); + delete l_err; + } + else if((read_data[x] & 0x000000000000FFFF) != (test_data[x].data & 0x000000000000FFFF)) + { + TRACFCOMP(g_trac_scom, "ScomTest::test_IndirectScomreadWrite_proc> [%d] Read: Data miss-match : addr=0x%X, read_data=0x%llx, write_data=0x%llx", x, test_data[x].addr, read_data[x], test_data[x].data); + TS_FAIL( "ScomTest::test_IndirectScomreadWrite_proc> ERROR : Data miss-match between read and expected data" ); + fails++; + } + + } + + TRACFCOMP( g_trac_scom, "ScomTest::test_IndirectScomreadWrite_proc> %d/%d fails", fails, total ); + + } + //@todo - write tests to verify connection between XSCOM and FSISCOM //@todo - write error path testcase for FSI scom using bad address - //@todo - indirect scom + //@todo - address translation diff --git a/src/usr/targeting/xmltohb/attribute_types.xml b/src/usr/targeting/xmltohb/attribute_types.xml index 9adbbb126..94785e06a 100644 --- a/src/usr/targeting/xmltohb/attribute_types.xml +++ b/src/usr/targeting/xmltohb/attribute_types.xml @@ -2768,4 +2768,17 @@ </hwpfToHbAttrMap> </attribute> +<attribute> + <id>SCOM_IND_MUTEX</id> + <description>Mutex for Indirect SCOM read operation</description> + <simpleType> + <hbmutex> + <default>0</default> + </hbmutex> + </simpleType> + <persistency>volatile-zeroed</persistency> + <readable/> + <writeable/> +</attribute> + </attributes> diff --git a/src/usr/targeting/xmltohb/target_types.xml b/src/usr/targeting/xmltohb/target_types.xml index a4be0cab1..67e922b5d 100644 --- a/src/usr/targeting/xmltohb/target_types.xml +++ b/src/usr/targeting/xmltohb/target_types.xml @@ -144,6 +144,10 @@ <attribute> <id>FSI_SCOM_MUTEX</id> </attribute> + <attribute> + <id>SCOM_IND_MUTEX</id> + </attribute> + </targetType> <targetType> @@ -685,6 +689,10 @@ <attribute> <id>FSI_SCOM_MUTEX</id> </attribute> + <attribute> + <id>SCOM_IND_MUTEX</id> + </attribute> + </targetType> <!-- Centaur MBS --> |