summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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