summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/utils
diff options
context:
space:
mode:
authorPrem Shanker Jha <premjha2@in.ibm.com>2015-11-12 03:36:55 -0600
committerStephen Cprek <smcprek@us.ibm.com>2016-02-19 17:08:23 -0600
commit548a746856d6095fd4585253893d78b74205f926 (patch)
treeac8bdce8358cc2aae8d6d329dc6df675d717b387 /src/import/chips/p9/procedures/utils
parent5c52f2606c25ccaa3d500323914257cd988c52d9 (diff)
downloadtalos-hostboot-548a746856d6095fd4585253893d78b74205f926.tar.gz
talos-hostboot-548a746856d6095fd4585253893d78b74205f926.zip
PM: Updated Stop API based on modified HOMER layout.
This commit updates the STOP APIs to accomodate changes made in HOMER layout. CME region begins at an offset of 2MB wrt start of HOMER whereas STOP GPE regions begins at 1 MB wrt start of HOMER. There are some corrections for minor coding aesthetics issues. Change-Id: I2914635fa7223654b89a084e17e33065b1655762 RTC: 140797 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/21985 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/utils')
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_cpu_reg_restore_instruction.H69
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_stop_api.C982
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_stop_api.H150
-rw-r--r--src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.mk21
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_stop_data_struct.H133
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_stop_section_defines.H96
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_stop_util.C169
-rwxr-xr-xsrc/import/chips/p9/procedures/utils/stopreg/p9_stop_util.H122
8 files changed, 1742 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_cpu_reg_restore_instruction.H b/src/import/chips/p9/procedures/utils/stopreg/p9_cpu_reg_restore_instruction.H
new file mode 100755
index 000000000..fcbe317c6
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_cpu_reg_restore_instruction.H
@@ -0,0 +1,69 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_cpu_reg_restore_instruction.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_cpu_reg_restore_instruction.H
+/// @brief enumerates all the opcodes used for SPR restoration.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#ifndef __REG_RESTORE_INSTRUCTION_H
+#define __REG_RESTORE_INSTRUCTION_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace stopImageSection
+{
+
+/**
+ * @brief enumerates opcodes for few instructions.
+ */
+enum
+{
+ ORI_OPCODE = 24,
+ RFI_OPCODE = 19,
+ RFI_CONST = 50,
+ ORIS_OPCODE = 25,
+ OPCODE_31 = 31,
+ XOR_CONST = 316,
+ RLDIMI_OPCODE = 30,
+ RLDIMI_CONST = 3,
+ MTSPR_CONST1 = 467,
+ MTMSRD_CONST1 = 178,
+ MR_INT = 0x7c0a0378,
+ BLR_INST = 0x4e800020,
+ MTSPR_BASE_OPCODE = 0x7c0003a6,
+ ATTN_OPCODE = 0x00000200,
+};
+
+} // namespace stopImageSection ends
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //__REG_RESTORE_INSTRUCTION_H
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.C b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.C
new file mode 100755
index 000000000..4bde2e425
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.C
@@ -0,0 +1,982 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_stop_api.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_api.C
+/// @brief implements STOP API which create/manipulate STOP image.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#include "p9_stop_api.H"
+#include "p9_cpu_reg_restore_instruction.H"
+#include "p9_stop_data_struct.H"
+#include <string.h>
+#include "p9_stop_util.H"
+#include <stdio.h>
+
+#ifdef __FAPI_2_
+ #include <fapi2.H>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace stopImageSection
+{
+const StopSprReg_t g_sprRegister[] =
+{
+ { P9_STOP_SPR_HSPRG0, true },
+ { P9_STOP_SPR_HRMOR, false },
+ { P9_STOP_SPR_LPCR, true },
+ { P9_STOP_SPR_HMEER, false },
+ { P9_STOP_SPR_PSSCR, true },
+ { P9_STOP_SPR_PMCR, false },
+ { P9_STOP_SPR_HID, false },
+ { P9_STOP_SPR_MSR, true },
+ { P9_STOP_SPR_DAWR, true },
+};
+
+const uint32_t MAX_SPR_SUPPORTED =
+ sizeof ( g_sprRegister ) / sizeof( StopSprReg_t );
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validates input arguments provided by STOP API caller.
+ * @param[in] i_pImage pointer to beginning of chip's HOMER image.
+ * @param[in] i_regId SPR register id
+ * @param[in] i_coreId core id
+ * @param[in|out] io_threadId thread id
+ * @param[in|out] io_threadLevelReg true if register is of thread scope, false if of
+ * core scope.
+ * @return STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
+ * @note for register of scope core, function shall force io_threadId to
+ * zero.
+ */
+StopReturnCode_t validateSprImageInputs( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint32_t i_coreId,
+ uint32_t& io_threadId,
+ bool& io_threadLevelReg )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ bool sprSupported = false;
+ io_threadLevelReg = false;
+
+ do
+ {
+ if( NULL == i_pImage )
+ {
+ // Error: HOMER image start location is not valid
+ // Cannot proceed further. So, let us exit.
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ MY_ERR( "invalid image location " );
+
+ break;
+ }
+
+ // STOP API manages STOP image based on physical core Id. PIR value
+ // is interpreted to calculate the physical core number and virtual
+ // thread number.
+ if( MAX_CORE_ID_SUPPORTED < i_coreId )
+ {
+ // Error: invalid core number. given core number exceeds maximum
+ // cores supported by chip.
+
+ // Physical core number is calculated based on following formula:
+ // core id = 4 * quad id (0..5) + core no within quad ( 0..3)
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ MY_ERR( "invalid core id " );
+ break;
+ }
+
+ if( MAX_THREAD_ID_SUPPORTED < io_threadId )
+ {
+ //Error: invalid core thread. Given core thread exceeds maximum
+ //threads supported in a core.
+
+ // 64 bit PIR value is interpreted to calculate virtual thread
+ // Id. In fuse mode, b61 and b62 gives virtual thread id whereas in
+ // non fuse mode, b62 and b63 is read to determine the same.
+
+ l_rc = STOP_SAVE_ARG_INVALID_THREAD;
+ MY_ERR( "invalid thread " );
+ break;
+ }
+
+ for( uint32_t index = 0; index < MAX_SPR_SUPPORTED; ++index )
+ {
+ if( i_regId == g_sprRegister[index].sprId )
+ {
+ // given register is in the list of register supported
+ sprSupported = true;
+ io_threadLevelReg = g_sprRegister[index].isThreadScope;
+ io_threadId = io_threadLevelReg ? io_threadId : 0;
+ break;
+ }
+ }
+
+ if( !sprSupported )
+ {
+ // Following SPRs are supported
+ // trace out all registers supported
+ MY_ERR("Register not supported" );
+ // error code to caller.
+ l_rc = STOP_SAVE_ARG_INVALID_REG;
+ break;
+ }
+
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR( "image 0x%08x, regId %08d, coreId %d, "
+ "threadId %d return code 0x%08x", i_pImage, i_regId,
+ i_coreId, io_threadId, l_rc );
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates ori instruction code.
+ * @param[in] i_Rs Source register number
+ * @param[in] i_Ra destination regiser number
+ * @param[in] i_data 16 bit immediate data
+ * @return returns 32 bit instruction representing ori instruction.
+ */
+uint32_t getOriInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_data )
+{
+ uint32_t oriInstOpcode = 0;
+ oriInstOpcode = 0;
+ oriInstOpcode = ORI_OPCODE << 26;
+ oriInstOpcode |= i_Rs << 21;
+ oriInstOpcode |= i_Rs << 16;
+ oriInstOpcode |= i_data;
+
+ return SWIZZLE_4_BYTE(oriInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates 32 bit key used for SPR lookup in core section.
+ */
+uint32_t genKeyForSprLookup( const CpuReg_t i_regId )
+{
+ return getOriInstruction( 0, 0, (uint16_t) i_regId );
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates xor instruction code.
+ * @param[in] i_Rs source register number for xor operation
+ * @param[in] i_Ra destination register number for xor operation result
+ * @param[in] i_Rb source register number for xor operation
+ * @return returns 32 bit instruction representing xor immediate instruction.
+ */
+uint32_t getXorInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
+ const uint16_t i_Rb )
+{
+ uint32_t xorRegInstOpcode;
+ xorRegInstOpcode = XOR_CONST << 1;
+ xorRegInstOpcode |= OPCODE_31 << 26;
+ xorRegInstOpcode |= i_Rs << 21;
+ xorRegInstOpcode |= i_Rs << 16;
+ xorRegInstOpcode |= i_Rb << 11;
+
+ return SWIZZLE_4_BYTE(xorRegInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates xor instruction code.
+ * @param[in] i_Rs source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_data 16 bit immediate data
+ * @return returns 32 bit instruction representing xor immediate instruction.
+ */
+uint32_t getOrisInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_data )
+{
+ uint32_t orisInstOpcode;
+ orisInstOpcode = 0;
+ orisInstOpcode = ORIS_OPCODE << 26;
+ orisInstOpcode |= ( i_Rs & 0x001F ) << 21 | ( i_Ra & 0x001F ) << 16;
+ orisInstOpcode |= i_data;
+
+ return SWIZZLE_4_BYTE(orisInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates instruction for mtspr
+ * @param[in] i_Rs source register number
+ * @param[in] i_Spr represents spr where data is to be moved.
+ * @return returns 32 bit instruction representing mtspr instruction.
+ */
+uint32_t getMtsprInstruction( const uint16_t i_Rs, const uint16_t i_Spr )
+{
+ uint32_t mtsprInstOpcode = 0;
+ uint32_t temp = (( i_Spr & 0x03FF ) << 11);
+ mtsprInstOpcode = ( temp & 0x0000F800 ) << 5;
+ mtsprInstOpcode |= ( temp & 0x001F0000 ) >> 5;
+ mtsprInstOpcode |= MTSPR_BASE_OPCODE;
+
+ return SWIZZLE_4_BYTE(mtsprInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates xor instruction code.
+ * @param[in] i_Rs source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_sh1 position by which contents of i_Rs are to be shifted
+ * @param[in] i_MB shift poistion start
+ * @return returns 32 bit instruction representing rldimi instruction.
+ */
+uint32_t getRldimiInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_sh1, uint16_t i_MB )
+{
+ // limited support of this instruction
+ uint32_t rldimiInstOpcode = 0;
+ rldimiInstOpcode = 0;
+ rldimiInstOpcode = ((RLDIMI_OPCODE << 26 ) | ( i_Rs << 21 ) | ( i_Ra << 16 ));
+ rldimiInstOpcode |= ( ( i_sh1 & 0x001F ) << 11 ) | (RLDIMI_CONST << 2 );
+ rldimiInstOpcode |= (( i_sh1 & 0x0020 ) >> 4);
+ rldimiInstOpcode |= (i_MB & 0x003F ) << 5;
+ return SWIZZLE_4_BYTE(rldimiInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates instruction for mtmsr instruction.
+ * @param[in] i_Rs source register number
+ * @return returns 32 bit instruction representing mtmsr instruction.
+ * @note moves contents of register i_Rs to MSR register.
+ */
+uint32_t getMtmsrdInstruction( const uint16_t i_Rs )
+{
+ uint32_t mtmsrdInstOpcode = 0;
+ mtmsrdInstOpcode = 0;
+ mtmsrdInstOpcode = OPCODE_31 << 26;
+ mtmsrdInstOpcode |= i_Rs << 21 | ( MTMSRD_CONST1 << 1 );
+
+ return SWIZZLE_4_BYTE(mtmsrdInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief looks up entry for given SPR in given thread/core section.
+ * @param[in] i_pThreadSectLoc start of given thread section or core section.
+ * @param[in] i_lookUpKey search key for lookup of given SPR entry.
+ * @param[in] i_isCoreReg true if register is of scope core, false
+ * otherwise.
+ * @param[in|out] io_pSprEntryLoc Input: NULL
+ * Output: location of given entry or end of table.
+ * @return STOP_SAVE_SUCCESS if entry is found, STOP_SAVE_FAIL in case of
+ * an error.
+ */
+StopReturnCode_t lookUpSprInImage( uint32_t* i_pThreadSectLoc,
+ const uint32_t i_lookUpKey,
+ const bool i_isCoreReg,
+ void*& io_pSprEntryLoc )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_FAIL;
+ uint32_t temp = i_isCoreReg ? CORE_SPR_SECTN_SIZE : THREAD_SECTN_SIZE;
+ uint32_t* i_threadSectEnd = i_pThreadSectLoc + temp;
+ uint32_t bctr_inst = SWIZZLE_4_BYTE(BLR_INST);
+ io_pSprEntryLoc = NULL;
+
+ do
+ {
+ if( !i_pThreadSectLoc )
+ {
+ break;
+ }
+
+ temp = 0;
+
+ while( ( i_pThreadSectLoc <= i_threadSectEnd ) &&
+ ( temp != bctr_inst ) )
+ {
+ temp = *i_pThreadSectLoc;
+
+ if( ( temp == i_lookUpKey ) || ( temp == bctr_inst ) )
+ {
+ io_pSprEntryLoc = i_pThreadSectLoc;
+ l_rc = STOP_SAVE_SUCCESS;
+ break;
+ }
+
+ i_pThreadSectLoc = i_pThreadSectLoc + SIZE_PER_SPR_RESTORE_INST;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief updates an SPR STOP image entry.
+ * @param[in] i_pSprEntryLocation location of entry.
+ * @param[in] i_regId register Id associated with SPR.
+ * @param[in] i_regData data needs to be written to SPR entry.
+ * @return STOP_SAVE_SUCCESS if update works, STOP_SAVE_FAIL otherwise.
+ */
+StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t tempInst = 0;
+ typedef union
+ {
+ uint64_t regData;
+ uint16_t dataBit[4];
+ } RegData;
+
+ do
+ {
+ if( !i_pSprEntryLocation )
+ {
+ MY_ERR("invalid location of SPR image entry" );
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ RegData regValue;
+ regValue.regData = i_regData;
+
+ tempInst = genKeyForSprLookup( i_regId );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = getXorInstruction( 0, 0, 0 );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = getOrisInstruction( 0, 0, regValue.dataBit[0] );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = getOriInstruction( 0, 0, regValue.dataBit[1] );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = getRldimiInstruction(0, 0, 32, 0);
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = getOrisInstruction( 0, 0, regValue.dataBit[2] );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = getOriInstruction( 0, 0, regValue.dataBit[3] );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ if( P9_STOP_SPR_MSR == i_regId )
+ {
+ tempInst = getMtmsrdInstruction( 0 );
+ }
+ else if (P9_STOP_SPR_HRMOR == i_regId )
+ {
+ tempInst = SWIZZLE_4_BYTE(MR_INT);
+ }
+ else
+ {
+ tempInst =
+ getMtsprInstruction( 0, (uint16_t)i_regId );
+ }
+
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempInst = SWIZZLE_4_BYTE(BLR_INST);
+ *i_pSprEntryLocation = tempInst;
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+StopReturnCode_t p9_stop_save_cpureg( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const uint64_t i_pir )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS; // procedure return code
+ HomerSection_t* chipHomer = NULL;
+
+ do
+ {
+ uint32_t threadId = 0;
+ uint32_t coreId = 0;
+ uint32_t lookUpKey = 0;
+ void* pSprEntryLocation = NULL; // an offset w.r.t. to start of image
+ void* pThreadLocation = NULL;
+ bool threadScopeReg = false;
+
+ l_rc = getCoreAndThread( i_pImage, i_pir, coreId, threadId );
+ MY_INF( " PIR 0x%016llx coreId %d threadid %d "
+ " registerId %d", i_pir, coreId,
+ threadId, i_regId );
+ // First of all let us validate all input arguments.
+ l_rc = validateSprImageInputs( i_pImage,
+ i_regId,
+ coreId,
+ threadId,
+ threadScopeReg );
+
+ if( l_rc )
+ {
+ // Error: bad argument traces out error code
+ MY_ERR("Bad input argument rc %d", l_rc );
+
+ break;
+ }
+
+ chipHomer = ( HomerSection_t*)i_pImage;
+
+ if( threadScopeReg )
+ {
+ pThreadLocation =
+ &(chipHomer->coreThreadRestore[coreId][threadId].threadArea[0]);
+ }
+ else
+ {
+ pThreadLocation =
+ &(chipHomer->coreThreadRestore[coreId][threadId].coreArea[0]);
+ }
+
+ if( SWIZZLE_4_BYTE(ATTN_OPCODE) == *(uint32_t*)pThreadLocation )
+ {
+ // table for given core id doesn't exit. It needs to be
+ // defined.
+ pSprEntryLocation = pThreadLocation;
+ }
+ else
+ {
+ // an SPR restore section for given core already exists
+ lookUpKey = genKeyForSprLookup( i_regId );
+ l_rc = lookUpSprInImage( (uint32_t*)pThreadLocation,
+ lookUpKey,
+ threadScopeReg,
+ pSprEntryLocation );
+ }
+
+
+ if( l_rc )
+ {
+ MY_ERR("Invalid or corrupt SPR entry. CoreId 0x%08x threadId ",
+ "0x%08x regId 0x%08x lookUpKey 0x%08x pThreadLocation 0x%08x"
+ , coreId, threadId, i_regId, lookUpKey, pThreadLocation );
+ break;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) pSprEntryLocation,
+ i_regId,
+ i_regData );
+
+ if( l_rc )
+ {
+ MY_ERR( " Failed to update the SPR entry of PIR 0x%08x reg"
+ "0x%08x", i_pir, i_regId );
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validates all the input arguments.
+ * @param[in] i_pImage pointer to start of HOMER of image for proc chip.
+ * @param[in] i_scomAddress SCOM address of register.
+ * @param[in] i_chipletId core or cache chiplet id
+ * @param[in] i_operation operation requested for SCOM entry.
+ * @param[in] i_section image section on which operation is to be performed
+ * @return STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
+ * @note Function does not validate that the given SCOM address really
+ * belongs to the given section.
+ */
+StopReturnCode_t validateScomImageInputs( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint8_t i_chipletId,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pImage )
+ {
+ //Error Invalid image pointer
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ MY_ERR("invalid image location ");
+ break;
+ }
+
+ if( 0 == i_scomAddress )
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_ADDRESS;
+ MY_ERR("invalid SCOM address");
+ break;
+ }
+
+ if(( CACHE_CHIPLET_ID_MIN > i_chipletId ) ||
+ ( CORE_CHIPLET_ID_MAX < i_chipletId ))
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
+ MY_ERR("chiplet id not in range");
+ break;
+ }
+
+ if(( CORE_CHIPLET_ID_MIN > i_chipletId ) &&
+ ( CACHE_CHIPLET_ID_MAX < i_chipletId ))
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
+ MY_ERR("chiplet id not valid");
+ break;
+ }
+
+ if(( P9_STOP_SCOM_OP_MIN >= i_operation ) ||
+ ( P9_STOP_SCOM_OP_MAX <= i_operation ))
+ {
+ //invalid SCOM image operation requested
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ MY_ERR("invalid SCOM image operation");
+ break;
+ }
+
+ if(( P9_STOP_SECTION_MIN >= i_section ) ||
+ ( P9_STOP_SECTION_MAX <= i_section ))
+ {
+ // invalid cache sub section specified
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ MY_ERR("invalid section");
+ break;
+ }
+
+ if(( i_operation == P9_STOP_SCOM_RESET ) &&
+ ( i_chipletId < CORE_CHIPLET_ID_MIN ))
+ {
+ // replace requested with a cache chiplet Id
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ MY_ERR( "reset not supported for cache. chiplet Id 0x%08x",
+ i_chipletId );
+ break;
+ }
+
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR("image 0x%08x SCOMAddress 0x%08x chipletId 0x%08x operation"
+ "0x%08x section 0x%08x", i_pImage, i_scomAddress, i_chipletId,
+ i_operation, i_section );
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief edit SCOM entry associated with the given core.
+ * @param[in] i_scomAddr SCOM address of register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_pEntryLocation points to a SCOM entry in HOMER image.
+ * @param[in] i_operation operation to be performed on SCOM entry.
+ * @return STOP_SAVE_SUCCESS if existing entry is updated, STOP_SAVE_FAIL
+ * otherwise.
+ */
+StopReturnCode_t editScomEntry( uint32_t i_scomAddr, uint64_t i_scomData,
+ ScomEntry_t* i_pEntryLocation,
+ uint32_t i_operation )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pEntryLocation )
+ {
+ //Error: location of SCOM entry is not known
+ //therefore no point moving forward
+ MY_ERR("SCOM entry location not valid");
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ switch( i_operation )
+ {
+ case P9_STOP_SCOM_OR:
+ i_pEntryLocation->scomEntryData |= i_scomData;
+ break;
+
+ case P9_STOP_SCOM_AND:
+ i_pEntryLocation->scomEntryData &= i_scomData;
+ break;
+
+ case P9_STOP_SCOM_NOOP:
+ {
+ uint32_t nopInst = getOriInstruction( 0, 0, 0 );
+ i_pEntryLocation->scomEntryHeader = SCOM_ENTRY_START;
+ i_pEntryLocation->scomEntryData = nopInst;
+ i_pEntryLocation->scomEntryAddress = nopInst;
+ }
+ break;
+
+ case P9_STOP_SCOM_APPEND:
+ i_pEntryLocation->scomEntryHeader = SCOM_ENTRY_START;
+ i_pEntryLocation->scomEntryData = i_scomData;
+ i_pEntryLocation->scomEntryAddress = i_scomAddr;
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief update SCOM entry associated with the given core.
+ * @param[in] i_scomAddr SCOM address of register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_scomEntry points to a SCOM entry in cache section of HOMER image.
+ * @return STOP_SAVE_SUCCESS if new entry is added, STOP_SAVE_FAIL otherwise.
+ * @note adds an entry at a given location. It can be used to add entry in
+ * place of NOP, at the end of table or as first entry of the cache
+ * sub-section(L2, L3 or NC ).
+ */
+StopReturnCode_t updateScomEntry( uint32_t i_scomAddr, uint64_t i_scomData,
+ ScomEntry_t* i_scomEntry )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_scomEntry )
+ {
+ MY_ERR( "cache entry cannot be located");
+ l_rc = STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED;
+ break;
+ }
+
+ i_scomEntry->scomEntryHeader = SCOM_ENTRY_START; // done for now
+ i_scomEntry->scomEntryAddress = i_scomAddr;
+ i_scomEntry->scomEntryData = i_scomData;
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+StopReturnCode_t p9_stop_save_scom( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint64_t i_scomData,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ StopCacheSection_t* pStopCacheScomStart = NULL;
+ ScomEntry_t* pScomEntry = NULL;
+ uint32_t entryLimit = 0;
+ uint8_t chipletId = 0;
+
+ do
+ {
+ chipletId = i_scomAddress >> 24;
+ chipletId = chipletId & 0x3F;
+
+ l_rc = validateScomImageInputs( i_pImage,
+ i_scomAddress,
+ chipletId,
+ i_operation,
+ i_section );
+
+ if( l_rc )
+ {
+ MY_ERR( "invalid argument: aborting");
+ break;
+ }
+
+ if( chipletId >= CORE_CHIPLET_ID_MIN )
+ {
+ // chiplet is core. So, let us find the start address of SCOM area
+ // pertaining to a core in STOP image.
+ pScomEntry = CORE_ID_SCOM_START(i_pImage,
+ chipletId )
+ entryLimit = MAX_CORE_SCOM_ENTRIES;
+ }
+ else
+ {
+ // chiplet is a cache. let us find start address of cache section
+ // associated with given chiplet. A cache section associated with
+ // given chiplet is split in to L2, L3 and NC area.
+ pStopCacheScomStart = CACHE_SECTN_START(i_pImage,
+ chipletId);
+ }
+
+ if(( !pStopCacheScomStart ) && ( !pScomEntry) )
+ {
+ //Error invalid pointer to SCOM entry in cache or core section
+ //of STOP image.
+ MY_ERR("invalid start location for chiplet %d",
+ chipletId );
+ break;
+ }
+
+ switch( i_section )
+ {
+ case P9_STOP_SECTION_NC:
+ pScomEntry = pStopCacheScomStart->nonCacheArea;
+ entryLimit = MAX_NC_SCOM_ENTRIES;
+ break;
+
+ case P9_STOP_SECTION_L2:
+ pScomEntry = pStopCacheScomStart->l2CacheArea;
+ entryLimit = MAX_L2_SCOM_ENTRIES;
+ break;
+
+ case P9_STOP_SECTION_L3:
+ pScomEntry = pStopCacheScomStart->l3CacheArea;
+ entryLimit = MAX_L3_SCOM_ENTRIES;
+ break;
+
+ case P9_STOP_SECTION_CORE_SCOM:
+ //macro CORE_ID_SCOM_START already gives start of scom
+ //entry for given core. entry limit too is assigned thereafter.
+ //Handling for core and cache segment is different for scom
+ //entries. It is because scom entries are organized differently
+ //in core and cache segment.
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ break;
+ }
+
+ if(( !pScomEntry ) || ( l_rc ) )
+ {
+ // Error Invalid pointer to cache entry
+ MY_ERR("invalid subsection %d or internal firmware failure",
+ i_section );
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ uint32_t nopInst = getOriInstruction( 0, 0, 0 );
+
+ ScomEntry_t* pEntryLocation = NULL;
+ ScomEntry_t* pNopLocation = NULL;
+ ScomEntry_t* pTableEndLocationtable = NULL;
+ uint32_t swizzleAddr = SWIZZLE_4_BYTE(i_scomAddress);
+ uint64_t swizzleData = SWIZZLE_8_BYTE(i_scomData);
+ uint32_t swizzleAttn = SWIZZLE_4_BYTE(ATTN_OPCODE);
+ uint32_t index = 0;
+
+ for( index = 0; index < entryLimit; ++index )
+ {
+ if( ( swizzleAddr == pScomEntry[index].scomEntryAddress ) &&
+ ( !pEntryLocation ) )
+
+ {
+ pEntryLocation = &pScomEntry[index];
+ }
+
+ if( (( nopInst == pScomEntry[index].scomEntryAddress ) ||
+ ( swizzleAttn == pScomEntry[index].scomEntryAddress )) &&
+ ( !pNopLocation ) )
+ {
+ pNopLocation = &pScomEntry[index];
+ }
+
+ if( SCOM_ENTRY_START == pScomEntry[index].scomEntryHeader )
+ {
+ continue;
+ }
+
+ pTableEndLocationtable = &pScomEntry[index];
+ break;
+ }
+
+ if( ( !pEntryLocation ) && ( !pTableEndLocationtable ) )
+ {
+ MY_ERR(" exhausted all location available for section"
+ "0x%08x scom address 0x%08x",
+ i_section, i_scomAddress );
+ l_rc = STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED;
+ break;
+ }
+
+ switch( i_operation )
+ {
+ case P9_STOP_SCOM_APPEND:
+ {
+ ScomEntry_t* pScomAppend = NULL;
+
+ if( pNopLocation )
+ {
+ pScomAppend = pNopLocation;
+ }
+ else
+ {
+ pScomAppend = pTableEndLocationtable;
+ }
+
+ l_rc = updateScomEntry ( swizzleAddr,
+ swizzleData, pScomAppend );
+ }
+ break;
+
+ case P9_STOP_SCOM_REPLACE:
+ {
+ ScomEntry_t* scomReplace = NULL;
+
+ if( pEntryLocation )
+ {
+ scomReplace = pEntryLocation;
+ }
+ else
+ {
+ scomReplace = pTableEndLocationtable;
+ }
+
+ l_rc = updateScomEntry( swizzleAddr,
+ swizzleData, scomReplace );
+ }
+ break;
+
+ case P9_STOP_SCOM_OR:
+ case P9_STOP_SCOM_AND:
+ case P9_STOP_SCOM_NOOP:
+
+ if( pEntryLocation )
+ {
+ l_rc = editScomEntry( swizzleAddr,
+ swizzleData,
+ pEntryLocation,
+ i_operation );
+ }
+ else
+ {
+ //Invalid operation requested.
+ MY_ERR( "entry not found edit chiplet Id 0x%08x "
+ "swizzle addr 0x%08x ",
+ chipletId, swizzleAddr );
+
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ }
+
+ break;
+
+ case P9_STOP_SCOM_RESET:
+ memset( pScomEntry, nopInst, SCOM_SIZE_PER_CORE );
+ break;
+
+ case P9_STOP_SCOM_OR_APPEND:
+ case P9_STOP_SCOM_AND_APPEND:
+ {
+ uint32_t tempOperation = P9_STOP_SCOM_APPEND;
+ ScomEntry_t* editAppend = NULL;
+
+ if( NULL == pEntryLocation )
+ {
+ editAppend = pTableEndLocationtable;
+ }
+ else
+ {
+ editAppend = pEntryLocation;
+
+ if( P9_STOP_SCOM_OR_APPEND == i_operation )
+ {
+ tempOperation = P9_STOP_SCOM_OR;
+ }
+ else
+ {
+ tempOperation = P9_STOP_SCOM_AND;
+ }
+ }
+
+ l_rc = editScomEntry( swizzleAddr,
+ swizzleData,
+ editAppend,
+ tempOperation );
+ }
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ break;
+ }
+
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR("SCOM image operation 0x%08x failed for chiplet 0x%08x addr"
+ "0x%08x", i_operation, chipletId ,
+ i_scomAddress );
+ }
+
+ return l_rc;
+}
+
+
+} //namespace stopImageSection ends
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.H b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.H
new file mode 100755
index 000000000..b597e3ed7
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.H
@@ -0,0 +1,150 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_stop_api.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __P9_STOP_IMAGE_API_
+#define __P9_STOP_IMAGE_API_
+
+#include <stdint.h>
+
+///
+/// @file p9_stop_api.H
+/// @brief describes STOP API which create/manipulate STOP image.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+namespace stopImageSection
+{
+
+/**
+ * @brief all SPRs and MSR for which register restore is to be supported.
+ * @note STOP API design has built in support to accomodate 8 register of
+ * scope core and thread each.
+ */
+typedef enum
+{
+ P9_STOP_SPR_DAWR = 180, // thread register
+ P9_STOP_SPR_HSPRG0 = 304, // thread register
+ P9_STOP_SPR_HRMOR = 313, // core register
+ P9_STOP_SPR_LPCR = 318, // thread register
+ P9_STOP_SPR_HMEER = 337, // core register
+ P9_STOP_SPR_PSSCR = 855, // thread register
+ P9_STOP_SPR_PMCR = 884, // core register
+ P9_STOP_SPR_HID = 1008, // core register
+ P9_STOP_SPR_MSR = 2000, // thread register
+} CpuReg_t;
+
+/**
+ * @brief lists all the bad error codes.
+ */
+typedef enum
+{
+ STOP_SAVE_SUCCESS = 0,
+ STOP_SAVE_ARG_INVALID_IMG = 1,
+ STOP_SAVE_ARG_INVALID_REG = 2,
+ STOP_SAVE_ARG_INVALID_THREAD = 3,
+ STOP_SAVE_ARG_INVALID_MODE = 4,
+ STOP_SAVE_ARG_INVALID_CORE = 5,
+ STOP_SAVE_SPR_ENTRY_NOT_FOUND = 6,
+ STOP_SAVE_SPR_ENTRY_UPDATE_FAILED = 7,
+ STOP_SAVE_SCOM_INVALID_OPERATION = 8,
+ STOP_SAVE_SCOM_INVALID_SECTION = 9,
+ STOP_SAVE_SCOM_INVALID_ADDRESS = 10,
+ STOP_SAVE_SCOM_INVALID_CHIPLET = 11,
+ STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED = 12,
+ STOP_SAVE_FAIL = 13, // for internal failure within firmware.
+} StopReturnCode_t;
+
+/**
+ * @brief summarizes all operations supported on scom entries of STOP image.
+ */
+typedef enum
+{
+ P9_STOP_SCOM_OP_MIN = 0,
+ P9_STOP_SCOM_APPEND = 1,
+ P9_STOP_SCOM_REPLACE = 2,
+ P9_STOP_SCOM_OR = 3,
+ P9_STOP_SCOM_AND = 4,
+ P9_STOP_SCOM_NOOP = 5,
+ P9_STOP_SCOM_RESET = 6,
+ P9_STOP_SCOM_OR_APPEND = 7,
+ P9_STOP_SCOM_AND_APPEND = 8,
+ P9_STOP_SCOM_OP_MAX = 9
+} ScomOperation_t;
+
+/**
+ * @brief All subsections that contain scom entries in a STOP image.
+ */
+typedef enum
+{
+ P9_STOP_SECTION_MIN = 0,
+ P9_STOP_SECTION_CORE_SCOM = 1,
+ P9_STOP_SECTION_NC = 2,
+ P9_STOP_SECTION_L2 = 3,
+ P9_STOP_SECTION_L3 = 4,
+ P9_STOP_SECTION_MAX = 5
+} ScomSection_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief Updates STOP image entry associated with CPU register.
+ * @param[in] i_pImage start address of homer image associated with processor.
+ * @param[in] i_regId id of SPR for which STOP image needs to be updated.
+ * @param[in] i_regData data to be restored in SPR register.
+ * @param[in] i_pir value of processor identification register (PIR)
+ * @return STOP_SAVE_SUCCESS SUCCESS if image is updated successfully, error
+ * code otherwise.
+ */
+
+StopReturnCode_t p9_stop_save_cpureg( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const uint64_t i_pir );
+
+/**
+ * @brief Updates scom image entry associated with given core or cache in
+ * STOP section of homer image.
+ * @param[in] i_pImage start address of homer image of P9 chip.
+ * @param[in] i_scomAddress fully qualified address of SCOM register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_operation operation to be done on SCOM image entry.
+ * @param[in] i_section area to which given SCOM entry belongs.
+ * @return STOP_SAVE_SUCCESS if image is updated successfully, error code
+ * otherwise.
+ * @note API is intended to update SCOM image entry associated with given
+ * core or given part of a cache section. API doesn't validate if
+ * a given SCOM address really belongs to given section.
+ */
+StopReturnCode_t p9_stop_save_scom( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint64_t i_scomData,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section );
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+}; // namespace stopImageSection ends
+
+
+#endif //__P9_STOP_IMAGE_API_
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.mk b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.mk
new file mode 100644
index 000000000..a4a1a93f7
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.mk
@@ -0,0 +1,21 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: chips/p9/procedures/utils/stopreg/p9_stop_api.mk $
+#
+# IBM CONFIDENTIAL
+#
+# EKB Project
+#
+# COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# The source code for this program is not published or otherwise
+# divested of its trade secrets, irrespective of what has been
+# deposited with the U.S. Copyright Office.
+#
+# IBM_PROLOG_END_TAG
+PROCEDURE=p9_stop_api
+libp9_stop_util_DEPLIBS += p9_stop_util
+$(call BUILD_PROCEDURE)
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_data_struct.H b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_data_struct.H
new file mode 100755
index 000000000..63422850d
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_data_struct.H
@@ -0,0 +1,133 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_stop_data_struct.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_data_struct.H
+/// @brief describes data structures internal to STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifndef __STOP_DATA_STRUCT_
+#define __STOP_DATA_STRUCT_
+
+#ifndef __HOS_AIX__
+ #include <endian.h>
+#endif
+
+#include "p9_stop_section_defines.H"
+
+#ifdef __FAPI_2_
+ #include <fapi2.H>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+namespace stopImageSection
+{
+
+typedef struct
+{
+ uint32_t scomEntryHeader;
+ uint32_t scomEntryAddress;
+ uint64_t scomEntryData;
+} ScomEntry_t;
+
+/**
+ * @brief models a CPU register restoration area in STOP section of homer image.
+ */
+typedef struct
+{
+ uint8_t threadArea[THREAD_SECTN_SIZE];
+ uint8_t reserve[THREAD_AREA_SIZE - THREAD_SECTN_SIZE];
+ uint8_t coreArea[CORE_SPR_SECTN_SIZE];
+} SprRestoreArea_t;
+
+/**
+ * @brief models homer image of a chip.
+ * @note sections not relevant for CPU register restoration have been
+ * abstracted using field 'reserve'.
+ */
+typedef struct
+{
+ uint8_t occ_host_sgpe_area[ TWO_MB ]; // CPU restore area starts at an offset of 2MB from chip HOMER
+ uint8_t interrruptHandler[INTERRUPT_HANDLER_SIZE];
+ uint8_t threadLauncher[THREAD_LAUNCHER_SIZE];
+ SprRestoreArea_t coreThreadRestore[MAX_CORE_ID_SUPPORTED + 1][MAX_THREAD_ID_SUPPORTED + 1];
+ uint8_t reserve[(ONE_KB * ONE_KB) - SPR_RESTORE_PER_CHIP];
+} HomerSection_t;
+
+/**
+ * @brief models cache subsection in STOP section of a given homer image.
+ * @note given the start of cache subsection associated with a given core,
+ * the structure below represents what a cache subsection would look
+ * like. Based on known start address, quick traversing can be done
+ * within the cache subsection.
+ */
+typedef struct
+{
+ ScomEntry_t nonCacheArea[MAX_NC_SCOM_ENTRIES];
+ ScomEntry_t l2CacheArea[MAX_L2_SCOM_ENTRIES];
+ ScomEntry_t l3CacheArea[MAX_L3_SCOM_ENTRIES];
+} StopCacheSection_t;
+
+/**
+ * @brief summarizes attributes associated with a SPR register.
+ */
+typedef struct
+{
+ uint32_t sprId;
+ bool isThreadScope;
+} StopSprReg_t;
+
+enum
+{
+ SIZE_SCOM_ENTRY = sizeof( ScomEntry_t ),
+ SCOM_ENTRY_START = 0xDEADDEAD,
+};
+
+#ifdef __FAPI_2_
+ #define MY_ERR( _fmt_, _args_...) FAPI_ERR(_fmt_, ##_args_)
+ #define MY_INF(_fmt_, _args_...) FAPI_INF(_fmt_, ##_args_)
+#else
+ #define MY_ERR( _fmt_, _args_...)
+ #define MY_INF(_fmt_, _args_...)
+#endif
+
+#define CORE_ID_SCOM_START(io_image,\
+ i_chipletId) \
+((ScomEntry_t*)(((uint8_t*)(io_image))+ CORE_SCOM_SECTN_START +\
+ ((i_chipletId - CORE_CHIPLET_ID_MIN) * \
+ SCOM_SIZE_PER_CORE)));
+
+#define CACHE_SECTN_START(io_image,\
+ i_chipletId) \
+((StopCacheSection_t *)(((uint8_t *)(io_image))+CACHE_SCOM_SECTN_START \
+ + ( i_chipletId - CACHE_CHIPLET_ID_MIN ) * \
+ SCOM_SIZE_PER_CACHE_CHIPLET ));
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+} //namespace stopImageSection ends
+#endif
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_section_defines.H b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_section_defines.H
new file mode 100755
index 000000000..435931983
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_section_defines.H
@@ -0,0 +1,96 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_stop_section_defines.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_section_defines.H
+/// @brief defines all constants associated with STOP image layout.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#ifndef _STOP_SECTION_DEFINES_H
+#define _STOP_SECTION_DEFINES_H
+
+namespace stopImageSection
+{
+
+//basic constants
+enum
+{
+ ONE_KB = 1024,
+ ONE_MB = ONE_KB * ONE_KB,
+ TWO_MB = 2 * ONE_MB,
+ MAX_CORE_SCOM_ENTRIES = 15,
+ MAX_NC_SCOM_ENTRIES = 15,
+ MAX_L2_SCOM_ENTRIES = 16,
+ MAX_L3_SCOM_ENTRIES = 16,
+ MAX_CORE_ID_SUPPORTED = 23,
+ MAX_THREAD_ID_SUPPORTED = 3,
+ MAX_CACHE_SECTN_SIZE_PER_CHIPLET =
+ MAX_NC_SCOM_ENTRIES + MAX_L2_SCOM_ENTRIES + MAX_L3_SCOM_ENTRIES,
+
+ // start offset for SPR register restore, core scom or cache scom register
+ // restore regions in homer image.
+ CORE_SCOM_SECTN_START = ( TWO_MB + ( 256 * ONE_KB )), //offset from start of chip HOMER
+ CACHE_SCOM_SECTN_START = ( ONE_MB + ( 32 * ONE_KB )), // start of cache section
+
+ //constants in HOMER's header area.
+ REGULAR_MODE = 0xAA,
+ FUSE_MODE = 0xBB,
+ HOMER_MAGIC_WORD = 0x484F4D4552312E30ll,
+ CACHE_CHIPLET_ID_MIN = 0x10,
+ CACHE_CHIPLET_ID_MAX = 0x15,
+ CORE_CHIPLET_ID_MIN = 0x20,
+ CORE_CHIPLET_ID_MAX = 0x37,
+ MAX_SPR_RESTORE_INST = 0x08,
+ SIZE_PER_SPR_RESTORE_INST = ((4 * sizeof(uint8_t)) / sizeof(uint32_t)),
+};
+
+// all section sizes below are in bytes
+enum
+{
+ SCOM_ENTRY_SIZE = 16,
+ INTERRUPT_HANDLER_SIZE = 8 * ONE_KB,
+ THREAD_LAUNCHER_SIZE = 256,
+ THREAD_RESTORE_SECTN = 192,
+ THREAD_COMPLETION = 64,
+ THREAD_AREA_SIZE = ONE_KB,
+ THREAD_SECTN_SIZE = THREAD_RESTORE_SECTN + THREAD_COMPLETION,
+ CORE_SPR_SECTN_SIZE = ONE_KB,
+ L2_AREA = (SCOM_ENTRY_SIZE * MAX_L2_SCOM_ENTRIES),
+ L3_AREA = (SCOM_ENTRY_SIZE * MAX_L2_SCOM_ENTRIES ),
+ NON_CACHE_AREA = SCOM_ENTRY_SIZE * MAX_NC_SCOM_ENTRIES,
+ MAX_SIZE_PER_CORE = 8 * ONE_KB,
+ SPR_RESTORE_PER_CHIP = ( MAX_SIZE_PER_CORE *
+ ( MAX_CORE_ID_SUPPORTED + 1)) +
+ ( INTERRUPT_HANDLER_SIZE + THREAD_LAUNCHER_SIZE),
+ SCOM_SIZE_PER_CORE = ( MAX_CORE_SCOM_ENTRIES + 1 ) * SCOM_ENTRY_SIZE,
+ SCOM_SIZE_PER_CHIP = SCOM_SIZE_PER_CORE * ( MAX_CORE_ID_SUPPORTED + 1),
+ SCOM_SIZE_PER_CACHE_CHIPLET = L2_AREA + L3_AREA + NON_CACHE_AREA
+ + SCOM_ENTRY_SIZE,
+//size in byte ends
+};
+
+}//stopImageSection ends
+
+#endif
+
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.C b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.C
new file mode 100755
index 000000000..28dffb71d
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.C
@@ -0,0 +1,169 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_stop_util.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_util.C
+/// @brief implements some utilty functions for STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#include "p9_stop_api.H"
+#include "p9_stop_util.H"
+#include "p9_stop_data_struct.H"
+namespace stopImageSection
+{
+
+/**
+ * @brief Returns proc chip's fuse mode status.
+ * @param i_pImage points to start of chip's HOMER image.
+ * @param o_fuseMode true if system is in fuse mode, false otherwise.
+ * @return STOP_SAVE_SUCCESS if functions succeeds, error code otherwise.
+ */
+StopReturnCode_t isFusedMode( void* const i_pImage, bool& o_fuseMode )
+{
+ o_fuseMode = false;
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pImage )
+ {
+ MY_ERR( "invalid pointer to HOMER image");
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ HomerImgDesc_t* pHomer = (HomerImgDesc_t*)i_pImage;
+
+ if( HOMER_MAGIC_WORD != pHomer->homerMagicNumber )
+ {
+ MY_ERR("corrupt or invalid HOMER image location");
+ break;
+ }
+
+ if( (uint8_t) FUSE_MODE == pHomer->fuseModeStatus )
+ {
+ o_fuseMode = true;
+ break;
+ }
+
+ if( (uint8_t) REGULAR_MODE == pHomer->fuseModeStatus )
+ {
+ break;
+ }
+
+ MY_ERR("Unexpected value 0x%08x for fuse mode. Bad or corrupt "
+ "HOMER location", pHomer->fuseModeStatus );
+ l_rc = STOP_SAVE_FAIL;
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//----------------------------------------------------------------------
+
+StopReturnCode_t getCoreAndThread( void* const i_pImage, const uint64_t i_pir,
+ uint32_t& o_coreId, uint32_t& o_threadId )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ // for SPR restore using 'Virtual Thread' and 'Physical Core' number
+ // In Fuse Mode:
+ // bit b28 and b31 of PIR give physical core and b29 and b30 gives
+ // virtual thread id.
+ // In Non Fuse Mode
+ // bit 28 and b29 of PIR give both logical and physical core number
+ // whereas b30 and b31 gives logical and virtual thread id.
+ bool fuseMode = false;
+ uint8_t coreThreadInfo = (uint8_t)i_pir;
+ o_coreId = 0;
+ o_threadId = 0;
+ l_rc = isFusedMode( i_pImage, fuseMode );
+
+ if( l_rc )
+ {
+ MY_ERR(" Checking Fuse mode. Read failed 0x%08x", l_rc );
+ break;
+ }
+
+ if( fuseMode )
+ {
+ if( coreThreadInfo & FUSE_BIT1 )
+ {
+ o_threadId = 2;
+ }
+
+ if( coreThreadInfo & FUSE_BIT2 )
+ {
+ o_threadId += 1;
+ }
+
+ if( coreThreadInfo & FUSE_BIT0 )
+ {
+ o_coreId = 2;
+ }
+
+ if( coreThreadInfo & FUSE_BIT3 )
+ {
+ o_coreId += 1;
+ }
+ }
+ else
+ {
+ if( coreThreadInfo & FUSE_BIT0 )
+ {
+ o_coreId = 2;
+ }
+
+ if ( coreThreadInfo & FUSE_BIT1 )
+ {
+ o_coreId += 1;
+ }
+
+ if( coreThreadInfo & FUSE_BIT2 )
+ {
+ o_threadId = 2;
+ }
+
+ if( coreThreadInfo & FUSE_BIT3 )
+ {
+ o_threadId += 1;
+ }
+
+
+ }
+
+ //quad field is not affected by fuse mode
+ o_coreId += 4 * (( coreThreadInfo & 0x70 ) >> 4 );
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+}//namespace stopImageSection ends
diff --git a/src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.H b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.H
new file mode 100755
index 000000000..5d276f870
--- /dev/null
+++ b/src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.H
@@ -0,0 +1,122 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/procedures/utils/stopreg/p9_stop_util.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __P9_STOP_UTIL_
+#define __P9_STOP_UTIL_
+
+#ifdef __HOS_AIX__
+ #define __BYTE_ORDER __BIG_ENDIAN
+#else
+ #include <endian.h>
+#endif
+
+#include "p9_stop_api.H"
+
+#ifdef FAPI_2
+ #include <fapi2.H>
+#endif
+
+///
+/// @file p9_stop_util.H
+/// @brief describes some utilty functions for STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+namespace stopImageSection
+{
+/**
+ * @brief helper function to swizzle given input data
+ * @note swizles bytes to handle endianess issue.
+ */
+#if( __BYTE_ORDER == __BIG_ENDIAN )
+
+// NOP if it is a big endian system
+#define SWIZZLE_2_BYTE(WORD) WORD
+#define SWIZZLE_4_BYTE(WORD) WORD
+#define SWIZZLE_8_BYTE(WORD) WORD
+
+#else
+#define SWIZZLE_2_BYTE(WORD) \
+ ( (((WORD) >> 8) & 0x00FF) | (((WORD) << 8) & 0xFF00) )
+
+#define SWIZZLE_4_BYTE(WORD) \
+ ( (((WORD) >> 24) & 0x000000FF) | (((WORD) >> 8) & 0x0000FF00) | \
+ (((WORD) << 8) & 0x00FF0000) | (((WORD) << 24) & 0xFF000000) )
+
+#define SWIZZLE_8_BYTE(WORD) \
+ ( (((WORD) >> 56) & 0x00000000000000FF) | \
+ (((WORD) >> 40) & 0x000000000000FF00)| \
+ (((WORD) >> 24) & 0x0000000000FF0000) | \
+ (((WORD) >> 8) & 0x00000000FF000000) | \
+ (((WORD) << 8) & 0x000000FF00000000) | \
+ (((WORD) << 24) & 0x0000FF0000000000) | \
+ (((WORD) << 40) & 0x00FF000000000000) | \
+ (((WORD) << 56) & 0xFF00000000000000) )
+#endif
+
+/**
+ * @brief describes details of start section of chip's HOMER image.
+ */
+typedef struct
+{
+ uint64_t attnOpcodes;
+ uint64_t homerMagicNumber;
+ uint32_t buildDate;
+ uint32_t version;
+ uint8_t reserve[7];
+ uint8_t fuseModeStatus;
+ uint32_t cmeHcodeOffset;
+ uint32_t cmeHcodeLength;
+ uint32_t cmeCommonRingOffset;
+ uint32_t cmeCommonRingLength;
+ uint32_t cmePstateOffset;
+ uint32_t cmePstateLength;
+} HomerImgDesc_t;
+
+/**
+ * @brief enumerates bit(s) positions of interest for PIR.
+ */
+enum
+{
+ FUSE_BIT0 = 0x08,
+ FUSE_BIT1 = 0x04,
+ FUSE_BIT2 = 0x02,
+ FUSE_BIT3 = 0x01,
+ QUAD_BITS = 0x70
+};
+
+/**
+ * @brief returns core id and thread id by parsing a given PIR.
+ * @param i_pStopImage points to STOP image associated with a proc chip.
+ * @param i_pir PIR associated with a core's thread.
+ * @param o_coreId core id obtained from PIR.
+ * @param o_threadId thread id obtained from PIR.
+ * @return SUCCESS if function suceeds, error code otherwise.
+ */
+StopReturnCode_t getCoreAndThread( void* const i_pStopImage,
+ const uint64_t i_pir,
+ uint32_t& o_coreId, uint32_t& o_threadId );
+
+} // namespace stopImageSection ends
+
+#endif
+
+
OpenPOWER on IntegriCloud