summaryrefslogtreecommitdiffstats
path: root/src/occ
diff options
context:
space:
mode:
Diffstat (limited to 'src/occ')
-rwxr-xr-xsrc/occ/Makefile7
-rwxr-xr-xsrc/occ/app.mk7
-rwxr-xr-xsrc/occ/cfiles.mk13
-rwxr-xr-xsrc/occ/cmdh/cmdh_fsp_cmds.c5
-rwxr-xr-xsrc/occ/cmdh/cmdh_fsp_cmds_datacnfg.c13
-rwxr-xr-xsrc/occ/cmdh/cmdh_fsp_cmds_datacnfg.h4
-rwxr-xr-xsrc/occ/errl/errl.c68
-rw-r--r--src/occ/firdata/ecc.c272
-rw-r--r--src/occ/firdata/ecc.h76
-rw-r--r--src/occ/firdata/firData.c754
-rw-r--r--src/occ/firdata/firData.h48
-rw-r--r--src/occ/firdata/firDataConst_common.h75
-rw-r--r--src/occ/firdata/fir_data_collect.c163
-rw-r--r--src/occ/firdata/fir_data_collect.h56
-rw-r--r--src/occ/firdata/fsi.c115
-rw-r--r--src/occ/firdata/fsi.h47
-rw-r--r--src/occ/firdata/homerData_common.h170
-rw-r--r--src/occ/firdata/lpc.c302
-rw-r--r--src/occ/firdata/lpc.h51
-rw-r--r--src/occ/firdata/native.c68
-rw-r--r--src/occ/firdata/native.h99
-rw-r--r--src/occ/firdata/nor_micron.c73
-rw-r--r--src/occ/firdata/norflash.h154
-rw-r--r--src/occ/firdata/pnorData_common.h164
-rw-r--r--src/occ/firdata/pnor_util.c236
-rw-r--r--src/occ/firdata/pnor_util.h41
-rw-r--r--src/occ/firdata/scom_trgt.c135
-rw-r--r--src/occ/firdata/scom_trgt.h89
-rw-r--r--src/occ/firdata/scom_util.c386
-rw-r--r--src/occ/firdata/scom_util.h49
-rw-r--r--src/occ/firdata/sfc_ast2400.c728
-rw-r--r--src/occ/firdata/sfc_ast2400.h298
-rwxr-xr-xsrc/occ/homer.c172
-rwxr-xr-xsrc/occ/homer.h25
-rwxr-xr-xsrc/occ/incl/common_types.h7
-rwxr-xr-xsrc/occ/incl/occ_common.h19
-rwxr-xr-xsrc/occ/linkocc.cmd74
-rwxr-xr-xsrc/occ/main.c307
-rw-r--r--src/occ/occLinkInputFile110
-rw-r--r--src/occ/occ_service_codes.h16
-rwxr-xr-xsrc/occ/reset.c74
-rwxr-xr-xsrc/occ/state.c83
-rwxr-xr-xsrc/occ/trac/trac.h5
-rwxr-xr-xsrc/occ/trac/trac_interface.h4
44 files changed, 5378 insertions, 284 deletions
diff --git a/src/occ/Makefile b/src/occ/Makefile
index ad2bacd..bba6075 100755
--- a/src/occ/Makefile
+++ b/src/occ/Makefile
@@ -5,15 +5,15 @@
#
# OpenPOWER OnChipController Project
#
-# Contributors Listed Below - COPYRIGHT 2011,2014
-# [+] Google Inc.
+# Contributors Listed Below - COPYRIGHT 2011,2015
# [+] International Business Machines Corp.
#
+#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -49,6 +49,7 @@ APP_INCLUDES += -I.
APP_INCLUDES += -I../occ
APP_INCLUDES += -I../../occ
APP_INCLUDES += -I./timer
+APP_INCLUDES += -I./firdata
export APP_INCLUDES
diff --git a/src/occ/app.mk b/src/occ/app.mk
index 2ce5e81..025b100 100755
--- a/src/occ/app.mk
+++ b/src/occ/app.mk
@@ -5,15 +5,15 @@
#
# OpenPOWER OnChipController Project
#
-# Contributors Listed Below - COPYRIGHT 2011,2014
-# [+] Google Inc.
+# Contributors Listed Below - COPYRIGHT 2011,2015
# [+] International Business Machines Corp.
#
+#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -107,6 +107,7 @@ LDFLAGS = \
-L $(OCC)/thread \
-L $(OCC)/timer \
-L $(OCC)/trac \
+ -L $(OCC)/firdata \
-lssx -lppc32 --oformat=elf32-powerpc -melf32ppc
# Added for linking files compiled using gnu assembler
diff --git a/src/occ/cfiles.mk b/src/occ/cfiles.mk
index f8173a0..8fc299d 100755
--- a/src/occ/cfiles.mk
+++ b/src/occ/cfiles.mk
@@ -91,8 +91,21 @@ occ_CFILES = \
occbuildname.c \
common.c \
+occ_CFILES += firdata/ecc.c
+occ_CFILES += firdata/fir_data_collect.c
+occ_CFILES += firdata/firData.c
+occ_CFILES += firdata/fsi.c
+occ_CFILES += firdata/lpc.c
+occ_CFILES += firdata/native.c
+occ_CFILES += firdata/nor_micron.c
+occ_CFILES += firdata/pnor_util.c
+occ_CFILES += firdata/scom_trgt.c
+occ_CFILES += firdata/scom_util.c
+occ_CFILES += firdata/sfc_ast2400.c
+
occ_SFILES = cmdh/ll_ffdc.S
+
occ_cfiles = ${occ_CFILES:.c=.o}
occ_Sfiles = ${occ_SFILES:.S=.o}
diff --git a/src/occ/cmdh/cmdh_fsp_cmds.c b/src/occ/cmdh/cmdh_fsp_cmds.c
index d0f268c..d15decb 100755
--- a/src/occ/cmdh/cmdh_fsp_cmds.c
+++ b/src/occ/cmdh/cmdh_fsp_cmds.c
@@ -216,9 +216,10 @@ ERRL_RC cmdh_poll_v10(cmdh_fsp_rsp_t * o_rsp_ptr)
cmdh_poll_resp_v10_fixed_t * l_poll_rsp = (cmdh_poll_resp_v10_fixed_t *) o_rsp_ptr;
// Byte 1
- l_poll_rsp->status.word = SMGR_validate_get_valid_states(); //TODO: Do we need to set FIR master?
+ l_poll_rsp->status.word = SMGR_validate_get_valid_states();
// Byte 2
- l_poll_rsp->ext_status.word = 0; //TODO: What values should we set for memthrotOT and n power?
+ //TODO: What values should we set for memthrotOT and n power?
+ l_poll_rsp->ext_status.word = 0;
for ( k = 0; k < MAX_NUM_CORES; k++ )
{
diff --git a/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.c b/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.c
index 730b98b..09bc805 100755
--- a/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.c
+++ b/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.c
@@ -1073,7 +1073,10 @@ errlHndl_t data_store_pstate_super(const cmdh_fsp_cmd_t * i_cmd_ptr,
//
// Name: data_store_role
//
-// Description: TODO Add description
+// Description: Tell the OCC if it should run as a master or slave. HTMGT knows
+// which OCC is the master from the MRW. To be the master OCC
+// requires a connection to the APSS. Until an OCC is told a role
+// it should default to running as a slave
//
// End Function Specification
errlHndl_t data_store_role(const cmdh_fsp_cmd_t * i_cmd_ptr,
@@ -1082,17 +1085,13 @@ errlHndl_t data_store_role(const cmdh_fsp_cmd_t * i_cmd_ptr,
errlHndl_t l_errlHndl = NULL;
uint8_t l_old_role = G_occ_role;
uint8_t l_new_role = OCC_SLAVE;
- uint8_t l_fir_master = 0x00;
ERRL_RC l_rc = ERRL_RC_SUCCESS;
// Cast the command to the struct for this format
cmdh_set_role_t * l_cmd_ptr = (cmdh_set_role_t *)i_cmd_ptr;
- // With BMC-based systems, there is a FIR Master bit
- l_fir_master = l_cmd_ptr->role >> 7;
-
- // Mask off the FIR Master bit
- l_new_role = l_cmd_ptr->role & 0x7F;
+ // Mask off the OCC role
+ l_new_role = l_cmd_ptr->role & OCC_ROLE_MASTER_MASK;
// Must be in standby state before we can change roles
diff --git a/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.h b/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.h
index 4f20f0d..a17b982 100755
--- a/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.h
+++ b/src/occ/cmdh/cmdh_fsp_cmds_datacnfg.h
@@ -84,6 +84,10 @@ typedef enum
DATA_FRU_MAX,
} eConfigDataFruType;
+// Set OCC Role Masks
+#define OCC_ROLE_MASTER_MASK 0x01
+#define OCC_ROLE_FIR_MASTER_MASK 0x40
+
// Used by TMGT to send OCC the PstateSuperStruct
typedef struct __attribute__ ((packed))
{
diff --git a/src/occ/errl/errl.c b/src/occ/errl/errl.c
index 646be8f..ca0a279 100755
--- a/src/occ/errl/errl.c
+++ b/src/occ/errl/errl.c
@@ -59,6 +59,7 @@ errlHndl_t G_occErrSlots[ERRL_MAX_SLOTS] = {
};
extern uint8_t G_occ_interrupt_type;
+extern bool G_fir_collection_required;
void hexDumpLog( errlHndl_t i_log );
@@ -354,7 +355,9 @@ void addTraceToErrl(
void * l_traceAddr = io_err;
uint16_t l_actualSizeOfUsrDtls = 0;
pore_status_t l_gpe0_status;
+ ocb_oisr0_t l_oisr0_status;
static bool L_gpe_halt_traced = FALSE;
+ static bool L_sys_checkstop_traced = FALSE;
// check if GPE was frozen due to a checkstop
@@ -362,10 +365,20 @@ void addTraceToErrl(
if(l_gpe0_status.fields.freeze_action && !L_gpe_halt_traced)
{
L_gpe_halt_traced = TRUE;
- TRAC_ERR("addTraceToErrl: OCC GPE halted due to checkstop. GPE0 status[0x%08x%08x]",
- l_gpe0_status.words.high_order, l_gpe0_status.words.low_order);
+ TRAC_IMP("addTraceToErrl: Frozen GPE0 detected. GPE0 status[0x%08x%08x]",
+ l_gpe0_status.words.high_order,
+ l_gpe0_status.words.low_order);
}
+ // Check if there is a system checkstop
+ l_oisr0_status.value = in32(OCB_OISR0);
+ if (l_oisr0_status.fields.check_stop && !L_sys_checkstop_traced)
+ {
+ L_sys_checkstop_traced = TRUE;
+ TRAC_IMP("addTraceToErrl: System checkstop detected");
+ }
+
+
// 1. Check if error log is not null
// 2. error log is not invalid
// 3. error log has not been commited
@@ -520,16 +533,20 @@ void reportErrorLog( errlHndl_t i_err, uint16_t i_entrySize )
i_err->iv_userDetails.iv_modId, i_err->iv_reasonCode,
i_err->iv_userDetails.iv_userData1, i_err->iv_userDetails.iv_userData2);
- // If this system is using PSIHB complex, send an interrupt to Host so that
- // Host can inform HTMGT to collect the error log
- if (G_occ_interrupt_type == PSIHB_INTERRUPT)
+ // Defer the interrupt if FIR collection is required
+ if (!G_fir_collection_required)
{
- // From OCC OpenPower Interface v1.1, OCC needs to set bits 0 and 1 of
- // the OCB_OCCMISC register
- l_reg.fields.core_ext_intr = 1;
- l_reg.fields.reason_intr = 1;
+ // If this system is using PSIHB complex, send an interrupt to Host so that
+ // Host can inform HTMGT to collect the error log
+ if (G_occ_interrupt_type == PSIHB_INTERRUPT)
+ {
+ // From OCC OpenPower Interface v1.1, OCC needs to set bits 0 and 1 of
+ // the OCB_OCCMISC register
+ l_reg.fields.core_ext_intr = 1;
+ l_reg.fields.reason_intr = 1;
- out32(OCB_OCCMISC_OR, l_reg.value);
+ out32(OCB_OCCMISC_OR, l_reg.value);
+ }
}
}
@@ -544,16 +561,33 @@ void reportErrorLog( errlHndl_t i_err, uint16_t i_entrySize )
void commitErrl( errlHndl_t *io_err )
{
pore_status_t l_gpe0_status;
+ ocb_oisr0_t l_oisr0_status;
+ static bool L_log_commits_suspended_by_safe_mode = FALSE;
- if ( io_err != NULL )
+ if (!L_log_commits_suspended_by_safe_mode && io_err != NULL)
{
// check if handle is valid and is NOT empty
if ((*io_err != NULL ) && ( *io_err != INVALID_ERR_HNDL ))
{
- // check if GPE was frozen due to a checkstop
+ // Check if the GPE is frozen or if a system
+ // checkstop has occurred
l_gpe0_status.value = in64(PORE_GPE0_STATUS);
- if(l_gpe0_status.fields.freeze_action)
+ l_oisr0_status.value = in32(OCB_OISR0);
+
+ if (l_gpe0_status.fields.freeze_action
+ ||
+ l_oisr0_status.fields.check_stop)
{
+ if (l_gpe0_status.fields.freeze_action)
+ {
+ TRAC_IMP("Frozen GPE0 detected by commitErrl");
+ }
+
+ if (l_oisr0_status.fields.check_stop)
+ {
+ TRAC_IMP("System checkstop detected by commitErrl");
+ }
+
//Go to the reset state to minimize errors
reset_state_request(RESET_REQUESTED_DUE_TO_ERROR);
@@ -565,6 +599,14 @@ void commitErrl( errlHndl_t *io_err )
//set callouts to 0
(*io_err)->iv_numCallouts = 0;
+
+ TRAC_IMP("SAFE mode required, suspending error log commits. FIR capture required.");
+
+ // Suspend all error log commits
+ L_log_commits_suspended_by_safe_mode = TRUE;
+
+ // Motivate FIR data collection
+ G_fir_collection_required = TRUE;
}
// if reset action bit is set force severity to unrecoverable and
diff --git a/src/occ/firdata/ecc.c b/src/occ/firdata/ecc.c
new file mode 100644
index 0000000..6696678
--- /dev/null
+++ b/src/occ/firdata/ecc.c
@@ -0,0 +1,272 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/ecc.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/*#include <stdio.h> */
+#include <endian.h>
+#include <assert.h>
+
+#include <native.h>
+#include <ecc.h>
+
+/** Matrix used for ECC calculation.
+ *
+ * Each row of this is the set of data word bits that are used for
+ * the calculation of the corresponding ECC bit. The parity of the
+ * bitset is the value of the ECC bit.
+ *
+ * ie. ECC[n] = eccMatrix[n] & data
+ *
+ * Note: To make the math easier (and less shifts in resulting code),
+ * row0 = ECC7. HW numbering is MSB, order here is LSB.
+ *
+ * These values come from the HW design of the ECC algorithm.
+ */
+static uint64_t eccMatrix[] = {
+ /*0000000000000000111010000100001000111100000011111001100111111111 */
+ 0x0000e8423c0f99ff,
+ /*0000000011101000010000100011110000001111100110011111111100000000 */
+ 0x00e8423c0f99ff00,
+ /*1110100001000010001111000000111110011001111111110000000000000000 */
+ 0xe8423c0f99ff0000,
+ /*0100001000111100000011111001100111111111000000000000000011101000 */
+ 0x423c0f99ff0000e8,
+ /*0011110000001111100110011111111100000000000000001110100001000010 */
+ 0x3c0f99ff0000e842,
+ /*0000111110011001111111110000000000000000111010000100001000111100 */
+ 0x0f99ff0000e8423c,
+ /*1001100111111111000000000000000011101000010000100011110000001111 */
+ 0x99ff0000e8423c0f,
+ /*1111111100000000000000001110100001000010001111000000111110011001 */
+ 0xff0000e8423c0f99
+};
+
+/** Syndrome calculation matrix.
+ *
+ * Maps syndrome to flipped bit.
+ *
+ * To perform ECC correction, this matrix is a look-up of the bit
+ * that is bad based on the binary difference of the good and bad
+ * ECC. This difference is called the "syndrome".
+ *
+ * When a particular bit is on in the data, it cause a column from
+ * eccMatrix being XOR'd into the ECC field. This column is the
+ * "effect" of each bit. If a bit is flipped in the data then its
+ * "effect" is missing from the ECC. You can calculate ECC on unknown
+ * quality data and compare the ECC field between the calculated
+ * value and the stored value. If the difference is zero, then the
+ * data is clean. If the difference is non-zero, you look up the
+ * difference in the syndrome table to identify the "effect" that
+ * is missing, which is the bit that is flipped.
+ *
+ * Notice that ECC bit flips are recorded by a single "effect"
+ * bit (ie. 0x1, 0x2, 0x4, 0x8 ...) and double bit flips are identified
+ * by the UE status in the table.
+ *
+ * Bits are in MSB order.
+ */
+static uint8_t syndromeMatrix[] = {
+ ECC_GD, ECC_E7, ECC_E6, ECC_UE, ECC_E5, ECC_UE, ECC_UE, 47,
+ ECC_E4, ECC_UE, ECC_UE, 37, ECC_UE, 35, 39, ECC_UE,
+ ECC_E3, ECC_UE, ECC_UE, 48, ECC_UE, 30, 29, ECC_UE,
+ ECC_UE, 57, 27, ECC_UE, 31, ECC_UE, ECC_UE, ECC_UE,
+ ECC_E2, ECC_UE, ECC_UE, 17, ECC_UE, 18, 40, ECC_UE,
+ ECC_UE, 58, 22, ECC_UE, 21, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 16, 49, ECC_UE, 19, ECC_UE, ECC_UE, ECC_UE,
+ 23, ECC_UE, ECC_UE, ECC_UE, ECC_UE, 20, ECC_UE, ECC_UE,
+ ECC_E1, ECC_UE, ECC_UE, 51, ECC_UE, 46, 9, ECC_UE,
+ ECC_UE, 34, 10, ECC_UE, 32, ECC_UE, ECC_UE, 36,
+ ECC_UE, 62, 50, ECC_UE, 14, ECC_UE, ECC_UE, ECC_UE,
+ 13, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 61, 8, ECC_UE, 41, ECC_UE, ECC_UE, ECC_UE,
+ 11, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 15, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, 12, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_E0, ECC_UE, ECC_UE, 55, ECC_UE, 45, 43, ECC_UE,
+ ECC_UE, 56, 38, ECC_UE, 1, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 25, 26, ECC_UE, 2, ECC_UE, ECC_UE, ECC_UE,
+ 24, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, 28, ECC_UE,
+ ECC_UE, 59, 54, ECC_UE, 42, ECC_UE, ECC_UE, 44,
+ 6, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 5, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 63, 53, ECC_UE, 0, ECC_UE, ECC_UE, ECC_UE,
+ 33, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 3, ECC_UE, ECC_UE, 52, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ 7, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, 60, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, 4, ECC_UE, ECC_UE, ECC_UE,
+ ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE, ECC_UE,
+};
+
+/** Returns the parity of x, i.e. the number of 1-bits in x modulo 2.
+ * Replacement for __builtin_parityl
+ */
+uint8_t parity_check( uint64_t i_data )
+{
+ int ones = 0;
+ size_t x;
+ for( x=0; x<(sizeof(i_data)*8); x++ )
+ {
+ if( i_data & (0x8000000000000000ull >> x) )
+ {
+ ones++;
+ }
+ }
+ return ones%2;
+}
+
+/** Create the ECC field corresponding to a 8-byte data field
+ *
+ * @param[in] i_data - The 8 byte data to generate ECC for.
+ * @return The 1 byte ECC corresponding to the data.
+ */
+uint8_t generateECC(uint64_t i_data)
+{
+ uint8_t result = 0;
+
+ int i = 0;
+ for (i = 0; i < 8; i++)
+ {
+ result |= (parity_check(eccMatrix[i] & i_data) << i);
+ }
+
+ return result;
+}
+
+/** Verify the data and ECC match or indicate how they are wrong.
+ *
+ * @param[in] i_data - The data to check ECC on.
+ * @param[in] i_ecc - The [supposed] ECC for the data.
+ *
+ * @return eccBitfield or 0-64.
+ *
+ * @retval GD - Indicates the data is good (matches ECC).
+ * @retval UE - Indicates the data is uncorrectable.
+ * @retval all others - Indication of which bit is incorrect.
+ */
+uint8_t verifyECC(uint64_t i_data, uint8_t i_ecc)
+{
+ return syndromeMatrix[generateECC(i_data) ^ i_ecc];
+}
+
+/** Correct the data and/or ECC.
+ *
+ * @param[in,out] io_data - Data to check / correct.
+ * @param[in,out] io_ecc - ECC to check / correct.
+ *
+ * @return eccBitfield or 0-64.
+ *
+ * @retval GD - Data is good.
+ * @retval UE - Data is uncorrectable.
+ * @retval all others - which bit was corrected.
+ */
+uint8_t correctECC(uint64_t* io_data, uint8_t* io_ecc)
+{
+ uint8_t badBit = verifyECC(*io_data, *io_ecc);
+
+ if ((badBit != ECC_GD) && (badBit != ECC_UE)) /* Good is done, UE is hopeless. */
+ {
+ /* Determine if the ECC or data part is bad, do bit flip. */
+ if (badBit >= ECC_E7)
+ {
+ *io_ecc ^= (1 << (badBit - ECC_E7));
+ }
+ else
+ {
+ *io_data ^= (1ul << (63 - badBit));
+ }
+ }
+ return badBit;
+}
+
+void injectECC(const uint8_t* i_src,
+ size_t i_srcSz,
+ uint8_t* o_dst)
+{
+ assert(0 == (i_srcSz % sizeof(uint64_t)));
+
+ size_t i = 0;
+ size_t o = 0;
+ for(i = 0, o = 0;
+ i < i_srcSz;
+ i += sizeof(uint64_t), o += sizeof(uint64_t) + sizeof(uint8_t))
+ {
+ /* Read data word, copy to destination. */
+ uint64_t data = *((const uint64_t*)(&i_src[i]));
+ *((uint64_t*)(&o_dst[o])) = data;
+ data = be64toh(data);
+
+ /* Calculate ECC, copy to destination. */
+ uint8_t ecc = generateECC(data);
+ o_dst[o + sizeof(uint64_t)] = ecc;
+ }
+}
+
+eccStatus removeECC(uint8_t* io_src,
+ uint8_t* o_dst, size_t i_dstSz)
+{
+ assert(0 == (i_dstSz % sizeof(uint64_t)));
+
+ eccStatus rc = ECC_CLEAN;
+
+ size_t i = 0, o = 0;
+ for(i = 0, o = 0;
+ o < i_dstSz;
+ i += sizeof(uint64_t) + sizeof(uint8_t), o += sizeof(uint64_t))
+ {
+ /* Read data and ECC parts. */
+ uint64_t data = *((uint64_t*)(&io_src[i]));
+ data = be64toh(data);
+ uint8_t ecc = io_src[i + sizeof(uint64_t)];
+
+ /* Calculate failing bit and fix data. */
+ uint8_t badBit = correctECC(&data, &ecc);
+
+ /* Return data to big endian. */
+ data = htobe64(data);
+
+ /* Perform correction and status update. */
+ if (badBit == ECC_UE)
+ {
+ rc = ECC_UNCORRECTABLE;
+ }
+ else if (badBit != ECC_GD)
+ {
+ if (rc != ECC_UNCORRECTABLE)
+ {
+ rc = ECC_CORRECTED;
+ }
+ *((uint64_t*)(&io_src[i])) = data;
+ io_src[i + sizeof(uint64_t)] = ecc;
+ }
+
+ /* Copy fixed data to destination buffer. */
+ *((uint64_t*)(&o_dst[o])) = data;
+ }
+
+ return rc;
+}
+
diff --git a/src/occ/firdata/ecc.h b/src/occ/firdata/ecc.h
new file mode 100644
index 0000000..12ffe4e
--- /dev/null
+++ b/src/occ/firdata/ecc.h
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/ecc.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_ECC_H
+#define __PNOR_ECC_H
+
+#include <native.h>
+
+/** @file ecc.H
+ * @brief Interfaces for the P8 8-byte ECC algorithm.
+ */
+
+/** Status for the ECC removal function. */
+typedef uint8_t eccStatus;
+#define ECC_CLEAN 0x00 /*< No ECC Error was detected. */
+#define ECC_CORRECTED 0x01 /*< ECC error detected and corrected. */
+#define ECC_UNCORRECTABLE 0x02 /*< ECC error detected and uncorrectable. */
+
+/** Bit field identifiers for syndrome calculations. */
+typedef uint8_t eccBitfields;
+#define ECC_GD 0xff /*< Good ECC matches. */
+#define ECC_UE 0xfe /*< Uncorrectable. */
+#define ECC_E0 71 /*< Error in ECC bit 0 */
+#define ECC_E1 70 /*< Error in ECC bit 1 */
+#define ECC_E2 69 /*< Error in ECC bit 2 */
+#define ECC_E3 68 /*< Error in ECC bit 3 */
+#define ECC_E4 67 /*< Error in ECC bit 4 */
+#define ECC_E5 66 /*< Error in ECC bit 5 */
+#define ECC_E6 65 /*< Error in ECC bit 6 */
+#define ECC_E7 64 /*< Error in ECC bit 7 */
+
+/** Inject ECC into a data stream.
+ *
+ * @param[in] i_src - Source data to create ECC on.
+ * @param[in] i_srcSz - Size in bytes of source data.
+ * @param[out] o_dst - Destination buffer of data+ECC.
+ *
+ * @note i_srcSz must be a multiple of 8 bytes.
+ */
+void injectECC(const uint8_t* i_src, size_t i_srcSz,
+ uint8_t* o_dst);
+
+/** Remove ECC from a data stream.
+ *
+ * @param[in,out] io_src - Source data+ECC stream.
+ * @param[out] o_dst - Destination buffer for data only.
+ * @param[in] i_dstSz - Size in bytes of destination ((srcSz / 9) * 8).
+ *
+ * @note i_dstSz must be a multiple of 8 bytes.
+ */
+eccStatus removeECC(uint8_t* io_src,
+ uint8_t* o_dst, size_t i_dstSz);
+
+
+#endif
diff --git a/src/occ/firdata/firData.c b/src/occ/firdata/firData.c
new file mode 100644
index 0000000..e84e8fd
--- /dev/null
+++ b/src/occ/firdata/firData.c
@@ -0,0 +1,754 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/firData.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <native.h>
+
+#include <homerData_common.h>
+#include <pnorData_common.h>
+#include <pnor_util.h>
+#include <scom_trgt.h>
+#include <scom_util.h>
+
+/** Keeps track of pointers to register lists in the HOMER data for each target
+ * type. */
+typedef struct
+{
+ uint32_t * glbl; /*/< Global registers */
+ uint32_t * fir; /*/< Normal FIRs */
+ uint32_t * reg; /*/< Normal registers */
+ uint64_t * idFir; /*/< Indirect-SCOM FIRs */
+ uint64_t * idReg; /*/< Indirect-SCOM registers */
+
+} FirData_ListPointers_t;
+
+/** Contains pointers and sizes for the HOMER and PNOR data buffers. */
+typedef struct
+{
+ uint8_t * hBuf; /*/< Pointer to the HOMER data buffer */
+ uint32_t maxHBufSize; /*/< Maximum size of the HOMER data buffer */
+ HOMER_Data_t * hData; /*/< Pointer to the HOMER header data */
+
+ uint8_t * pBuf; /*/< Pointer to the PNOR data buffer */
+ uint32_t maxPBufSize; /*/< Maximum size of the PNOR data buffer */
+ PNOR_Data_t * pData; /*/< Pointer to the PNOR header data */
+ uint32_t pBufSize; /*/< Current size of the PNOR data buffer */
+
+ FirData_ListPointers_t hPtrs[MAX_TRGTS]; /*/< Pointers to the register lists */
+
+} FirData_t;
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Add generic data to the PNOR buffer.
+ * @param io_fd The FIR data stuct.
+ * @param i_data Pointer to the data to add to the buffer.
+ * @param i_dataSize Size of the data to add to the buffer.
+ * @return True, if where is no room to add the new data. False, otherwise.
+ */
+bool FirData_addDataToPnor( FirData_t * io_fd, void * i_data,
+ uint32_t i_dataSize )
+{
+ bool full = (io_fd->maxPBufSize < io_fd->pBufSize + i_dataSize);
+
+ if ( full )
+ {
+ /* Indicate the PNOR data is full. */
+ io_fd->pData->full = 1;
+ }
+ else
+ {
+ /* Copy data to PNOR buffer. */
+ memcpy( &io_fd->pBuf[io_fd->pBufSize], i_data, i_dataSize );
+ io_fd->pBufSize += i_dataSize;
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief SCOMs hardware and adds a normal register to PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_addr 32-bit address to SCOM.
+ * @param o_nonZero True if the value of the register was non-zero. False,
+ * otherwise.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addRegToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt, uint32_t i_addr,
+ bool * o_nonZero )
+{
+ bool full = false;
+
+ int32_t rc = 0;
+ PNOR_Reg_t reg = { i_addr, 0 };
+
+ *o_nonZero = false;
+
+ do
+ {
+ rc = SCOM_getScom( i_sTrgt, i_addr, &(reg.val) );
+ if ( SUCCESS != rc )
+ {
+ if ( io_pTrgt->scomErrs < PNOR_Trgt_MAX_SCOM_ERRORS )
+ io_pTrgt->scomErrs++;
+ break;
+ }
+
+ if ( 0 == reg.val ) break; // Skip zero value registers.
+
+ full = FirData_addDataToPnor( io_fd, &reg, sizeof(reg) );
+ if ( full ) break;
+
+ *o_nonZero = true;
+
+ if ( io_pTrgt->regs < PNOR_Trgt_MAX_REGS_PER_TRGT )
+ io_pTrgt->regs++;
+
+ } while (0);
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief SCOMs hardware and add a indirect-SCOM register to PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param i_sTrgt Target to SCOM.
+ * @param i_addr 64-bit address to SCOM.
+ * @param o_nonZero True if the value of the register was non-zero. False,
+ * otherwise.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addIdRegToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt, uint64_t i_addr,
+ bool * o_nonZero )
+{
+ bool full = false;
+
+ int32_t rc = 0;
+ PNOR_IdReg_t reg = { i_addr, 0 };
+
+ *o_nonZero = false;
+
+ do
+ {
+ rc = SCOM_getIdScom( i_sTrgt, i_addr, &(reg.val) );
+ if ( SUCCESS != rc )
+ {
+ if ( io_pTrgt->scomErrs < PNOR_Trgt_MAX_SCOM_ERRORS )
+ io_pTrgt->scomErrs++;
+ break;
+ }
+
+ if ( 0 == reg.val ) break; // Skip zero value registers.
+
+ full = FirData_addDataToPnor( io_fd, &reg, sizeof(reg) );
+ if ( full ) break;
+
+ *o_nonZero = true;
+
+ if ( io_pTrgt->idRegs < PNOR_Trgt_MAX_ID_REGS_PER_TRGT )
+ io_pTrgt->idRegs++;
+
+ } while (0);
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of global registers and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @param o_noAttn True, if the global registers showed no active attentions
+ * on the target. False, otherwise.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addGlblsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt, bool * o_noAttn )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][GLBL];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool nonZero = false;
+
+ *o_noAttn = false; /* Must be false if there are no global regs. */
+
+ if ( 0 != cnt )
+ {
+ *o_noAttn = true; /* Assume no attentions. */
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].glbl[i];
+ nonZero = false;
+
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &nonZero );
+ if ( full ) break;
+
+ if ( nonZero ) *o_noAttn = false;
+ }
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of FIRs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addFirsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][FIR];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool nonZero = false;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].fir[i];
+ nonZero = false;
+
+ /* Add FIR */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &nonZero );
+ if ( full ) break;
+
+ /* Add MASK */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 3, &tmp );
+ if ( full ) break;
+
+ if ( nonZero )
+ {
+ /* Add ACT0 */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 6,
+ &tmp );
+ if ( full ) break;
+
+ /* Add ACT1 */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 7,
+ &tmp );
+ if ( full ) break;
+ }
+
+ /* Add WOF */
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr + 8, &tmp );
+ if ( full ) break;
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of REGs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addRegsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][REG];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].reg[i];
+
+ full = FirData_addRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &tmp );
+ if ( full ) break;
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of IDFIRs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addIdFirsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][IDFIR];
+
+ uint32_t i = 0;
+
+ uint64_t addr = 0;
+ bool nonZero = false;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].idFir[i];
+ nonZero = false;
+
+ /* Add FIR */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr,
+ &nonZero );
+ if ( full ) break;
+
+ /* Add MASK */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x300000000ll, &tmp );
+ if ( full ) break;
+
+ if ( nonZero )
+ {
+ /* Add ACT0 */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x600000000ll, &tmp );
+ if ( full ) break;
+
+ /* Add ACT1 */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x700000000ll, &tmp );
+ if ( full ) break;
+ }
+
+ /* Add WOF */
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt,
+ addr + 0x800000000ll, &tmp );
+ if ( full ) break;
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates a list of IDREGs and adds them to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param io_pTrgt Pointer to PNOR target.
+ * @param i_sTrgt SCOM target.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addIdRegsToPnor( FirData_t * io_fd, PNOR_Trgt_t * io_pTrgt,
+ SCOM_Trgt_t i_sTrgt )
+{
+ bool full = false;
+
+ uint8_t t = i_sTrgt.type;
+ uint8_t cnt = io_fd->hData->counts[t][IDREG];
+
+ uint32_t i = 0;
+
+ uint32_t addr = 0;
+ bool tmp = false; /* ignored, not used */
+
+ for ( i = 0; i < cnt; i++ )
+ {
+ addr = io_fd->hPtrs[t].idReg[i];
+
+ full = FirData_addIdRegToPnor( io_fd, io_pTrgt, i_sTrgt, addr, &tmp );
+ if ( full ) break;
+ }
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Adds a target to the PNOR.
+ * @param io_fd The FIR data stuct.
+ * @param i_sTrgt SCOM Target.
+ * @param o_noAttn True, if the global registers showed no active
+ * attentions on the target. False, otherwise.
+ * @return True if the PNOR buffer is full, false if there was room.
+ */
+bool FirData_addTrgtToPnor( FirData_t * io_fd, SCOM_Trgt_t i_sTrgt,
+ bool * o_noAttn )
+{
+ bool full = false;
+
+ PNOR_Trgt_t * pTrgt = (PNOR_Trgt_t *)(&io_fd->pBuf[io_fd->pBufSize]);
+
+ PNOR_Trgt_t tmp_pTrgt = PNOR_getTrgt( i_sTrgt.type, i_sTrgt.procPos,
+ i_sTrgt.procUnitPos );
+
+ *o_noAttn = false; /* Must be false if there are no global regs. */
+
+ do
+ {
+ /* Add the target info to PNOR. */
+ full = FirData_addDataToPnor( io_fd, &tmp_pTrgt, sizeof(tmp_pTrgt) );
+ if ( full ) break;
+
+ /* Update the number of targets in the PNOR data. */
+ io_fd->pData->trgts++;
+
+ /* NOTE: Must add all regular registers (GLBL, FIR, REG) before all */
+ /* indirect-SCOM registers. Also, must check GLBL registers first */
+ /* to determine whether it is necessary to do the other registers. */
+
+ /* Add the GLBLs. */
+ full = FirData_addGlblsToPnor( io_fd, pTrgt, i_sTrgt, o_noAttn );
+ if ( full || *o_noAttn ) break;
+
+ /* Add the FIRs. */
+ full = FirData_addFirsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ /* Add the REGs. */
+ full = FirData_addRegsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ /* Add the IDFIRs. */
+ full = FirData_addIdFirsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ /* Add the IDREGs. */
+ full = FirData_addIdRegsToPnor( io_fd, pTrgt, i_sTrgt );
+ if ( full ) break;
+
+ } while (0);
+
+ return full;
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Iterates through configured targets and adds the data to PNOR.
+ * @param io_fd The FIR data stuct.
+ */
+void FirData_addTrgtsToPnor( FirData_t * io_fd )
+{
+ bool full = false;
+ bool noAttn = false;
+
+ uint8_t p = 0;
+ uint8_t u = 0;
+ uint8_t mu = 0;
+ uint8_t i = 0;
+ uint8_t j = 0;
+
+ bool isM = false;
+ uint32_t fsi = 0;
+
+ SCOM_Trgt_t sTrgt;
+
+ do
+ {
+ /* Iterate all PROCs. */
+ for ( p = 0; p < MAX_PROC_PER_NODE; p++ )
+ {
+ /* Check if the PROC is configured. */
+ if ( 0 == (io_fd->hData->procMask & (0x80 >> p)) ) continue;
+ TRACFCOMP("proc %d",p);
+
+ /* Check if this PROC is the master PROC and get the FSI base addr. */
+ isM = ( p == io_fd->hData->masterProc );
+ fsi = io_fd->hData->procFsiBaseAddr[p];
+
+ /* Add this PROC to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(PROC, p, 0, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the PROC, EXs, and MCSs */
+
+ for ( u = 0; u < MAX_EX_PER_PROC; u++ )
+ {
+ /* Check if the EX is configured. */
+ if ( 0 == (io_fd->hData->exMasks[p] & (0x8000 >> u)) ) continue;
+ TRACFCOMP("ex %d",u);
+
+ /* Add this EX to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(EX, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the EX */
+ }
+ if ( full ) break;
+
+ for ( u = 0; u < MAX_MCS_PER_PROC; u++ )
+ {
+ /* Check if the MCS is configured. */
+ if ( 0 == (io_fd->hData->mcsMasks[p] & (0x80 >> u)) ) continue;
+ TRACFCOMP("mcs %d",u);
+
+ /* Add this MCS to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(MCS, p, u, fsi, isM);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the MCS */
+ }
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ /* Iterate all MEMBs. Must do this separate of from the PROCs because */
+ /* it is possible a MEMB could be reporting an attention but the */
+ /* connected PROC is not. */
+ for ( i = 0; i < MAX_MEMB_PER_NODE; i++ )
+ {
+ p = i / MAX_MEMB_PER_PROC;
+ u = i % MAX_MEMB_PER_PROC;
+
+ /* Check if the MEMB is configured. */
+ if ( 0 == (io_fd->hData->membMasks[p] & (0x80 >> u)) ) continue;
+ TRACFCOMP("memb %d",u);
+
+ /* Get the FSI base address. */
+ fsi = io_fd->hData->membFsiBaseAddr[p][u];
+
+ /* Add this MEMB to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(MEMB, p, u, fsi, false);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the MEMB and MBAs */
+
+ for ( j = 0; j < MAX_MBA_PER_MEMB; j++ )
+ {
+ mu = u * MAX_MBA_PER_MEMB + j;
+
+ /* Check if the MBA is configured. */
+ if ( 0 == (io_fd->hData->mbaMasks[p] & (0x8000 >> mu)) )
+ continue;
+ TRACFCOMP("mba %d",mu);
+
+ /* Add this MBA to the PNOR. */
+ sTrgt = SCOM_Trgt_getTrgt(MBA, p, mu, fsi, false);
+ full = FirData_addTrgtToPnor( io_fd, sTrgt, &noAttn );
+ if ( full ) break;
+ if ( noAttn ) continue; /* Skip the MEMB */
+ }
+ if ( full ) break;
+ }
+ if ( full ) break;
+
+ } while (0);
+
+}
+
+/*------------------------------------------------------------------------------ */
+
+/** @brief Initializes the FIR data struct. Does range checking for the HOMER
+ * data. Initializes the PNOR header data.
+ * @param io_fd The FIR data stuct.
+ * @param i_hBuf SRAM pointer to the beginning of the HOMER data buffer.
+ * This should contain the FIR data information provided by
+ * PRD that is used to define which registers the OCC will
+ * need to SCOM.
+ * @param i_hBufSize Total size of the HOMER data buffer.
+ * @param i_pBuf SRAM pointer to the beginning of the PNOR data buffer.
+ * This will be used by this function as a temporary area of
+ * memory to store the PNOR data before writing that data to
+ * the PNOR.
+ * @param i_pBufSize Total size of the PNOR data buffer.
+ * @return Non-SUCCESS if HOMER or PNOR range checking fails or if an
+ * internal function fails. SUCCESS otherwise.
+ */
+int32_t FirData_init( FirData_t * io_fd,
+ uint8_t * i_hBuf, uint32_t i_hBufSize,
+ uint8_t * i_pBuf, uint32_t i_pBufSize )
+{
+ #define FUNC "[FirData_init] "
+
+ int32_t rc = SUCCESS;
+
+ size_t sz_hData = sizeof(HOMER_Data_t);
+ size_t sz_pnoNoEcc = 0;
+ size_t sz_u32 = sizeof(uint32_t);
+ size_t sz_u64 = sizeof(uint64_t);
+
+ bool full = false;
+
+ uint32_t x[MAX_TRGTS][MAX_REGS];
+ size_t curIdx = 0;
+
+ uint32_t t = FIRST_TRGT;
+
+ uint8_t * reglist = NULL;
+
+ PNOR_Data_t pData = PNOR_getData();
+
+ do
+ {
+ /* Init the struct. */
+ io_fd->hBuf = i_hBuf;
+ io_fd->maxHBufSize = i_hBufSize;
+ io_fd->hData = (HOMER_Data_t *)i_hBuf;
+
+ io_fd->pBuf = i_pBuf;
+ io_fd->maxPBufSize = i_pBufSize;
+ io_fd->pData = (PNOR_Data_t *)i_pBuf;
+ io_fd->pBufSize = 0;
+
+ memset( io_fd->hPtrs, 0x00, sizeof(io_fd->hPtrs) );
+
+ /* Check HOMER header data size. */
+ if ( io_fd->maxHBufSize < sz_hData )
+ {
+ TRACFCOMP( FUNC"HOMER header data size %d is larger than HOMER "
+ "data buffer %d", sz_hData, io_fd->maxHBufSize );
+ rc = FAIL;
+ break;
+ }
+
+ /* Check for valid HOMER data. */
+ if ( HOMER_FIR1 != io_fd->hData->header )
+ {
+ break; /* nothing to analyze. */
+ }
+
+ /* The actual maximum PNOR size may possibly be less then the PNOR data */
+ /* buffer. If so, adjust maximum size. */
+ sz_pnoNoEcc = (io_fd->hData->pnorInfo.pnorSize / 9) * 8;
+ if ( sz_pnoNoEcc < io_fd->maxPBufSize )
+ io_fd->maxPBufSize = sz_pnoNoEcc;
+
+ /* Initialize the PNOR header data. */
+ full = FirData_addDataToPnor( io_fd, &pData, sizeof(pData) );
+ if ( full )
+ {
+ TRACFCOMP( FUNC"Unable to add header to PNOR buffer" );
+ rc = FAIL;
+ break;
+ }
+
+ /* Get the register list byte indexes in HOMER data buffer */
+ memset( x, 0x00, sizeof(x) );
+ for ( t = FIRST_TRGT; t < MAX_TRGTS; t++ )
+ {
+ x[t][GLBL] = curIdx;
+ x[t][FIR] = x[t][GLBL] + sz_u32 * io_fd->hData->counts[t][GLBL];
+ x[t][REG] = x[t][FIR] + sz_u32 * io_fd->hData->counts[t][FIR];
+ x[t][IDFIR] = x[t][REG] + sz_u32 * io_fd->hData->counts[t][REG];
+ x[t][IDREG] = x[t][IDFIR] + sz_u64 * io_fd->hData->counts[t][IDFIR];
+ curIdx = x[t][IDREG] + sz_u64 * io_fd->hData->counts[t][IDREG];
+ }
+
+ /* Check to make sure the list data is not larger than the available */
+ /* Homer buffer. */
+ if ( io_fd->maxHBufSize - sz_hData < curIdx )
+ {
+ TRACFCOMP( FUNC"HOMER list size %d is larger than HOMER data "
+ "buffer %d", curIdx, io_fd->maxHBufSize - sz_hData );
+ rc = FAIL;
+ break;
+ }
+
+ /* Now, get the pointers for each list. */
+ reglist = io_fd->hBuf + sz_hData;
+ for ( t = FIRST_TRGT; t < MAX_TRGTS; t++ )
+ {
+ (io_fd->hPtrs[t]).glbl = (uint32_t *)(reglist + x[t][GLBL] );
+ (io_fd->hPtrs[t]).fir = (uint32_t *)(reglist + x[t][FIR] );
+ (io_fd->hPtrs[t]).reg = (uint32_t *)(reglist + x[t][REG] );
+ (io_fd->hPtrs[t]).idFir = (uint64_t *)(reglist + x[t][IDFIR]);
+ (io_fd->hPtrs[t]).idReg = (uint64_t *)(reglist + x[t][IDREG]);
+ }
+
+ } while (0);
+
+ return rc;
+
+ #undef FUNC
+}
+
+
+/*------------------------------------------------------------------------------ */
+/* External functions */
+/*------------------------------------------------------------------------------ */
+
+int32_t FirData_captureCsFirData( uint8_t * i_hBuf, uint32_t i_hBufSize,
+ uint8_t * i_pBuf, uint32_t i_pBufSize )
+{
+ #define FUNC "[FirData_captureCsFirData] "
+ TRACFCOMP( "FirData_captureCsFirData> hBuf=%p, hBufSize=%X, pBuf=%p, pBufSize=%.8X", i_hBuf, i_hBufSize, i_pBuf, i_pBufSize );
+ int32_t rc = SUCCESS;
+
+ do
+ {
+ /* Init the FIR data struct. */
+ FirData_t fd;
+ rc = FirData_init( &fd, i_hBuf, i_hBufSize, i_pBuf, i_pBufSize );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( FUNC"Failed to init FIR data" );
+ break;
+ }
+
+ /* Check for valid HOMER data. */
+ if ( HOMER_FIR1 != fd.hData->header )
+ {
+ TRACFCOMP( FUNC"No HOMER data=%.8X",fd.hData->header );
+ break; /* nothing to analyze. */
+ }
+
+ /* Start adding register data to PNOR for each target. */
+ FirData_addTrgtsToPnor( &fd );
+
+ /* Write the buffer to PNOR. */
+ rc = PNOR_writeFirData( fd.hData->pnorInfo, fd.pBuf, fd.pBufSize );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( FUNC"Failed to process FIR data" );
+ break;
+ }
+
+ } while (0);
+
+ return rc;
+
+ #undef FUNC
+}
+
diff --git a/src/occ/firdata/firData.h b/src/occ/firdata/firData.h
new file mode 100644
index 0000000..f1475db
--- /dev/null
+++ b/src/occ/firdata/firData.h
@@ -0,0 +1,48 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/firData.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __firData_h
+#define __firData_h
+
+#include "native.h"
+
+/** @brief Reads the register list from the HOMER data, SCOMs hardware, and
+ * stores the register values in PNOR.
+ * @param i_hBuf SRAM pointer to the beginning of the HOMER data buffer.
+ * This should contain the FIR data information provided by
+ * PRD that is used to define which registers the OCC will
+ * need to SCOM.
+ * @param i_hBufSize Total size of the HOMER data buffer.
+ * @param i_pBuf SRAM pointer to the beginning of the PNOR data buffer.
+ * This will be used by this function as a temporary area
+ * of memory to store the PNOR data before writing that
+ * data to the PNOR.
+ * @param i_pBufSize Total size of the PNOR data buffer.
+ * @return Non-SUCCESS if an internal function fails. SUCCESS otherwise.
+ */
+int32_t FirData_captureCsFirData( uint8_t * i_hBuf, uint32_t i_hBufSize,
+ uint8_t * i_pBuf, uint32_t i_pBufSize );
+
+#endif /* __firData_h */
diff --git a/src/occ/firdata/firDataConst_common.h b/src/occ/firdata/firDataConst_common.h
new file mode 100644
index 0000000..86a3ccc
--- /dev/null
+++ b/src/occ/firdata/firDataConst_common.h
@@ -0,0 +1,75 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/occ_const.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __firDataConst_common_h
+#define __firDataConst_common_h
+
+/** NOTE: This file is common between OCC and Hosboot. Any change to this file
+ * must be mirrored to both repositories. */
+
+#include <stdint.h>
+
+/** Target types for all supported targets. */
+typedef enum
+{
+ /* NOTE: These will be used as array indexes. */
+ FIRST_TRGT = 0,
+ PROC = FIRST_TRGT,
+ EX,
+ MCS,
+ MEMB,
+ MBA,
+ MAX_TRGTS,
+
+} TrgtType_t;
+
+/** Boundary/position ranges for each target type. */
+typedef enum
+{
+ MAX_PROC_PER_NODE = 8,
+ MAX_EX_PER_PROC = 16,
+ MAX_MCS_PER_PROC = 8,
+ MAX_MEMB_PER_PROC = MAX_MCS_PER_PROC,
+ MAX_MEMB_PER_NODE = MAX_MEMB_PER_PROC * MAX_PROC_PER_NODE,
+ MAX_MBA_PER_MEMB = 2,
+ MAX_MBA_PER_PROC = MAX_MEMB_PER_PROC * MAX_MBA_PER_MEMB,
+
+} TrgtPos_t;
+
+/** All register types. */
+typedef enum
+{
+ /* NOTE: These will be used as array indexes. */
+ FIRST_REG = 0,
+ GLBL = FIRST_REG,
+ FIR,
+ REG,
+ IDFIR,
+ IDREG,
+ MAX_REGS,
+
+} RegType_t;
+
+#endif /* __firDataConst_common_h */
diff --git a/src/occ/firdata/fir_data_collect.c b/src/occ/firdata/fir_data_collect.c
new file mode 100644
index 0000000..1930fa5
--- /dev/null
+++ b/src/occ/firdata/fir_data_collect.c
@@ -0,0 +1,163 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fir_data_collect.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+
+#include <fir_data_collect.h>
+#include <scom.h>
+#include <occ_service_codes.h>
+#include <errl.h>
+#include "tpc_firmware_registers.h"
+#include "tpc_register_addresses.h"
+#include <trac.h>
+#include <homer.h>
+
+FIR_HEAP_BUFFER(uint8_t G_fir_heap[FIR_HEAP_SECTION_SIZE]);
+FIR_PARMS_BUFFER(uint8_t G_fir_data_parms[FIR_PARMS_SECTION_SIZE]);
+uint32_t G_fir_master = FIR_OCC_NOT_FIR_MASTER;
+
+/*
+ * Function Specification
+ *
+ * Name: fir_data_collect
+ *
+ * Description: Collects FIR data on checkstop.
+ *
+ * End Function Specification
+ */
+void fir_data_collect(void)
+{
+ int32_t l_rc = 0;
+
+ // Homer data section and size
+ uint8_t *l_hBuf = FIR_PARMS_SECTION_BASE_ADDRESS;
+ uint32_t l_hBufSize = HOMER_FIR_PARM_SIZE;
+ // PNOR working buffer in SRAM and size
+ uint8_t *l_pBuf = FIR_HEAP_SECTION_BASE_ADDRESS;
+ uint32_t l_pBufSize = FIR_HEAP_SECTION_SIZE;
+
+ l_rc = FirData_captureCsFirData(l_hBuf,
+ l_hBufSize,
+ l_pBuf,
+ l_pBufSize);
+
+ // Trace the rc only, error logs cannot be collected in this state
+ TRAC_IMP("Checkstop FIR data capture completed with rc=%d", l_rc);
+}
+
+
+/*
+ * Function Specification
+ *
+ * Name: pnor_access_ok
+ *
+ * Description: Determines if it is ok for this OCC to access the PNOR.
+ *
+ * End Function Specification
+ */
+bool pnor_access_allowed(void)
+{
+ /* BMC ownership of the PNOR is indicated by bit 18 in TPC_GP0 */
+ int l_rc = 0;
+ tpc_gp0_t l_tp_gp0_read;
+ bool l_access_allowed = FALSE;
+
+ l_tp_gp0_read.words.high_order = 0x00000000;
+ l_tp_gp0_read.words.low_order = 0x00000000;
+
+ l_rc = getscom_ffdc(TPC_GP0, (uint64_t *)&l_tp_gp0_read, NULL);
+
+ if (l_rc == 0)
+ {
+ if ((l_tp_gp0_read.words.high_order & TPC_GP0_BIT18_PNOR_OWNER_MASK) == 0)
+ {
+ TRAC_INFO("PNOR access allowed at this time");
+ l_access_allowed = TRUE;
+ }
+ else
+ {
+ TRAC_INFO("PNOR access NOT allowed at this time, tpc_gp0.hi = 0x%08x",
+ l_tp_gp0_read.words.high_order);
+
+ /* @
+ * @errortype
+ * @moduleid FIR_DATA_MID
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 TPC_GP0 high word
+ * @userdata4 ERC_PNOR_OWNERSHIP_NOT_AVAILABLE
+ * @devdesc PNOR access not allowed at this time.
+ */
+ errlHndl_t l_errl = createErrl(
+ FIR_DATA_MID, /*ModId */
+ INTERNAL_FAILURE, /*Reasoncode */
+ ERC_PNOR_OWNERSHIP_NOT_AVAILABLE, /*Extended reasoncode */
+ ERRL_SEV_INFORMATIONAL, /*Severity */
+ NULL, /*Trace Buf */
+ DEFAULT_TRACE_SIZE, /*Trace Size */
+ l_tp_gp0_read.words.high_order, /*Userdata1 */
+ 0 /*Userdata2 */
+ );
+
+ /* Commit log */
+ commitErrl(&l_errl);
+ }
+ }
+ else
+ {
+ /* getscom failure */
+ TRAC_ERR("TPC_GP0 getscom failure rc = 0x%08x", -l_rc );
+
+ /* @
+ * @errortype
+ * @moduleid FIR_DATA_MID
+ * @reasoncode INTERNAL_HW_FAILURE
+ * @userdata1 getscom failure rc
+ * @userdata4 ERC_GETSCOM_TPC_GP0_FAILURE
+ * @devdesc Failure determining PNOR ownership. Cannot read TPC_GP0.
+ */
+ errlHndl_t l_errl = createErrl(
+ FIR_DATA_MID, /*ModId */
+ INTERNAL_HW_FAILURE, /*Reasoncode */
+ ERC_GETSCOM_TPC_GP0_FAILURE, /*Extended reasoncode */
+ ERRL_SEV_PREDICTIVE, /*Severity */
+ NULL, /*Trace Buf */
+ DEFAULT_TRACE_SIZE, /*Trace Size */
+ l_rc, /*Userdata1 */
+ 0 /*Userdata2 */
+ );
+
+ /* Callout firmware */
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ /* Commit log */
+ commitErrl(&l_errl);
+ }
+
+ return l_access_allowed;
+}
+
+
diff --git a/src/occ/firdata/fir_data_collect.h b/src/occ/firdata/fir_data_collect.h
new file mode 100644
index 0000000..c313956
--- /dev/null
+++ b/src/occ/firdata/fir_data_collect.h
@@ -0,0 +1,56 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fir_data_collect.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+
+#ifndef _FIR_DATA_COLLECT_H
+#define _FIR_DATA_COLLECT_H
+
+#include <common_types.h>
+
+/* This size has to agree with the size _FIR_PARMS_SECTION_SIZE defined in the */
+/* OCC linker command file. */
+#define FIR_PARMS_SECTION_SIZE 0x1000
+// This size has to agree with the size _FIR_HEAP_SECTION_SIZE defined in the
+// OCC linker command file.
+#define FIR_HEAP_SECTION_SIZE 0x3000
+
+enum fir_master
+{
+ FIR_OCC_NOT_FIR_MASTER = 0x00000000,
+ FIR_OCC_IS_FIR_MASTER = 0x00000001
+};
+
+extern uint8_t G_fir_data_parms[FIR_PARMS_SECTION_SIZE];
+extern uint8_t G_fir_heap[FIR_HEAP_SECTION_SIZE];
+extern uint32_t G_fir_master;
+
+#define OCC_SET_FIR_MASTER(_fm_t) G_fir_master = _fm_t
+#define OCC_IS_FIR_MASTER() (G_fir_master == FIR_OCC_IS_FIR_MASTER) ? TRUE : FALSE
+#define TPC_GP0_BIT18_PNOR_OWNER_MASK 0x00002000
+
+void fir_data_collect(void);
+bool pnor_access_allowed(void);
+
+#endif /* _FIR_DATA_COLLECT_H */
diff --git a/src/occ/firdata/fsi.c b/src/occ/firdata/fsi.c
new file mode 100644
index 0000000..111bf2e
--- /dev/null
+++ b/src/occ/firdata/fsi.c
@@ -0,0 +1,115 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fsi.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <fsi.h>
+#include <scom_util.h>
+#include <native.h>
+
+#define OPB_REG_CMD 0x00020000
+#define OPB_REG_STAT 0x00020001
+#define OPB_STAT_BUSY 0x0001000000000000 /**< 15 is the Busy bit */
+#define NS_PER_MSEC (1000000ull)
+
+
+/**
+ * @brief Poll for completion of a FSI operation, return data on read
+ */
+uint32_t poll_for_complete( void )
+{
+ enum { MAX_OPB_TIMEOUT_NS = 10*NS_PER_MSEC }; /*=10ms */
+
+ /* poll for complete */
+ uint64_t read_data = FSIFAIL;
+ uint64_t elapsed_time_ns = 0;
+ do
+ {
+ read_data = xscom_read(OPB_REG_STAT);
+ /* check for completion or xscom error */
+ /* note: not checking for FSI errors */
+ if( ((read_data & OPB_STAT_BUSY) == 0) /*not busy */
+ || (read_data == SCOMFAIL) ) /*scom error */
+ {
+ break;
+ }
+ else
+ {
+ read_data = FSIFAIL;
+ }
+
+ sleep( 10000 ); /*sleep for 10,000 ns */
+ elapsed_time_ns += 10000;
+ } while( elapsed_time_ns <= MAX_OPB_TIMEOUT_NS );
+
+ return (uint32_t)read_data; /*data in the bottom half */
+}
+
+/**
+ * @brief Read a FSI register
+ */
+uint32_t getfsi( SCOM_Trgt_t i_target, uint32_t i_address )
+{
+ uint32_t fsi_base = i_target.fsiBaseAddr;
+ uint32_t fsi_addr = fsi_base | i_address;
+
+ /* setup the OPB command register */
+ /* only supporting 4-byte access */
+ uint64_t fsi_cmd = fsi_addr | 0x60000000; /*011=Read Full Word */
+ fsi_cmd <<= 32; /* Command is in the upper word of the scom */
+
+ /* write the OPB command register to trigger the read */
+ xscom_write( OPB_REG_CMD, fsi_cmd );
+
+ /* poll for complete and get the data back */
+ uint32_t out_data = poll_for_complete();
+
+ return out_data;
+}
+
+
+/**
+ * @brief Write a FSI register
+ */
+void putfsi( SCOM_Trgt_t i_target,
+ uint32_t i_address,
+ uint32_t i_data )
+{
+ uint32_t fsi_base = i_target.fsiBaseAddr;
+ uint32_t fsi_addr = fsi_base | i_address;
+
+ /* setup the OPB command register */
+ /* only supporting 4-byte access */
+ uint64_t fsi_cmd = fsi_addr | 0xE0000000; /* 111=Write Full Word */
+ fsi_cmd <<= 32; /* Command is in the upper word of the scom */
+ fsi_cmd |= i_data; /* Data is in the bottom 32-bits */
+
+ /* write the OPB command register to trigger the read */
+ xscom_write( OPB_REG_CMD, fsi_cmd );
+
+ /* poll for complete */
+ poll_for_complete();
+
+ return;
+}
+
diff --git a/src/occ/firdata/fsi.h b/src/occ/firdata/fsi.h
new file mode 100644
index 0000000..f3e6fab
--- /dev/null
+++ b/src/occ/firdata/fsi.h
@@ -0,0 +1,47 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/fsi.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/* Interfaces to read/write FSI registers */
+
+#include <scom_trgt.h>
+
+#define FSIFAIL 0xDEADBEEF
+
+/**
+ * @brief Read a FSI register
+ * @param[in] Chip/unit to read from
+ * @param[in] FSI address to read, relative to slave's base address
+ * @return FSI data on success, FSIFAIL on error
+ */
+uint32_t getfsi( SCOM_Trgt_t i_target, uint32_t i_address );
+
+/**
+ * @brief Write a FSI register
+ * @param[in] Chip/unit to write to
+ * @param[in] FSI address to write, relative to slave's base address
+ * @param[in] Data to write
+ */
+void putfsi( SCOM_Trgt_t i_target, uint32_t i_address, uint32_t i_data );
+
diff --git a/src/occ/firdata/homerData_common.h b/src/occ/firdata/homerData_common.h
new file mode 100644
index 0000000..c010293
--- /dev/null
+++ b/src/occ/firdata/homerData_common.h
@@ -0,0 +1,170 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/homerData.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __homerData_common_h
+#define __homerData_common_h
+
+/** NOTE: This file is common between OCC and Hosboot. Any change to this file
+ * must be mirrored to both repositories. */
+
+#include <firDataConst_common.h>
+#include <string.h>
+
+/** This file is used to define the format of the register list stored in the
+ * HOMER data that the OCC will use to determine what register data to capture
+ * in the event of a system checkstop. The data will be stored in the following
+ * format:
+ *
+ * - HOMER_Data_t struct - This has all of the information characterizing what
+ * hardware is configured and how many addresses are in each register
+ * list. See the struct definition below.
+ *
+ * - Rgister address lists - These lists vary in size depending on the number
+ * of register addresses needed in each list. The list counts are
+ * stored in HOMER_Data_t::counts. All lists for each target type will
+ * be stored in the following order:
+ * - PROC lists
+ * - EX lists
+ * - MCS lists
+ * - MEMB lists
+ * - MBA lists
+ * Each target type will have a set of lists that will be stored in the
+ * following order:
+ * - Global FIRs 32-bit addresses
+ * - FIRs 32-bit addresses
+ * - Registers 32-bit addresses
+ * - Indirect-SCOM FIRs 64-bit addresses
+ * - Indirect-SCOM registers 64-bit addresses
+ *
+ * Note that FIRs and indirect-SCOM FIRs characterize a set of registers to
+ * capture. In addition to capturing the FIR (or ID FIR), the OCC will need to
+ * capture the following addresses for each type:
+ * - FIR
+ * - MASK (FIR address + 3)
+ * - ACT0 (FIR address + 6)
+ * - ACT1 (FIR address + 7)
+ * - WOF (FIR address + 8)
+ * - ID FIR
+ * - ID MASK (ID FIR address + 0x300000000ll)
+ * - ID ACT0 (ID FIR address + 0x600000000ll)
+ * - ID ACT1 (ID FIR address + 0x700000000ll)
+ * - ID WOF (ID FIR address + 0x800000000ll)
+ */
+
+typedef enum Version
+{
+ HOMER_FIR1 = 0x46495231, /*/< FIR data version 1 ("FIR1" in ascii) */
+
+} HOMER_Version_t;
+
+/** PNOR information contained within the HOMER data. */
+typedef struct __attribute__((packed))
+{
+ uint32_t pnorOffset; /*/< Physical offset of FIRDATA in PNOR */
+ uint32_t pnorSize; /*/< Maximum size of FIRDATA (includes ECC) */
+ uint32_t mmioOffset; /*/< Address of MMIO access */
+ uint32_t norWorkarounds; /*/< NOR flash vendor */
+
+} HOMER_PnorInfo_t;
+
+/** HOMER data header information containing hardware configurations and
+ * register counts. */
+typedef struct __attribute__((packed))
+{
+ uint32_t header; /*/< Magic number to indicate valid data and version */
+
+ uint16_t reserved;
+
+ uint8_t masterProc; /*/< The position of the master PROC */
+
+ /** Bitwise mask to indicate which PROCs are configured (max 8). The mask
+ * bit position is consistant with PROC ATTR_POSITION attribute. */
+ uint8_t procMask;
+
+ /** Bitwise masks to indicate which EXs are configured (16 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * consistant with the EX's ATTR_CHIP_UNIT attribute. */
+ uint16_t exMasks[MAX_PROC_PER_NODE];
+
+ /** Bitwise masks to indicate which MCSs are configured (8 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * consistant with the MCS's ATTR_CHIP_UNIT attribute. */
+ uint8_t mcsMasks[MAX_PROC_PER_NODE];
+
+ /** Bitwise masks to indicate which MEMBs are configured (8 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * consistant with the ATTR_CHIP_UNIT attribute of the connected MCS. */
+ uint8_t membMasks[MAX_PROC_PER_NODE];
+
+ /** Bitwise masks to indicate which MBAs are configured (16 per PROC). The
+ * array index is the associated PROC position. The mask bit position is
+ * calculated as:
+ * (MEMB position * MAX_MBA_PER_MEMB) + MBA's ATTR_CHIP_UNIT attribute
+ */
+ uint16_t mbaMasks[MAX_PROC_PER_NODE];
+
+ /** Contains number of registers per type for each target type. */
+ uint8_t counts[MAX_TRGTS][MAX_REGS];
+
+ /** FSI base address for each PROC chip. */
+ uint32_t procFsiBaseAddr[MAX_PROC_PER_NODE];
+
+ /** FSI base address for each MEMB chip. */
+ uint32_t membFsiBaseAddr[MAX_PROC_PER_NODE][MAX_MEMB_PER_PROC];
+
+ /** Information regarding the PNOR location and size. */
+ HOMER_PnorInfo_t pnorInfo;
+
+} HOMER_Data_t;
+
+/** @return An initialized HOMER_Data_t struct. */
+static inline HOMER_Data_t HOMER_getData()
+{
+ HOMER_PnorInfo_t p;
+ HOMER_Data_t d;
+
+ p.pnorOffset = 0;
+ p.pnorSize = 0;
+ p.mmioOffset = 0;
+ p.norWorkarounds = 0;
+
+ d.header = HOMER_FIR1;
+ d.reserved = 0;
+ d.masterProc = 0;
+ d.procMask = 0;
+ d.pnorInfo = p;
+
+ memset( d.exMasks, 0x00, sizeof(d.exMasks) );
+ memset( d.mcsMasks, 0x00, sizeof(d.mcsMasks) );
+ memset( d.membMasks, 0x00, sizeof(d.membMasks) );
+ memset( d.mbaMasks, 0x00, sizeof(d.mbaMasks) );
+ memset( d.counts, 0x00, sizeof(d.counts) );
+ memset( d.procFsiBaseAddr, 0xff, sizeof(d.procFsiBaseAddr) );
+ memset( d.membFsiBaseAddr, 0xff, sizeof(d.membFsiBaseAddr) );
+
+ return d;
+}
+
+#endif /* __homerData_common_h */
diff --git a/src/occ/firdata/lpc.c b/src/occ/firdata/lpc.c
new file mode 100644
index 0000000..8bcdb5f
--- /dev/null
+++ b/src/occ/firdata/lpc.c
@@ -0,0 +1,302 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/lpc.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <native.h>
+#include <lpc.h>
+#include <trac_interface.h>
+
+#define LPCHC_FW_SPACE 0xF0000000 /**< LPC Host Controller FW Space */
+#define LPCHC_MEM_SPACE 0xE0000000 /**< LPC Host Controller Mem Space */
+#define LPCHC_IO_SPACE 0xD0010000 /**< LPC Host Controller I/O Space */
+#define LPCHC_REG_SPACE 0xC0012000 /**< LPC Host Ctlr Register Space */
+
+#define ECCB_NON_FW_RESET_REG 0x000B0001 /**< ECCB Reset Reg (non-FW) */
+
+#define ECCB_CTL_REG 0x000B0020 /**< ECCB Control Reg (FW) */
+#define ECCB_RESET_REG 0x000B0021 /**< ECCB Reset Reg (FW) */
+#define ECCB_STAT_REG 0x000B0022 /**< ECCB Status Reg (FW) */
+#define ECCB_DATA_REG 0x000B0023 /**< ECCB Data Reg (FW) */
+
+/* Default Values to set for all operations
+ 1101.0100.0000.000x.0000.0001.0000.0000.<address> */
+#define ECCB_CTL_REG_DEFAULT 0xD400010000000000
+
+/* Error bits: 41-43 56 (52cmd complete) (not 57: only non-fw use) */
+#define ECCB_STAT_REG_ERROR_MASK 0x0000000000700080 /**< Error Bits */
+
+/**< OPB LPCM Sync FIR Reg - used to read the FIR*/
+#define OPB_LPCM_FIR_REG 0x01010C00
+
+/**< OPB LPCM Sync FIR Reg WOX_AND - used to clear the FIR */
+#define OPB_LPCM_FIR_WOX_AND_REG 0x01010C01
+
+/**< OPB LPCM Sync FIR Mask Reg WO_OR - used to set the mask */
+#define OPB_LPCM_FIR_MASK_WO_OR_REG 0x01010C05
+
+#define OPB_LPCM_FIR_ERROR_MASK 0xFF00000000000000 /**< Error Bits MASK */
+
+/* LPCHC reset-related registers */
+#define OPB_MASTER_LS_CONTROL_REG 0x008 /**<OPBM LS Control Reg */
+#define LPCHC_RESET_REG 0x0FC /**<LPC HC Reset Register */
+
+#define ECCB_RESET_LPC_FAST_RESET (1ULL << 62) /**< bit 1 Fast reset */
+
+#define ECCB_POLL_TIME_NS 400000 /**< max time should be 400ms */
+//dc99 #define ECCB_POLL_INCR_NS 10 /**< minimum increment during poll */
+#define ECCB_POLL_INCR_NS 100000 /**< increase for testing */
+
+#define LPCHC_SYNC_CYCLE_COUNTER_INFINITE 0xFF000000
+
+int TRACE_LPC = 0;
+#define TRACZCOMP(args...) if(TRACE_LPC){TRACFCOMP(args);}
+
+/* Set to enable LPC tracing. */
+/* #define LPC_TRACING 1 */
+#ifdef LPC_TRACING
+#define LPC_TRACFCOMP(des,printf_string,args...) \
+ TRACFCOMP(des,printf_string,##args) /* FIX FIRDATA */
+#else
+#define LPC_TRACFCOMP(args...)
+#endif
+
+/**
+ * @brief ECCB Control Register Layout
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ /* unused sections should be set to zero */
+ uint64_t magic1 : 4; /**< 0:3 = b1101 per spec */
+ uint64_t data_len : 4; /**< 4:7 = b0100 means 4 byte */
+ uint64_t unused1 : 7; /**< 8:14 */
+ uint64_t read_op : 1; /**< 15 = set for read operation */
+ uint64_t unused2 : 7; /**< 16:22 */
+ uint64_t addr_len : 3; /**< 23:25 = b100 means 4 byte */
+ uint64_t unused3 : 6; /**< 26:31 */
+ uint64_t address : 32; /**< 32:63 = LPC Address */
+ };
+} ControlReg_t;
+
+/**
+ * @brief ECCB Status Register Layout
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ uint64_t unused : 6; /**< 0:5 */
+ uint64_t read_data : 32; /**< 6:37 */
+ uint64_t unused1 : 3; /**< 38:40 */
+ uint64_t eccb_err : 3; /**< 41:43 = ECCB_Error_Info */
+ uint64_t busy : 1; /**< 44 = Operation Busy */
+ uint64_t unused2 : 7; /**< 45:51 */
+ uint64_t op_done : 1; /**< 52 = Command Complete */
+ uint64_t unused3 : 3; /**< 53:55 */
+ uint64_t addr_parity_err : 1; /**< 56 = ECC Address Register
+ Parity Error */
+ uint64_t unused4 : 7; /**< 57:63 */
+ };
+} StatusReg_t;
+
+
+uint32_t checkAddr(LpcTransType i_type,
+ uint32_t i_addr)
+{
+ uint32_t full_addr = 0;
+ switch ( i_type )
+ {
+ case LPC_TRANS_IO:
+ full_addr = i_addr | LPCHC_IO_SPACE;
+ break;
+ case LPC_TRANS_FW:
+ full_addr = i_addr | LPCHC_FW_SPACE;
+ break;
+ }
+ return full_addr;
+}
+
+
+errorHndl_t pollComplete(const ControlReg_t* i_ctrl,
+ StatusReg_t* o_stat)
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ do
+ {
+ o_stat->data64 = xscom_read( ECCB_STAT_REG );
+ LPC_TRACFCOMP( "writeLPC> Poll on ECCB Status, "
+ "poll_time=0x%.16x, stat=0x%.16x",
+ poll_time,
+ o_stat->data64 );
+ if( l_err )
+ {
+ break;
+ }
+
+ if( o_stat->op_done )
+ {
+ break;
+ }
+
+ /* want to start out incrementing by small numbers then get bigger
+ to avoid a really tight loop in an error case so we'll increase
+ the wait each time through */
+ sleep( ECCB_POLL_INCR_NS*(++loop) );
+ poll_time += ECCB_POLL_INCR_NS * loop;
+ } while ( poll_time < ECCB_POLL_TIME_NS );
+
+ /* Check for hw errors or timeout if no previous logs */
+ if( (l_err == NO_ERROR) &&
+ ((o_stat->data64 & ECCB_STAT_REG_ERROR_MASK)
+ || (!o_stat->op_done)) )
+ {
+ TRACFCOMP( "LpcDD::pollComplete> LPC error or timeout: addr=0x%.8X, status=0x%.8X%.8X",
+ i_ctrl->address, (uint32_t)(o_stat->data64>>32), (uint32_t)o_stat->data64 );
+ l_err = -1;
+ break;
+ }
+ } while(0);
+
+ return l_err;
+}
+
+
+/*========================================================*/
+
+errorHndl_t lpc_read( LpcTransType i_type,
+ uint32_t i_addr,
+ uint8_t* o_data,
+ size_t i_size )
+{
+ errorHndl_t l_err = NO_ERROR;
+ uint32_t l_addr = 0;
+
+ do {
+ if( o_data == NULL )
+ {
+ TRACFCOMP( "o_data is NULL!" );
+ l_err = -2;
+ break;
+ }
+
+ /* Generate the full absolute LPC address */
+ l_addr = checkAddr( i_type, i_addr );
+
+ /* Execute command. */
+ ControlReg_t eccb_cmd;
+ eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT;
+ eccb_cmd.data_len = i_size;
+ eccb_cmd.read_op = 1;
+ eccb_cmd.addr_len = sizeof(l_addr);
+ eccb_cmd.address = l_addr;
+ xscom_write( ECCB_CTL_REG, eccb_cmd.data64 );
+
+ /* Poll for completion */
+ StatusReg_t eccb_stat;
+ l_err = pollComplete( &eccb_cmd, &eccb_stat );
+ if( l_err ) { break; }
+
+ /* Copy data out to caller's buffer. */
+ if( i_size <= sizeof(uint32_t) )
+ {
+ uint32_t tmpbuf = eccb_stat.read_data;
+ memcpy( o_data, &tmpbuf, i_size );
+ }
+ else
+ {
+ TRACFCOMP( "readLPC> Unsupported buffer size : %d", i_size );
+ l_err = -1;
+ break;
+ }
+
+ } while(0);
+
+ LPC_TRACFCOMP( "readLPC> %08X[%d] = %08X", l_addr, i_size, *reinterpret_cast<uint32_t*>( o_data ) >> (8 * (4 - i_size)) );
+
+ return l_err;
+}
+
+errorHndl_t lpc_write( LpcTransType i_type,
+ uint32_t i_addr,
+ uint8_t* i_data,
+ size_t i_size )
+{
+ errorHndl_t l_err = NO_ERROR;
+ uint32_t l_addr = 0;
+
+ do {
+ /* Generate the full absolute LPC address */
+ l_addr = checkAddr( i_type, i_addr );
+
+ uint64_t eccb_data = 0;
+ /* Left-justify user data into data register. */
+ switch ( i_size )
+ {
+ case 1:
+ eccb_data = (uint64_t)
+ (*(const uint8_t*)(i_data)) << 56;
+ break;
+ case 2:
+ eccb_data = (uint64_t)
+ (*(const uint16_t*)( i_data ) ) << 48;
+ break;
+ case 4:
+ eccb_data = (uint64_t)
+ (*(const uint32_t*)( i_data ) ) << 32;
+ break;
+ default:
+ TRACFCOMP( "writeLPC> Unsupported buffer size : %d", i_size );
+ break;
+ }
+
+ /* Write data out */
+ TRACZCOMP("ECCB_DATA_REG=%.8X%.8X",(uint32_t)(eccb_data>>32),(uint32_t)eccb_data);
+ xscom_write( ECCB_DATA_REG, eccb_data );
+
+ /* Execute command. */
+ ControlReg_t eccb_cmd;
+ eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT;
+ eccb_cmd.data_len = i_size;
+ eccb_cmd.read_op = 0;
+ eccb_cmd.addr_len = sizeof(l_addr);
+ eccb_cmd.address = l_addr;
+ xscom_write( ECCB_CTL_REG, eccb_cmd.data64 );
+ TRACZCOMP("ECCB_CTL_REG=%.8X%.8X",(uint32_t)(eccb_cmd.data64>>32),(uint32_t)eccb_cmd.data64);
+
+ /* Poll for completion */
+ StatusReg_t eccb_stat;
+ l_err = pollComplete( &eccb_cmd, &eccb_stat );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ return l_err;
+}
diff --git a/src/occ/firdata/lpc.h b/src/occ/firdata/lpc.h
new file mode 100644
index 0000000..11290cc
--- /dev/null
+++ b/src/occ/firdata/lpc.h
@@ -0,0 +1,51 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/lpc.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef _LPC_H
+#define _LPC_H
+
+#include <native.h>
+#include <errl.h>
+
+/**
+ * @enum LPC::TransType
+ * @brief LPC Transaction Types
+ */
+typedef enum {
+ LPC_TRANS_IO = 1, /* LPC IO Space */
+ LPC_TRANS_FW = 2, /* LPC Firmware Space */
+} LpcTransType;
+
+errorHndl_t lpc_read( LpcTransType i_type,
+ uint32_t i_addr,
+ uint8_t* o_data,
+ size_t i_size );
+
+errorHndl_t lpc_write( LpcTransType i_type,
+ uint32_t i_addr,
+ uint8_t* i_data,
+ size_t i_size );
+
+#endif
diff --git a/src/occ/firdata/native.c b/src/occ/firdata/native.c
new file mode 100644
index 0000000..d31868f
--- /dev/null
+++ b/src/occ/firdata/native.c
@@ -0,0 +1,68 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/native.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <native.h>
+#include <scom.h>
+#include <trac.h>
+
+void sleep( SsxInterval i_nanoseconds )
+{
+ ssx_sleep(SSX_NANOSECONDS(i_nanoseconds));
+}
+
+int TRACE_XSCOM=0;
+
+uint64_t xscom_read( uint32_t i_address )
+{
+ uint64_t l_data = 0;
+ int l_rc = 0;
+
+ l_rc = getscom_ffdc(i_address,
+ &l_data,
+ NULL);
+ if (l_rc)
+ {
+ TRAC_ERR("SCOM error in xscom_read wrapper, rc=%d", l_rc);
+ }
+
+ if(TRACE_XSCOM){TRACFCOMP("xscom_read (%.8X)=%.8X%.8X", i_address, (uint32_t)(l_data>>32), (uint32_t)l_data);}
+ return l_data;
+}
+
+void xscom_write( uint32_t i_address, uint64_t i_data )
+{
+ int l_rc = 0;
+
+ l_rc = putscom_ffdc(i_address,
+ i_data,
+ NULL);
+
+ if (l_rc)
+ {
+ TRAC_ERR("SCOM error in xscom_write wrapper, rc=%d", l_rc);
+ }
+ if(TRACE_XSCOM){TRACFCOMP("xscom_write(%.8X)=%.8X%.8X", i_address, (uint32_t)(i_data>>32), (uint32_t)i_data);}
+}
+
diff --git a/src/occ/firdata/native.h b/src/occ/firdata/native.h
new file mode 100644
index 0000000..ad722dd
--- /dev/null
+++ b/src/occ/firdata/native.h
@@ -0,0 +1,99 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/native.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/* Native functions provided by OCC code */
+#ifndef _NATIVE_H
+#define _NATIVE_H
+
+#include <common_types.h>
+#include <trac.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "ssx.h"
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef NO_TRAC_STRINGS
+
+#ifdef FIRD_DEBUG
+#define TRACDCOMP(frmt,args...) DBG_PRINT(frmt,##args)
+#else
+#define TRACDCOMP(frmt,args...)
+#endif // FIRD_DEBUG
+
+#define TRACFCOMP(frmt,args...) TRACE(g_trac_inf,INFO_MRK frmt,##args)
+
+#else // NO_TRAC_STRINGS
+
+#define TRACDCOMP(frmt,args...)
+#define TRACFCOMP(frmt,args...)
+
+#endif // NO_TRAC_STRINGS
+
+typedef uint32_t errorHndl_t;
+
+#define ENTER_MRK
+#define NO_ERROR 0
+
+/* Return a number >= input that is aligned up to the next 4-byte boundary */
+#define ALIGN_4(u) (((u) + 0x3ull) & ~0x3ull)
+
+#define NS_PER_SEC (1000000000ull)
+
+#undef be64toh
+#undef htobe64
+#define be64toh(x) (x)
+#define htobe64(x) (x)
+
+#define KILOBYTE (1024ul) /**< 1 KB */
+#define MEGABYTE (1024 * 1024ul) /**< 1 MB */
+#define GIGABYTE (MEGABYTE * 1024ul) /**< 1 GB */
+#define TERABYTE (GIGABYTE * 1024ul) /**< 1 TB */
+
+#define PAGESIZE (4*KILOBYTE) /**< 4 KB */
+#define PAGE_SIZE PAGESIZE
+
+#undef SUCCESS
+#define SUCCESS 0
+
+#undef FAIL
+#define FAIL -1
+
+/*================================================ */
+
+/* XSCOM Read */
+uint64_t xscom_read( uint32_t i_address );
+
+/* XSCOM Write */
+void xscom_write( uint32_t i_address, uint64_t i_data );
+
+/* Sleep */
+void sleep( SsxInterval i_nanoseconds );
+
+
+#endif
diff --git a/src/occ/firdata/nor_micron.c b/src/occ/firdata/nor_micron.c
new file mode 100644
index 0000000..3d0329a
--- /dev/null
+++ b/src/occ/firdata/nor_micron.c
@@ -0,0 +1,73 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/nor_micron.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include "norflash.h"
+#include "sfc_ast2400.h"
+#include <native.h>
+
+
+
+
+/**
+ * @brief Check flag status bit on Micron NOR chips
+ * Some versions of Micron parts require the Flag
+ * Status register be read after a write or erase operation,
+ * otherwise all future operations won't work..
+ */
+errorHndl_t micronFlagStatus( Sfc_t* i_sfc )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( g_trac_pnor, "micronFlagStatus>" ); */
+
+ do {
+ /*Read Micron 'flag status' register */
+ uint8_t flagstat = 0;
+ l_err = sendSpiCmd( i_sfc,
+ SPI_MICRON_FLAG_STAT,
+ NO_ADDRESS,
+ 0, NULL,
+ sizeof(flagstat), &flagstat );
+ if(l_err) { break; }
+
+ /*TRACDCOMP(g_trac_pnor, */
+ /* "micronFlagStatus> (0x%.2X)", */
+ /* flagstat); */
+
+ /* check for ready and no errors */
+ /* bit 0 = ready, bit 2=erase fail, bit 3=Program (Write) failure */
+ if( (flagstat & 0xB0) != 0x80)
+ {
+ /*TRACFCOMP(g_trac_pnor, "micronFlagStatus> Error or timeout from Micron Flag Status Register (0x%.2X)", flagstat); */
+ l_err = -1;
+ break;
+ }
+
+
+ }while(0);
+
+ return l_err;
+
+}
+
diff --git a/src/occ/firdata/norflash.h b/src/occ/firdata/norflash.h
new file mode 100644
index 0000000..d41c878
--- /dev/null
+++ b/src/occ/firdata/norflash.h
@@ -0,0 +1,154 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/norflash.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __PNOR_NORFLASH_H
+#define __PNOR_NORFLASH_H
+
+#include <native.h>
+#include <sfc_ast2400.h>
+
+/** @file norflash.H
+ * @brief Contains constants related to specific types of
+ * of NOR flash chips
+ */
+
+/**
+ * @brief Supported NOR Chip IDs
+ */
+enum NorChipIDs
+{
+ UNKNOWN_NOR_ID = 0x12345600, /**< Initial value before read */
+
+ MICRON_MFG_ID = 0x20000000, /**< Micron Mfg ID */
+ MICRON_NOR_ID = 0x20ba2000, /**< Micron NOR */
+
+ MACRONIX_MFG_ID = 0xC2000000, /**< Macronix Mfg ID */
+ MACRONIX32_NOR_ID = 0xC2201A00, /**< Macronix NOR MXxxL51235F */
+ MACRONIX64_NOR_ID = 0xC2201900, /**< Macronix NOR MXxxL25635F */
+
+ /* Note: Simics currently models Micron NOR */
+ VPO_NOR_ID = 0x20201800, /**< VPO NOR chip ID */
+ FAKE_NOR_ID = 0xBADBAD00, /**< ID used during fake pnor */
+
+ ID_MASK = 0xFFFFFF00, /**< Only look at 3 bytes */
+ MFGID_MASK = 0xFF000000, /**< Manufacturer ID is the first byte */
+};
+
+/**
+ * @brief SPI Config Info
+ * OP Codes and other MISC info for configuring SFC
+ */
+typedef enum
+{
+ SPI_NO_OPCODE = 0x00, /**< Undefined value */
+
+ /*
+ * Micron Flash Commands
+ */
+ SPI_MICRON_FLAG_STAT = 0x70, /**< Check write/erase complete */
+ SPI_MICRON_CLRFLAG_STAT = 0x50, /**< Clear write/erase Status reg */
+
+ /*
+ * Macronix Flash Commands
+ */
+ SPI_MACRONIX_EN4B = 0xB7, /**< Enable Macronix 4-Byte addressing */
+
+ /* SPI protocol commands */
+ SPI_JEDEC_WRITE_STATUS = 0x01, /*WRSR */
+ SPI_JEDEC_PAGE_PROGRAM = 0x02, /*PP */
+ SPI_JEDEC_READ = 0x03, /*READ */
+ SPI_JEDEC_WRITE_DISABLE = 0x04, /*WRDI */
+ SPI_JEDEC_READ_STATUS = 0x05, /*RDSR */
+ SPI_JEDEC_WRITE_ENABLE = 0x06, /*WREN */
+ SPI_JEDEC_FAST_READ = 0x0B, /*FAST_READ */
+ SPI_JEDEC_SECTOR_ERASE = 0x20, /*SE */
+ SPI_JEDEC_READ_SFDP = 0x5A, /*RDSFDP */
+ SPI_JEDEC_CHIPID = 0x9F, /*RDID */
+ SPI_JEDEC_BLOCK_ERASE = 0xD8, /*BE */
+
+} SpiConfigInfo;
+
+/**
+ * @brief General Constants related to flash
+ */
+enum
+{
+ PAGE_PROGRAM_BYTES = 256, /***< 256 bytes per PP command */
+};
+
+
+/**
+ * Common format of Status Register
+ */
+typedef union
+{
+ uint8_t data8;
+ struct
+ {
+ uint8_t writeProtect : 1; /*0 */
+ uint8_t rsvd : 5; /*1:5 */
+ uint8_t writeEnable : 1; /*6 */
+ uint8_t writeInProgress : 1; /*7 */
+ };
+} NorStatusReg_t;
+
+/**
+ * Flags used to trigger Hardware workarounds
+ */
+enum
+{
+ /* No workarounds present */
+ HWWK_NO_WORKAROUNDS = 0x00000000,
+
+ /* Must perform 'read flag status' commands after */
+ /* any write or erase */
+ HWWK_MICRON_WRT_ERASE = 0x00000001,
+
+ /* Must do a read of a low flash address before issuing read */
+ /* commands that return more than 1 word of data */
+ HWWK_MICRON_EXT_READ = 0x00000002,
+};
+
+
+/*
+ * Vendor-specific interfaces
+ */
+
+/**
+ * @brief Check flag status bit on Micron NOR chips
+ * The current version of Micron parts require the Flag
+ * Status register be read after a read or erase operation,
+ * otherwise all future operations won't work..
+ *
+ * @parm i_sfc SFC driver to operate on
+ *
+ * @return Error from operation
+ */
+errorHndl_t micronFlagStatus( Sfc_t* i_sfc );
+
+
+
+
+#endif
diff --git a/src/occ/firdata/pnorData_common.h b/src/occ/firdata/pnorData_common.h
new file mode 100644
index 0000000..5ef10a1
--- /dev/null
+++ b/src/occ/firdata/pnorData_common.h
@@ -0,0 +1,164 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/pnorData.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __pnorData_common_h
+#define __pnorData_common_h
+
+/** NOTE: This file is common between OCC and Hosboot. Any change to this file
+ * must be mirrored to both repositories. */
+
+#include <firDataConst_common.h>
+
+/** This file is used to define the format of the register data captured by the
+ * OCC and stored in PNOR. The data will be stored in the following format:
+ *
+ * - PNOR_Data_t struct - This has all of the information characterizing how
+ * many targets that have register data.
+ * - For each target with register data, the following format will be used:
+ * - PNOR_Trgt_t struct - Contains the target type, position, and how many
+ * registers are in the register list.
+ * - A list of all regular registers (PNOR_Reg_t).
+ * - A list of all indirect-SCOM registers (PNOR_IdReg_t).
+ *
+ * The PNOR has limited data space. So the following rules will apply:
+ * - Any registers with the value of zero will not be captured.
+ * - Registers with SCOM errors will not be captured, however, the number
+ * of SCOM errors detected should be stored in each PNOR_Trgt_t struct.
+ * - If the value of a FIR (or ID FIR) is zero, do not capture the
+ * associated ACT0 and ACT1 registers. Note that the associated MASK and
+ * WOF registers are still needed.
+ * - Each target type may have associated global registers. If none exist,
+ * simply capture all registers for that type. However, if they do exist
+ * and the values of ALL the global registers are zero, skip capturing
+ * the associated targets using the following rules:
+ * - For a PROC, skip this PROC and all associated EXs, and MCSs.
+ * - For an EX, skip this EX.
+ * - For an MCS, skip this MCS.
+ * - For a MEMB, skip this MEMB and all associated MBAs.
+ * - For an MBA, skip this MBA.
+ * - If for some reason we run out of space in the PNOR, do not SCOM any
+ * more registers, set the 'full' bit in the PNOR_Data_t struct, and
+ * write all data successfully captured to PNOR.
+ */
+
+typedef enum
+{
+ PNOR_FIR1 = 0x46495231, /*/< FIR data version 1 ("FIR1" in ascii) */
+
+} PNOR_Version_t;
+
+/** PNOR data header information. */
+typedef struct __attribute__((packed))
+{
+ uint32_t header; /*/< Magic number to indicate valid data and version */
+
+ uint32_t trgts : 8; /*/< Number of targets with register data */
+ uint32_t full : 1; /*/< 1 if PNOR data is full and data may be missing */
+ uint32_t reserved : 23;
+
+} PNOR_Data_t;
+
+/** @return An initialized PNOR_Data_t struct. */
+static inline PNOR_Data_t PNOR_getData()
+{
+ PNOR_Data_t d;
+ d.header = PNOR_FIR1;
+ d.trgts = 0;
+ d.full = 0;
+ d.reserved = 0;
+
+ return d;
+};
+
+/** These values will match the corresponding bit fields in PNOR_Trgt_t. */
+typedef enum RegLimits
+{
+ PNOR_Trgt_MAX_REGS_PER_TRGT = 511, /* Currently expect 266 on the PROC */
+ PNOR_Trgt_MAX_ID_REGS_PER_TRGT = 15, /* Currently expect 9 on the MBA */
+ PNOR_Trgt_MAX_SCOM_ERRORS = 511, /* Should be plenty */
+
+} PNOR_Trgt_RegLimits_t;
+
+/** Information for each target with SCOM data. */
+typedef struct __attribute__((packed))
+{
+ uint32_t type : 3; /*/< Target type. See enum TrgtType_t */
+ uint32_t procPos : 3; /*/< The processor position (0-7) */
+ uint32_t unitPos : 4; /*/< Unit position relative to the processor (0-15) */
+ uint32_t regs : 9; /*/< Number of normal registers */
+ uint32_t idRegs : 4; /*/< Number of indirect-SCOM registers */
+ uint32_t scomErrs : 9; /*/< Number of SCOM errors detected */
+
+} PNOR_Trgt_t;
+
+/** @param i_type Target type. See enum TrgtType_t.
+ * @param i_procPos The processor position.
+ * @param i_procUnitPos Unit position relative to the processor.
+ * @return An initialized PNOR_Data_t struct.
+ */
+static inline PNOR_Trgt_t PNOR_getTrgt( uint32_t i_type, uint32_t i_procPos,
+ uint32_t i_procUnitPos )
+{
+ PNOR_Trgt_t t;
+ t.type = i_type;
+ t.procPos = i_procPos;
+ t.unitPos = i_procUnitPos;
+ t.regs = 0;
+ t.idRegs = 0;
+ t.scomErrs = 0;
+
+ return t;
+};
+
+/** Information for a normal register. */
+typedef struct __attribute__((packed))
+{
+ uint32_t addr; /*/< 32-bit address */
+ uint64_t val; /*/< 64-bit value */
+
+} PNOR_Reg_t;
+
+/** Information for an indirect-SCOM register. */
+typedef struct __attribute__((packed))
+{
+ uint64_t addr; /*/< 64-bit address */
+ uint32_t val; /*/< 32-bit value */
+
+} PNOR_IdReg_t;
+
+/** @return An initialized PNOR_IdReg_t struct. */
+inline
+PNOR_IdReg_t PNOR_getIdReg()
+{
+ PNOR_IdReg_t r = {
+ .addr = 0,
+ .val = 0,
+ };
+
+ return r;
+};
+
+#endif /* __pnorData_common_h */
+
diff --git a/src/occ/firdata/pnor_util.c b/src/occ/firdata/pnor_util.c
new file mode 100644
index 0000000..bf32480
--- /dev/null
+++ b/src/occ/firdata/pnor_util.c
@@ -0,0 +1,236 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/pnor_util.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/* Interfaces to write into PNOR */
+
+#include <native.h>
+#include <sfc_ast2400.h>
+#include <ecc.h>
+#include <pnor_util.h>
+#include <norflash.h>
+
+/*================================================================= */
+/* The offset of the next byte to write */
+uint32_t g_next_byte = 0xFFFFFFFF;
+/* Size of the FIRDATA section of PNOR */
+uint32_t g_pnor_size = 0;
+/* Global SFC object */
+Sfc_t g_sfc;
+/* Cache to queue up PNOR writes */
+uint8_t g_write_cache[PAGE_PROGRAM_BYTES];
+/* Current position of data inside write cache */
+size_t g_write_cache_index = 0;
+
+/**
+ * @brief Write 8 bytes of data into PNOR starting
+ */
+int32_t pnor_write_8B( uint64_t i_data )
+{
+ int32_t rc = SUCCESS;
+
+ if ( (g_next_byte == 0xFFFFFFFF) || /* initialized data */
+ ((g_next_byte + g_pnor_size) < (g_next_byte + 9)) ) /* make sure there is room */
+ {
+ TRACFCOMP("pnor_write_8B> g_next_byte=%.8X, g_pnor_size=%.8X",g_next_byte,g_pnor_size);
+ /* must have been some error in the prep */
+ return FAIL;
+ }
+
+ /* Create 9-byte ECC-ified version */
+ uint8_t data9[9];
+ injectECC( (uint8_t*)(&i_data), 8, data9 );
+
+ /* Copy data into the write cache until we queue up
+ a big chunk of data to write. This is more efficient
+ and avoids handling the write boundary of the PP
+ command internally. */
+ size_t cpsz = 9;
+ if( (g_write_cache_index + cpsz) > PAGE_PROGRAM_BYTES )
+ {
+ cpsz = PAGE_PROGRAM_BYTES - g_write_cache_index;
+ }
+ memcpy( &(g_write_cache[g_write_cache_index]), data9, cpsz );
+ g_write_cache_index += cpsz;
+
+ /* Write a complete chunk into the flash */
+ if( g_write_cache_index == PAGE_PROGRAM_BYTES )
+ {
+ errorHndl_t tmp = writeFlash( &g_sfc,
+ g_next_byte,
+ PAGE_PROGRAM_BYTES,
+ g_write_cache );
+ if ( NO_ERROR != tmp )
+ {
+ TRACFCOMP("pnor_write_8B> writeFlash failed");
+ /* hit an error, stop any more writes from happening */
+ g_next_byte = 0xFFFFFFFF;
+ g_pnor_size = 0;
+ return FAIL;
+ }
+ g_next_byte += PAGE_PROGRAM_BYTES;
+ memset( g_write_cache, 0xFF, PAGE_PROGRAM_BYTES );
+ g_write_cache_index = 0;
+
+ /* Handle the overflow */
+ if( (9 - cpsz) > 0 )
+ {
+ memcpy( &(g_write_cache[0]), &(data9[cpsz]), 9 - cpsz );
+ g_write_cache_index = 9 - cpsz;
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * @brief Perform any necessary operations to prepare
+ * the PNOR hw/code for writing
+ */
+errorHndl_t pnor_prep( HOMER_PnorInfo_t* i_pnorInfo )
+{
+ errorHndl_t l_err = NO_ERROR;
+
+ g_sfc.iv_mmioOffset = i_pnorInfo->mmioOffset;
+ g_sfc.iv_flashWorkarounds = i_pnorInfo->norWorkarounds;
+
+ /* Figure out where to start */
+ TRACFCOMP("FIRDATA is at %.8X..%.8X", i_pnorInfo->pnorOffset, i_pnorInfo->pnorOffset+i_pnorInfo->pnorSize );
+ g_next_byte = i_pnorInfo->pnorOffset;
+ g_pnor_size = i_pnorInfo->pnorSize;
+ memset( g_write_cache, 0xFF, PAGE_PROGRAM_BYTES );
+
+ /* Can we rely on skiboot leaving things in a good state? */
+ l_err = hwInit(&g_sfc);
+ if( l_err )
+ {
+ TRACFCOMP("hwInit failed");
+ /* hit an error, stop any writes from happening */
+ g_next_byte = 0xFFFFFFFF;
+ g_pnor_size = 0;
+ }
+
+ /* Future Improvement
+ Enable write mode once at the beginning to avoid extra
+ reg operations turning it on and off
+ l_err = enableWriteMode(g_sfc);
+ if( l_err )
+ {
+ g_next_byte = 0xFFFFFFFF;
+ g_pnor_size = 0;
+ }
+ */
+
+ return l_err;
+}
+
+/*------------------------------------------------------------------------------ */
+
+int32_t PNOR_writeFirData( HOMER_PnorInfo_t i_pnorInfo,
+ uint8_t * i_buf, uint32_t i_bufSize )
+{
+ int32_t rc = SUCCESS;
+ TRACFCOMP(">>PNOR_writeFirData");
+
+ do
+ {
+ /* Initialize the PNOR data. */
+ errorHndl_t l_err = pnor_prep( &i_pnorInfo );
+ if( l_err )
+ {
+ TRACFCOMP("pnor_prep failed");
+ rc = FAIL;
+ break; /*nothing more to do here*/
+ }
+
+ uint32_t idx = 0;
+
+ /* Erase the section. */
+ for( idx = i_pnorInfo.pnorOffset;
+ idx < (i_pnorInfo.pnorOffset+i_pnorInfo.pnorSize);
+ idx += 4096 )
+ {
+ l_err = eraseFlash(&g_sfc,idx);
+ if( l_err )
+ {
+ TRACFCOMP("eraseFlash failed");
+ rc = FAIL;
+ break; /*nothing more to do here*/
+ }
+ }
+
+ uint64_t dataChunk = 0;
+ size_t sz_dataChunk = sizeof(uint64_t);
+
+ /* Add PNOR data 8 bytes at a time. */
+ for ( idx = 0; idx < i_bufSize; idx += sz_dataChunk )
+ {
+ memcpy( &dataChunk, &i_buf[idx], sz_dataChunk );
+
+ rc = pnor_write_8B( dataChunk );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( "pnor_write_8B() failed during FIR write" );
+ break;
+ }
+ }
+ if ( SUCCESS != rc ) break;
+
+ /* Add any extra bytes if they exist at the end of the buffer. */
+ if ( idx != i_bufSize )
+ {
+ uint32_t extraBytes = idx - i_bufSize;
+
+ dataChunk = 0;
+ memcpy( &dataChunk, &i_buf[idx], extraBytes );
+
+ rc = pnor_write_8B( dataChunk );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( "pnor_write_8B() failed during blank fill" );
+ break;
+ }
+ }
+
+ /* Fill the rest of the page with good ECC */
+ for ( idx = i_bufSize;
+ idx < i_pnorInfo.pnorSize;
+ idx += sz_dataChunk )
+ {
+ dataChunk = 0xFFFFFFFFFFFFFFFFull;
+ rc = pnor_write_8B( dataChunk );
+ if ( SUCCESS != rc )
+ {
+ TRACFCOMP( "pnor_write_8B() failed during ECC fill" );
+ break;
+ }
+ }
+
+ } while (0);
+
+ TRACFCOMP("<<PNOR_writeFirData");
+ return rc;
+}
+
diff --git a/src/occ/firdata/pnor_util.h b/src/occ/firdata/pnor_util.h
new file mode 100644
index 0000000..d8b5518
--- /dev/null
+++ b/src/occ/firdata/pnor_util.h
@@ -0,0 +1,41 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/pnor_util.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __pnor_util_h
+#define __pnor_util_h
+
+#include <homerData_common.h>
+
+/**
+ * @brief Writes a buffer containing the FIR data to PNOR (adding ECC).
+ * @param i_pnorInfo Information regarding PNOR location, size, etc.
+ * @param i_buf Data buffer (no ECC included).
+ * @param i_bufSize Size of the data buffer.
+ * @return Non-SUCCESS, if the write fails. SUCCESS, otherwise.
+ */
+int32_t PNOR_writeFirData( HOMER_PnorInfo_t i_pnorInfo,
+ uint8_t * i_buf, uint32_t i_bufSize );
+
+#endif /* __pnor_util_h */
diff --git a/src/occ/firdata/scom_trgt.c b/src/occ/firdata/scom_trgt.c
new file mode 100644
index 0000000..ec38122
--- /dev/null
+++ b/src/occ/firdata/scom_trgt.c
@@ -0,0 +1,135 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scoms.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include <native.h>
+#include <scom_trgt.h>
+#include <scom_util.h>
+
+/*------------------------------------------------------------------------------ */
+
+SCOM_Trgt_t SCOM_Trgt_getTrgt( TrgtType_t i_type, uint8_t i_procPos,
+ uint8_t i_procUnitPos, uint32_t i_fsiBaseAddr,
+ bool i_isMaster )
+{
+ SCOM_Trgt_t trgt = {
+ .type = i_type,
+ .procPos = i_procPos,
+ .procUnitPos = i_procUnitPos,
+ .isMaster = i_isMaster,
+ .fsiBaseAddr = i_fsiBaseAddr,
+ };
+
+ if ( PROC == trgt.type ) trgt.procUnitPos = 0;
+
+ if ( MEMB == trgt.type || MBA == trgt.type ) trgt.isMaster = false;
+
+ return trgt;
+}
+
+/*------------------------------------------------------------------------------ */
+
+uint8_t SCOM_Trgt_getChipPos( SCOM_Trgt_t i_trgt )
+{
+ uint32_t p = 0;
+
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case EX:
+ case MCS:
+ p = i_trgt.procPos;
+ break;
+
+ case MEMB:
+ p = (i_trgt.procPos * MAX_MEMB_PER_PROC) + i_trgt.procUnitPos;
+ break;
+
+ case MBA:
+ p = (i_trgt.procPos * MAX_MEMB_PER_PROC) +
+ (i_trgt.procUnitPos / MAX_MBA_PER_MEMB);
+ break;
+
+ default: ;
+ }
+
+ return p;
+}
+
+/*------------------------------------------------------------------------------ */
+
+uint8_t SCOM_Trgt_getChipUnitPos( SCOM_Trgt_t i_trgt )
+{
+ uint32_t u = 0;
+
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case MEMB: u = 0; break;
+
+ case EX:
+ case MCS: u = i_trgt.procUnitPos; break;
+
+ case MBA: u = i_trgt.procUnitPos % MAX_MBA_PER_MEMB; break;
+
+ default: ;
+ }
+
+ return u;
+}
+
+/*------------------------------------------------------------------------------ */
+
+SCOM_Trgt_t SCOM_Trgt_getParentChip( SCOM_Trgt_t i_trgt )
+{
+ TrgtType_t t = MAX_TRGTS;
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case EX:
+ case MCS: t = PROC; break;
+
+ case MEMB:
+ case MBA: t = MEMB; break;
+
+ default: ;
+ }
+
+ uint8_t u = 0;
+ switch ( i_trgt.type )
+ {
+ case PROC:
+ case EX:
+ case MCS:
+ case MEMB: u = i_trgt.procUnitPos; break;
+
+ case MBA: u = i_trgt.procUnitPos / MAX_MBA_PER_MEMB; break;
+
+ default: ;
+ }
+
+ return SCOM_Trgt_getTrgt( t, i_trgt.procPos, u, i_trgt.fsiBaseAddr,
+ i_trgt.isMaster );
+}
+
diff --git a/src/occ/firdata/scom_trgt.h b/src/occ/firdata/scom_trgt.h
new file mode 100644
index 0000000..4ffe8b5
--- /dev/null
+++ b/src/occ/firdata/scom_trgt.h
@@ -0,0 +1,89 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scom.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __scom_trgt_h
+#define __scom_trgt_h
+
+#include <firDataConst_common.h>
+#include <native.h>
+
+typedef struct
+{
+ /** See enum TrgtType_t. NOTE: This value is not consistant with Hostboot
+ * target types. */
+ TrgtType_t type;
+
+ /** Absolute position of the connected PROC within the node. This value
+ * should be consistant with the Hostboot target positions. */
+ uint8_t procPos;
+
+ /** Unit position relative to the connected PROC. This value should be
+ * consistant with the Hostboot target positions. */
+ uint8_t procUnitPos;
+
+ /** Indicates this target is, or is connected to, the master processor. */
+ bool isMaster;
+
+ /** This target's FSI base address. */
+ uint32_t fsiBaseAddr;
+
+} SCOM_Trgt_t;
+
+/** @param i_type See enum Type.
+ * @param i_procPos Absolute position within the node of the connected
+ * PROC target.
+ * @param i_procUnitPos Unit position relative to the connected PROC. Will be
+ * explicitly set to 0 for PROC targets.
+ * @param i_fsiBaseAddr For EX and MCS, the FSI base address for the
+ * connected PROC. For MEMB and MBA, the FSI base
+ * address for the connected MEMB.
+ * @param i_isMaster True, if this target is, or is connected to, the
+ * master processor. False, otherwise. Will be explicitly
+ * set to false for MEMB and MBA targets.
+ * @return A SCOM_Trgt_t struct.
+ */
+SCOM_Trgt_t SCOM_Trgt_getTrgt( TrgtType_t i_type, uint8_t i_procPos,
+ uint8_t i_procUnitPos, uint32_t i_fsiBaseAddr,
+ bool i_isMaster );
+
+/** @param i_trgt The SCOM target.
+ * @return This target's absolute position of the parent chip (PROC or
+ * MEMB) within the node.
+ */
+uint8_t SCOM_Trgt_getChipPos( SCOM_Trgt_t i_trgt );
+
+/** @param i_trgt The SCOM target.
+ * @return This target's unit position relative to the parent chip. Only
+ * valid for EX, MCS, and MBA units. Will return 0 for PROC and
+ * MEMB chips.
+ */
+uint8_t SCOM_Trgt_getChipUnitPos( SCOM_Trgt_t i_trgt );
+
+/** @param i_trgt The SCOM target.
+ * @return A target for the containing parent chip (PROC or MEMB).
+ */
+SCOM_Trgt_t SCOM_Trgt_getParentChip( SCOM_Trgt_t i_trgt );
+
+#endif /* __scom_trgt_h */
diff --git a/src/occ/firdata/scom_util.c b/src/occ/firdata/scom_util.c
new file mode 100644
index 0000000..4762b3f
--- /dev/null
+++ b/src/occ/firdata/scom_util.c
@@ -0,0 +1,386 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scom_util.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/* Support for SCOM operations */
+#include <scom_util.h>
+#include <fsi.h>
+#include <native.h>
+
+enum {
+ /*FSI addresses are byte offsets, so need to multiply by 4
+ since each register is 4 bytes long.
+ prefix with 0x10xx for FSI2PIB engine offset */
+ DATA0_REG = 0x1000, /* SCOM Data Register 0 (0x00) */
+ DATA1_REG = 0x1004, /* SCOM Data Register 1 (0x01) */
+ COMMAND_REG = 0x1008, /* SCOM Command Register (0x02) */
+ ENGINE_RESET_REG = 0x1018, /* Engine Reset Register (0x06) */
+ STATUS_REG = 0x101C, /* STATUS Register (0x07) */
+ PIB_RESET_REG = 0x101C, /* PIB Reset Register (0x07) */
+
+ PIB_ABORT_BIT = 0x00100000, /* 12= PIB Abort */
+ PIB_ERROR_BITS = 0x00007000, /* 17:19= PCB/PIB Errors */
+};
+
+/**
+ * @brief Indirect SCOM Status
+ */
+typedef union
+{
+ uint64_t data64;
+ struct
+ {
+ uint64_t :12; /*0:11*/
+ uint64_t addr:20; /*12:31*/
+ uint64_t done:1; /*32*/
+ uint64_t piberr:3; /*33:35*/
+ uint64_t userstat:4; /*36:39*/
+ uint64_t :8; /*40:47*/
+ uint64_t data:16; /*48:63*/
+ };
+} IndirectScom_t;
+
+enum {
+ MCS_MASK = 0xFFFFFFFF7FFFFF80,
+ MCS_BASEADDR = 0x0000000002011800,
+ MCS_DMI_BASEADDR = 0x0000000002011A00,
+ IND_MCS_BASEADDR = 0x8000006002011A00,
+ IND_MCS_DMI_BASEADDR = 0x8000006002011A3F,
+ MBA_MASK = 0xFFFFFFFF7FFFFC00,
+ MBA_BASEADDR = 0x0000000003010400,
+ TCM_MBA_BASEADDR = 0x0000000003010800,
+ IND_MBA_BASEADDR = 0x800000000301143f,
+};
+
+
+
+/**
+ * @brief Translate a relative unit address to a real physical address
+ * @param[in] Chip/unit to scom
+ * @param[in] Address to scom, unit0's address for unit scoms
+ * @return Physical address
+ */
+uint32_t translate_scom( SCOM_Trgt_t i_target,
+ uint32_t i_address )
+{
+ TrgtType_t l_type = i_target.type;
+ uint32_t l_addr = i_address;
+
+ /* No translation needed for non-unit scoms */
+ if( (l_type == PROC) || (l_type == MEMB) )
+ {
+ l_addr = i_address;
+ }
+ else /* it is a Unit */
+ {
+ uint8_t l_num = SCOM_Trgt_getChipUnitPos(i_target);
+
+ if( l_type == EX )
+ {
+ /*first byte is 0x10, second nibble of that byte is the EX number */
+ l_addr |= (l_num << 24);
+ }
+ else if( l_type == MCS )
+ {
+ /*Non-DMI address */
+ if( (i_address & MCS_MASK) == MCS_BASEADDR )
+ {
+ /* MC0 MCS0 = 0x02011800 MCS-0 range 0 */
+ /* MC0 MCS1 = 0x02011880 MCS-1 range 0 + remainder */
+ /* MC1 MCS0 = 0x02011900 MCS-2 range 1 */
+ /* MC1 MCS0 = 0x02011980 MCS-3 range 1 + remainder */
+ /* MC2 MCS0 = 0x02011C00 MCS-4 range 2 */
+ /* MC2 MCS1 = 0x02011C80 MCS-5 range 2 + remainder */
+ /* MC3 MCS0 = 0x02011D00 MCS-6 range 3 */
+ /* MC3 MCS1 = 0x02011D80 MCS-7 range 3 + remainder */
+ if( (l_num / 2) == 1) /*range 1 */
+ {
+ l_addr += 0x100;
+ }
+ else if( (l_num / 2) == 2) /*range 2 */
+ {
+ l_addr += 0x400;
+ }
+ else if( (l_num / 2) == 3) /*range 3 */
+ {
+ l_addr += 0x500;
+ }
+
+ /* Add 0x80 for the odd numbers */
+ if( l_num % 2)
+ {
+ l_addr += 0x80;
+ }
+ }
+ else if( (i_address & MCS_MASK) == MCS_DMI_BASEADDR )
+ {
+ /* 0x00000000_02011A00 MCS 0-3 # MCS/DMI0 Direct SCOM */
+ /* 0x00000000_02011E00 MCS 4-7 # MCS/DMI4 Direct SCOM */
+ if( l_num > 3 )
+ {
+ l_addr |= 0x400; /* A00->E00 */
+ }
+ }
+ else if( (i_address & MCS_MASK) == IND_MCS_DMI_BASEADDR )
+ {
+ /* 0x80000060_02011A3F MCS 0 # DMI0 Indirect SCOM RX3 */
+ /* 0x80000040_02011A3F MCS 1 # DMI1 Indirect SCOM RX2 */
+ /* 0x80000000_02011A3F MCS 2 # DMI3 Indirect SCOM RX0 */
+ /* 0x80000020_02011A3F MCS 3 # DMI2 Indirect SCOM RX1 */
+ /* */
+ /* 0x80000060_02011E3F MCS 4 # DMI4 Indirect SCOM RX3 */
+ /* 0x80000040_02011E3F MCS 5 # DMI5 Indirect SCOM RX2 */
+ /* 0x80000000_02011E3F MCS 6 # DMI7 Indirect SCOM RX0 */
+ /* 0x80000020_02011E3F MCS 7 # DMI6 Indirect SCOM RX1 */
+ /* */
+ /* 0x80000460_02011A3F MCS 0 # DMI0 Indirect SCOM TX3 */
+ /* 0x80000440_02011A3F MCS 1 # DMI1 Indirect SCOM TX2 */
+ /* 0x80000400_02011A3F MCS 2 # DMI3 Indirect SCOM TX0 */
+ /* 0x80000420_02011A3F MCS 3 # DMI2 Indirect SCOM TX1 */
+ /* */
+ /* 0x80000460_02011E3F MCS 4 # DMI4 Indirect SCOM TX3 */
+ /* 0x80000440_02011E3F MCS 5 # DMI5 Indirect SCOM TX2 */
+ /* 0x80000400_02011E3F MCS 6 # DMI7 Indirect SCOM TX0 */
+ /* 0x80000420_02011E3F MCS 7 # DMI6 Indirect SCOM TX1 */
+
+ /* zero out the instance bits */
+ l_addr &= 0xFFFFFF9FFFFFFFFF;
+ switch( l_num )
+ {
+ case(0):
+ case(4):
+ l_addr |= 0x0000006000000000;
+ break;
+ case(1):
+ case(5):
+ l_addr |= 0x0000004000000000;
+ break;
+ case(2):
+ case(6):
+ /*nothing to do */
+ break;
+ case(3):
+ case(7):
+ l_addr |= 0x0000002000000000;
+ break;
+ default:
+ l_addr = SCOMFAIL;
+ }
+ if( l_num > 3 )
+ {
+ l_addr |= 0x400; /* A00->E00 */
+ }
+ }
+ }
+ else if( l_type == MBA )
+ {
+ if( (i_address & MBA_MASK) == MBA_BASEADDR )
+ {
+ /* 0x00000000_03010400 MBA 0 # MBA01 */
+ /* 0x00000000_03010C00 MBA 1 # MBA23 */
+ if( l_num == 1 )
+ {
+ l_addr |= 0x00000800;
+ }
+ }
+ else if( (i_address & MBA_MASK) == TCM_MBA_BASEADDR )
+ {
+ /* 0x00000000_03010880 MBA 0 # Trace for MBA01 */
+ /* 0x00000000_030110C0 MBA 1 # Trace for MBA23 */
+ l_addr += (l_num * 0x840);
+ }
+ else if( (i_address & MBA_MASK) == IND_MBA_BASEADDR )
+ {
+ /* 0x00000000_03011400 MBA 0 # DPHY01 (indirect addressing) */
+ /* 0x00000000_03011800 MBA 1 # DPHY23 (indirect addressing) */
+ /* 0x80000000_0301143f MBA 0 # DPHY01 (indirect addressing) */
+ /* 0x80000000_0301183f MBA 1 # DPHY23 (indirect addressing) */
+ /* 0x80000000_0701143f MBA 0 # DPHY01 (indirect addressing) */
+ /* 0x80000000_0701183f MBA 1 # DPHY23 (indirect addressing) */
+ if( l_num == 1 )
+ {
+ /* 030114zz->030118zz */
+ l_addr &= 0xFFFFFFFFFFFFFBFF;
+ l_addr |= 0x0000000000000800;
+ }
+ }
+ }
+ else
+ {
+ l_addr = SCOMFAIL;
+ }
+ }
+
+ return l_addr;
+}
+
+
+/**
+ * @brief Perform a getscom operation with no address translation
+ */
+uint64_t getscomraw( SCOM_Trgt_t i_chip,
+ uint32_t i_address )
+{
+ /* Scoms to the master chip are done via xscom */
+ if( i_chip.isMaster )
+ {
+ return xscom_read(i_address);
+ }
+
+ /*1) send the command to do the scom read */
+ putfsi( i_chip, COMMAND_REG, i_address );
+ /*2) check status next -- TODO */
+ /*3) read the two data regs */
+ uint64_t scomdata = SCOMFAIL;
+ uint32_t data = getfsi( i_chip, DATA0_REG );
+ if( data == FSIFAIL )
+ {
+ return SCOMFAIL;
+ }
+ scomdata = data;
+ scomdata <<= 32;
+ data = getfsi( i_chip, DATA1_REG );
+ if( data == FSIFAIL )
+ {
+ return SCOMFAIL;
+ }
+ scomdata |= (uint64_t)data;
+
+ return scomdata;
+}
+
+
+/**
+ * @brief Perform a scom operation with no address translation
+ */
+void putscomraw( SCOM_Trgt_t i_chip,
+ uint32_t i_address,
+ uint64_t i_data )
+{
+ /* Scoms to the master chip are done via xscom */
+ if( i_chip.isMaster )
+ {
+ xscom_write( i_address, i_data );
+ return;
+ }
+
+ /*1) write the two data regs */
+ putfsi( i_chip, DATA0_REG, i_data >> 32 );
+ putfsi( i_chip, DATA1_REG, (uint32_t)i_data );
+
+ /*2) send the command to do the scom write */
+ putfsi( i_chip, COMMAND_REG, i_address | 0x80000000 );
+
+ /*3) check status next -- TODO */
+}
+
+
+/**
+ * @brief Execute standard getscom and return result
+ */
+int32_t SCOM_getScom( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint64_t * o_val )
+{
+ int32_t rc = SUCCESS;
+
+ /* Translate the input args into physical addr/chip */
+ uint32_t real_addr = translate_scom( i_trgt, i_addr );
+ SCOM_Trgt_t chip_targ = SCOM_Trgt_getParentChip(i_trgt);
+
+ /* Do the scom */
+ *o_val = getscomraw( chip_targ, real_addr );
+ if ( SCOMFAIL == *o_val ) { rc = FAIL; }
+
+ return rc;
+}
+
+/**
+ * @brief Execute indirect getscom and return result
+ */
+int32_t SCOM_getIdScom( SCOM_Trgt_t i_trgt, uint64_t i_addr, uint32_t * o_val )
+{
+ int32_t rc = SUCCESS;
+
+ /* First translate the address */
+ uint64_t trans_addr = translate_scom( i_trgt, i_addr );
+ SCOM_Trgt_t chip_targ = SCOM_Trgt_getParentChip(i_trgt);
+
+ /* An indirect scom is performed by putting the top of the */
+ /* 64-bit address into the first data word of the scom */
+
+ /* zero out the indirect address from the buffer.. */
+ /* bit 0-31 - indirect area.. */
+ /* bit 32 - always 0 */
+ /* bit 33-47 - bcast/chipletID/port */
+ /* bit 48-63 - local addr */
+ uint32_t phys_addr = trans_addr & 0x000000007FFFFFFF;
+
+ /* To do a read we need to do a write first */
+
+ /* start with the 20bit indirect address */
+ uint64_t data_buffer = trans_addr & 0x001FFFFF00000000;
+ /* turn the read bit on. */
+ data_buffer |= 0x8000000000000000;
+
+ /* perform write before the read with the new */
+ putscomraw( i_trgt, phys_addr, data_buffer );
+
+ // Loop on read until we see done, error, or we timeout
+ IndirectScom_t scomout;
+ uint64_t elapsed_indScom_time_ns = 0;
+ do
+ {
+ /* Now perform the op requested using the passed in */
+ /* IO_Buffer to pass the read data back to caller. */
+ scomout.data64 = getscomraw( chip_targ, phys_addr );
+ if( scomout.data64 == SCOMFAIL )
+ {
+ break;
+ }
+
+ /* jump out on done or error */
+ if( scomout.done || scomout.piberr )
+ {
+ break;
+ }
+
+ sleep( 10000 ); /*sleep for 10,000 ns */
+ elapsed_indScom_time_ns += 10000;
+
+ } while( elapsed_indScom_time_ns <= 100000 ); /*wait for .1ms */
+
+ if( (scomout.data64 == SCOMFAIL)
+ || (scomout.piberr)
+ || !(scomout.done) )
+ {
+ *o_val = SCOMFAIL;
+ }
+ else
+ {
+ *o_val = scomout.data;
+ }
+
+ if ( SCOMFAIL == *o_val ) { rc = FAIL; }
+
+ return rc;
+}
diff --git a/src/occ/firdata/scom_util.h b/src/occ/firdata/scom_util.h
new file mode 100644
index 0000000..039ac64
--- /dev/null
+++ b/src/occ/firdata/scom_util.h
@@ -0,0 +1,49 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/scom_util.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/* Interfaces to read SCOM registers */
+
+/*#include <stdint.h> */
+#include <native.h>
+#include <scom_trgt.h>
+
+#define SCOMFAIL 0xDEADBEEF
+
+/** @brief Performs a hardware scom on a regular register.
+ * @param i_trgt The SCOM target.
+ * @param i_addr 32-bit SCOM address.
+ * @param o_val 64-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t SCOM_getScom( SCOM_Trgt_t i_trgt, uint32_t i_addr, uint64_t * o_val );
+
+/** @brief Performs a hardware scom on an indirect-SCOM register.
+ * @param i_trgt The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param o_val 32-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t SCOM_getIdScom( SCOM_Trgt_t i_trgt, uint64_t i_addr, uint32_t * o_val );
+
diff --git a/src/occ/firdata/sfc_ast2400.c b/src/occ/firdata/sfc_ast2400.c
new file mode 100644
index 0000000..fbdb0b3
--- /dev/null
+++ b/src/occ/firdata/sfc_ast2400.c
@@ -0,0 +1,728 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/sfc_ast2400.C $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/*****************************************************************************/
+/* I n c l u d e s */
+/*****************************************************************************/
+#include <native.h>
+#include <norflash.h>
+/*#include <string.h> */
+#include <sfc_ast2400.h>
+#include <lpc.h>
+extern int TRACE_LPC;
+int TRACE_SFC = 0;
+
+/*****************************************************************************/
+/* C o n s t a n t s */
+/*****************************************************************************/
+
+
+
+
+/*****************************************************************************/
+/* G l o b a l s */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* M e t h o d s */
+/*****************************************************************************/
+
+/**
+ * @brief Read data from the flash
+ */
+errorHndl_t readFlash( Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ /*TRACDCOMP( ENTER_MRK"readFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size ); */
+ errorHndl_t l_err = 0;
+
+ do{
+ uint32_t* word_ptr = (uint32_t*)(o_data);
+ uint32_t word_size = (ALIGN_4(i_size))/4;
+ uint32_t words_read = 0;
+ for( words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ /*Read directly from MMIO space */
+ uint32_t lpc_addr = i_sfc->iv_mmioOffset | (i_addr + words_read*4);
+ size_t reg_size = sizeof(uint32_t);
+ l_err = lpc_read( LPC_TRANS_FW,
+ lpc_addr,
+ (uint8_t*)&(word_ptr[words_read]),
+ reg_size );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+ }while(0);
+
+ /*TRACDCOMP( EXIT_MRK"readFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+
+/**
+ * @brief Write data into flash
+ */
+errorHndl_t writeFlash( Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACFCOMP( "writeFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size );
+ errorHndl_t l_err = 0;
+ size_t l_bytes_left = i_size;
+ size_t l_bytes_to_write = 0;
+ uint32_t l_addr_to_write = i_addr;
+ uint8_t* l_dataptr = (uint8_t*)(i_data);
+
+ do {
+ /* Enable write mode */
+ l_err = enableWriteMode(i_sfc);
+ if( l_err ) { break; }
+
+ /* Page Program (PP) command only supports 256 bytes at a time */
+ if( l_bytes_left <= PAGE_PROGRAM_BYTES )
+ {
+ l_bytes_to_write = l_bytes_left;
+ l_bytes_left = 0;
+ }
+ else
+ {
+ l_bytes_to_write = PAGE_PROGRAM_BYTES;
+ l_bytes_left -= PAGE_PROGRAM_BYTES;
+ }
+
+ /* Send in the Page Program command with the data to write */
+ uint8_t opcode = SPI_JEDEC_PAGE_PROGRAM;
+ l_err = sendSpiCmd( i_sfc, opcode, l_addr_to_write,
+ l_bytes_to_write,
+ l_dataptr,
+ 0, NULL );
+ if( l_err ) { break; }
+
+ /* Move to the next chunk */
+ l_addr_to_write += l_bytes_to_write;
+ l_dataptr += l_bytes_to_write;
+
+ /* Wait for idle */
+ l_err = pollOpComplete(i_sfc);
+ if( l_err ) { break; }
+
+ /*check for special Micron Flag Status reg */
+ if(i_sfc->iv_flashWorkarounds & HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = micronFlagStatus(i_sfc);
+ if(l_err) { break; }
+ }
+
+ } while(l_bytes_left);
+
+ /*TRACDCOMP( EXIT_MRK"writeFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Erase a block of flash
+ */
+errorHndl_t eraseFlash( Sfc_t* i_sfc,
+ uint32_t i_addr )
+{
+ TRACFCOMP(">>eraseFlash> Block 0x%.8X", i_addr );
+ errorHndl_t l_err = 0;
+
+ do {
+ // Enable write mode
+ l_err = enableWriteMode(i_sfc);
+ if( l_err ) { break; }
+
+ // Send erase command
+ uint8_t opcode = SPI_JEDEC_SECTOR_ERASE;
+ l_err = sendSpiCmd( i_sfc, opcode, i_addr, 0, 0, 0, NULL );
+ if( l_err ) { break; }
+
+ // Wait for idle
+ l_err = pollOpComplete(i_sfc);
+ if( l_err ) { break; }
+
+ //check for special Micron Flag Status reg
+ if(i_sfc->iv_flashWorkarounds & HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = micronFlagStatus(i_sfc);
+ if(l_err) { break; }
+ }
+ } while(0);
+
+ return l_err;
+}
+
+
+/**
+ * @brief Initialize and configure the SFC hardware
+ */
+errorHndl_t hwInit( Sfc_t* i_sfc )
+{
+ TRACFCOMP( ENTER_MRK"hwInit>" );
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /*** Initialize the LPC2AHB logic */
+
+ /* Send SuperIO password - send A5 twice */
+ uint8_t data = 0xA5;
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &data, reg_size );
+ if( l_err ) { break; }
+
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &data, reg_size );
+ if( l_err ) { break; }
+
+
+ /* Select logical device D (iLPC2AHB) */
+ l_err = writeRegSIO( i_sfc, 0x07, 0x0D );
+ if( l_err ) { break; }
+
+
+ /* Enable iLPC->AHB */
+ l_err = writeRegSIO( i_sfc, 0x30, 0x01 );
+ if( l_err ) { break; }
+
+
+ /*** Setup the SPI Controller */
+
+ /* Enable writing to the controller */
+ SpiControlReg04_t ctlreg;
+ l_err = readRegSPIC( i_sfc, CTLREG_04, &ctlreg.data32 );
+ if( l_err ) { break; }
+ TRACFCOMP("dc99> First read of CTLREG_04=%.8X", ctlreg.data32);
+ ctlreg.cmdMode = 2;/*0b10; //10:Normal Write (CMD + Address + Write data) */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ SpiConfigReg00_t confreg;
+ l_err = readRegSPIC( i_sfc, CONFREG_00, &confreg.data32 );
+ if( l_err ) { break; }
+ confreg.inactiveX2mode = 1; /*Enable CE# Inactive pulse width X2 mode */
+ confreg.enableWrite = 1; /*Enable flash memory write */
+ l_err = writeRegSPIC( i_sfc, CONFREG_00, confreg.data32 );
+ if( l_err ) { break; }
+
+
+ /*
+ * Setup control reg and for our use, switching
+ * to 1-bit mode, clearing user mode if set, etc...
+ *
+ * Also configure SPI clock to something safe
+ * like HCLK/8 (24Mhz)
+ */
+ ctlreg.fourByteMode = 1;
+ ctlreg.ioMode = 0;/*0b00; //single bit or controlled by bit[3] */
+ ctlreg.pulseWidth = 0x0; /*0000: 16T (1T = 1 HCLK clock) */
+ ctlreg.cmdData = 0x00;
+ ctlreg.spiClkFreq = 0x4; /*HCLK/8 */
+ ctlreg.dummyCycleRead1 = 0; /*no dummy cycles */
+ ctlreg.dummyCycleRead2 = 0;/*0b00; //no dummy cycles */
+ ctlreg.cmdMode = 0;/*0b00; //00:Normal Read (03h + Address + Read data) */
+ i_sfc->iv_ctlRegDefault = ctlreg; /* Default setup is regular read mode */
+
+ /* Configure for read */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ /* Setup flash-specific settings here, if there are any */
+
+ } while(0);
+
+ TRACFCOMP( "hwInit> err=%.8X", l_err );
+ return l_err;
+}
+
+/**
+ * @brief Send a SPI command
+ */
+errorHndl_t sendSpiCmd( Sfc_t* i_sfc,
+ uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData )
+{
+ errorHndl_t l_err = NO_ERROR;
+ size_t opsize = 0;
+ if(TRACE_SFC){
+ TRACFCOMP( ENTER_MRK"sendSpiCmd> i_opCode=%.2X, i_address=%.8X, i_writeCnt=0x%X, i_writeData=%p", i_opCode, i_address, i_writeCnt, i_writeData );
+ TRACFCOMP( " , i_readCnt=0x%X, o_readData=%p", i_readCnt, o_readData );
+ }
+
+ do {
+ /*Do a read of flash address zero to workaround */
+ /* a micron bug with extended reads */
+ if( (HWWK_MICRON_EXT_READ & i_sfc->iv_flashWorkarounds)
+ && (i_readCnt > 4) )
+ {
+ uint32_t ignored = 0;
+ l_err = readFlash( i_sfc, 0, 1, &ignored );
+ if(l_err) { break; }
+ }
+
+ /* Put controller into command mode (instead of read mode) */
+ l_err = commandMode( i_sfc, true );
+ if( l_err ) { break; }
+
+ /* Write command to the beginning of the flash space */
+ opsize = sizeof(i_opCode);
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ &i_opCode,
+ opsize ); /*just send opcode */
+ if( l_err ) { break; }
+
+ /* Send address if there is one */
+ if( i_address != NO_ADDRESS )
+ {
+ /* Write address to the beginning of the flash space */
+ opsize = sizeof(i_address);
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ (uint8_t*)&i_address,
+ opsize ); /*only supporting 4-byte addresses */
+ if( l_err ) { break; }
+ }
+
+ /* Send in the rest of the write data */
+ if( i_writeCnt && i_writeData )
+ {
+ size_t bytes_left = i_writeCnt;
+ uint8_t* curptr = (uint8_t*)(i_writeData);
+ while( bytes_left )
+ {
+ /* Write the last partial word if there is one */
+ if( bytes_left < 4 )
+ {
+ opsize = bytes_left;
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ break;
+ }
+
+ /* Write data into the beginning of the flash space, */
+ /* in command mode this doesn't write the flash */
+ /* but instead is a pass-through to the area we */
+ /* really want to write */
+ opsize = sizeof(uint32_t);
+ l_err = lpc_write( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ if( l_err ) { break; }
+
+ curptr += 4;
+ bytes_left -= 4;
+ }
+ if( l_err ) { break; }
+ }
+
+ /* Read back the results */
+ if( i_readCnt && o_readData )
+ {
+ size_t bytes_left = i_readCnt;
+ uint8_t* curptr = o_readData;
+ while( bytes_left )
+ {
+ /* Grab the last partial word if there is one */
+ if( bytes_left < 4 )
+ {
+ opsize = bytes_left;
+ l_err = lpc_read( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ break;
+ }
+
+ /* Read data from the beginning of the flash space, */
+ /* in command mode this doesn't read the flash */
+ /* but instead is a pass-through to the data we */
+ /* really want */
+ opsize = sizeof(uint32_t);
+ l_err = lpc_read( LPC_TRANS_FW, i_sfc->iv_mmioOffset,
+ curptr,
+ opsize );
+ if( l_err ) { break; }
+
+ curptr += 4;
+ bytes_left -= 4;
+ }
+ if( l_err ) { break; }
+ }
+ } while(0);
+
+
+ /* No matter what, put the logic back into read mode */
+ int tmp_err = commandMode( i_sfc, false );
+ if( tmp_err )
+ {
+ if( !l_err )
+ {
+ l_err = tmp_err;
+ }
+ }
+
+ /*TRACDCOMP( EXIT_MRK"sendSpiCmd> o_readData=%.2X, err=%.8X", o_readData == NULL ? 0 : o_readData[0], ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Enter/exit command mode
+ */
+errorHndl_t commandMode( Sfc_t* i_sfc,
+ bool i_enter )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"commandMode(%d)", i_enter ); */
+
+ /*
+ * There is only a limited addressable window within LPC space. The AST
+ * has its control register space at too far of a distance from the read
+ * space for them both to fit in a single window. Rather than moving the
+ * window around we will use the iLPC2AHB backdoor inside the SuperIO
+ * controller to do both register accesses and to write into the flash.
+ *
+ * High level flow to write into control space:
+ * Stop active control (SPI04 Control Reg)
+ * Enable command mode (SPI04 Control Reg)
+ * Write actual command into flash base addr (0x0E000000)
+ */
+
+ do {
+ SpiControlReg04_t ctlreg = i_sfc->iv_ctlRegDefault;
+
+ /* Switch to user mode, CE# dropped */
+ ctlreg.stopActiveCtl = 1;
+ ctlreg.cmdMode = 3;/*0b11; //User Mode (Read/Write Data) */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ if( i_enter ) /*ast_sf_start_cmd */
+ {
+ /* user mode, CE# active */
+ ctlreg.stopActiveCtl = 0;
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+ }
+ else /*ast_sf_end_cmd */
+ {
+ /* Switch back to read mode */
+ l_err = writeRegSPIC( i_sfc, CTLREG_04, i_sfc->iv_ctlRegDefault.data32 );
+ if( l_err ) { break; }
+ }
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"commandMode> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Enable write mode
+ */
+errorHndl_t enableWriteMode( Sfc_t* i_sfc )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"enableWriteMode>" ); */
+
+ /* Some flashes need it to be hammered */
+ NorStatusReg_t status;
+// status.data8 = 0x55;
+ size_t i = 0;
+ for( i = 0; i < 10; i++ )
+ {
+ /* Send the command to enable writes */
+ uint8_t opcode = SPI_JEDEC_WRITE_ENABLE;
+ l_err = sendSpiCmd( i_sfc, opcode, NO_ADDRESS, 0, NULL, 0, NULL );
+ if( l_err ) { break; }
+
+ /* Check to see if it worked */
+ opcode = SPI_JEDEC_READ_STATUS;
+ l_err = sendSpiCmd( i_sfc, opcode, NO_ADDRESS, 0, NULL, 1, &(status.data8) );
+ if( l_err ) { break; }
+ TRACDCOMP( "SPI_JEDEC_READ_STATUS=%.2X", status.data8 );
+
+ if( status.writeEnable )
+ {
+ break;
+ }
+ }
+
+ if( !l_err && !status.writeEnable )
+ {
+ TRACFCOMP( "Could not enable writes" );
+ l_err = -1;
+ }
+
+ /*TRACDCOMP( EXIT_MRK"enableWriteMode> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Write a single byte into the SIO
+ */
+errorHndl_t writeRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t i_data )
+{ /*lpc_sio_outb */
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACFCOMP( "writeRegSIO> i_regAddr=0x%.2X, i_data=0x%.2X", i_regAddr, i_data );*/
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /* AST2400 integrates a Super I/O module with */
+ /* LPC protocol (I/O cycle 0x2E/0x2F) */
+
+ /* Write out the register address */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &i_regAddr,
+ reg_size );
+ if( l_err ) { break; }
+
+ /* Write out the register data */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_DATA_2F,
+ &i_data,
+ reg_size );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"writeRegSIO> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Read a single byte from the SIO
+ */
+errorHndl_t readRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t* o_data )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"readRegSIO> i_regAddr=0x%.2X", i_regAddr ); */
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ /* AST2400 integrates a Super I/O module with */
+ /* LPC protocol (I/O cycle 0x2E/0x2F) */
+
+ /* Write out the register address */
+ l_err = lpc_write( LPC_TRANS_IO, SIO_ADDR_2E,
+ &i_regAddr,
+ reg_size );
+ if( l_err ) { break; }
+
+ /* Read in the register data */
+ l_err = lpc_read( LPC_TRANS_IO, SIO_DATA_2F,
+ o_data,
+ reg_size );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"readRegSIO> o_data=0x%.2X, err-%.8X", *o_data, ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Prepare the iLPC2AHB address regs
+ */
+errorHndl_t setupAddrLPC2AHB( Sfc_t* i_sfc,
+ uint32_t i_addr )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /*TRACDCOMP( ENTER_MRK"setupAddrLPC2AHB> i_addr=0x%X", i_addr ); */
+
+ do {
+ /* Select logical device D (iLPC2AHB) */
+ l_err = writeRegSIO( i_sfc, 0x07, 0x0D );
+ if( l_err ) { break; }
+
+ /* Push 4 address bytes into SIO regs 0xF0-0xF3 */
+ size_t i;
+ for( i=sizeof(i_addr); i>0; i-- )
+ {
+ l_err = writeRegSIO( i_sfc, 0xF3-(i-1), /*F0,F1,F2,F3 */
+ (uint8_t)(i_addr >> ((i-1)*8)) );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ /* Configure 4 byte length */
+ l_err = writeRegSIO( i_sfc, 0xF8, 0x02 );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"setupAddrLPC2AHB> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Write SPI Controller Register
+ */
+errorHndl_t writeRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t i_data )
+{
+ errorHndl_t l_err = NO_ERROR;
+ //TRACFCOMP( "writeRegSPIC> i_reg=0x%.2X, i_data=0x%.8X", i_reg, i_data );
+
+ do {
+ /* Compute the full LPC address */
+ uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB;
+
+ /* Setup the logic for the write */
+ l_err = setupAddrLPC2AHB( i_sfc, lpc_addr );
+ if( l_err ) { break; }
+
+ /* Push 4 data bytes into SIO regs 0xF4-0xF7 */
+ uint8_t* ptr8 = (uint8_t*)(&i_data);
+ size_t i;
+ for( i=0; i<sizeof(i_data); i++ )
+ {
+ l_err = writeRegSIO( i_sfc, 0xF4+i, /*F4,F5,F6,F7 */
+ ptr8[i] );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ /* Trigger the write operation by writing the magic 0xCF value */
+ l_err = writeRegSIO( i_sfc, 0xFE, 0xCF );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"writeRegSPIC> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Read SPI Controller Register
+ */
+errorHndl_t readRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t* o_data )
+{
+ //TRACFCOMP( "readRegSPIC> i_reg=0x%.2X", i_reg );
+ errorHndl_t l_err = NO_ERROR;
+
+ do {
+ /* Compute the full LPC address */
+ uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB;
+
+ /* Setup the logic for the write */
+ l_err = setupAddrLPC2AHB( i_sfc, lpc_addr );
+ if( l_err ) { break; }
+
+ /* Trigger the write operation by reading the magic register */
+ uint8_t ignored = 0;
+ l_err = readRegSIO( i_sfc, 0xFE, &ignored );
+ if( l_err ) { break; }
+
+ /* Read 4 data bytes into SIO regs 0xF4-0xF7 */
+ uint8_t* ptr8 = (uint8_t*)(o_data);
+ size_t i;
+ for( i=0; i<sizeof(*o_data); i++ )
+ {
+ l_err = readRegSIO( i_sfc, 0xF4+i, /*F4,F5,F6,F7 */
+ &(ptr8[i]) );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ } while(0);
+
+ /*TRACDCOMP( EXIT_MRK"readRegSPIC> o_data=0x%.8X, l_err=%.8X", *o_data, ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
+/**
+ * @brief Poll for completion of SPI operation
+ */
+errorHndl_t pollOpComplete( Sfc_t* i_sfc )
+{
+ errorHndl_t l_err = NO_ERROR;
+ /* TRACDCOMP( "pollOpComplete>" ); */
+int trace_lpc=TRACE_LPC; TRACE_LPC=0;
+int trace_sfc=TRACE_SFC; TRACE_SFC=0;
+
+ do {
+ /* Send RDSR command until write-in-progress clears */
+ NorStatusReg_t status;
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ while( poll_time < MAX_WRITE_TIME_NS )
+ {
+ uint8_t opcode = SPI_JEDEC_READ_STATUS;
+ l_err = sendSpiCmd( i_sfc, opcode,
+ NO_ADDRESS,
+ 0, NULL,
+ 1, &(status.data8) );
+ if( l_err ) { break; }
+
+ /* check if any op is still going */
+ if( !status.writeInProgress )
+ {
+ break;
+ }
+
+ /* want to start out incrementing by small numbers then get bigger
+ to avoid a really tight loop in an error case so we'll increase
+ the wait each time through */
+ ++loop;
+ sleep( 100*loop );
+ poll_time += 100*loop;
+ }
+ if( l_err ) { break; }
+
+ /*TRACDCOMP(g_trac_pnor,"pollOpComplete> command took %d ns", poll_time); */
+
+ /* No status regs to check so just look for timeout */
+ if( status.writeInProgress )
+ {
+ TRACFCOMP( "pollOpComplete> Timeout during write or erase" );
+ l_err = -1;
+ break;
+ }
+ } while(0);
+
+TRACE_LPC=trace_lpc;
+TRACE_SFC=trace_sfc;
+ /*TRACDCOMP( EXIT_MRK"pollOpComplete> err=%.8X", ERRL_GETEID_SAFE(l_err) ); */
+ return l_err;
+}
+
diff --git a/src/occ/firdata/sfc_ast2400.h b/src/occ/firdata/sfc_ast2400.h
new file mode 100644
index 0000000..30a9052
--- /dev/null
+++ b/src/occ/firdata/sfc_ast2400.h
@@ -0,0 +1,298 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/firdata/sfc_ast2400.H $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_SFCAST2400_H
+#define __PNOR_SFCAST2400_H
+
+#include <native.h>
+#include <homerData_common.h>
+
+/** @file sfc_ast2400.H
+ * @brief Provides the logic to access and configure the
+ * AST2400 BMC in order to access the PNOR
+ */
+
+/**
+ * @brief SPI04 Control Register
+ */
+typedef union
+{
+ uint32_t data32;
+ struct
+ { /*Little-endian bit positions*/
+ uint32_t rsvd : 2; /*31:30*/
+ uint32_t ioMode : 2; /*29:28*/
+ uint32_t pulseWidth : 4; /*27:24*/
+ uint32_t cmdData : 8; /*23:16*/
+ uint32_t dummyCycleCmd : 1; /*15*/
+ uint32_t dummyCycleRead1 : 1; /*14*/
+ uint32_t fourByteMode : 1; /*13*/
+ uint32_t disableCmdMerge : 1; /*12*/
+ uint32_t spiClkFreq : 4; /*11:8*/
+ uint32_t dummyCycleRead2 : 2; /*7:6*/
+ uint32_t lsbFirst : 1; /*5*/
+ uint32_t useClkMode3 : 1; /*4*/
+ uint32_t dualInputMode : 1; /*3*/
+ uint32_t stopActiveCtl : 1; /*2*/
+ uint32_t cmdMode : 2; /*1:0*/
+ };
+} SpiControlReg04_t;
+
+
+/**
+ * @brief Structure to hold information about the SFC
+ */
+typedef struct
+{
+ /**
+ * @brief Default value of SPI04 (saves a read)
+ */
+ SpiControlReg04_t iv_ctlRegDefault;
+
+ /**
+ * @brief Hardware workarounds
+ */
+ uint32_t iv_flashWorkarounds;
+
+ /**
+ * @brief LPC address that marks the beginning of flash
+ */
+ uint32_t iv_mmioOffset;
+} Sfc_t;
+
+
+/**
+ * @brief Initialize the SFC Hardware
+ * @param[in] Pointer to Sfc struct
+ *
+ * @return void
+ */
+errorHndl_t hwInit(Sfc_t* i_sfc);
+
+/**
+ * @brief Read data from the PNOR flash
+ *
+ * @param[in] Pointer to Sfc struct
+ * @parm[in] i_addr PNOR flash Address to read
+ * @parm[in] i_size Amount of data to read, in bytes.
+ * @parm[out] o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+errorHndl_t readFlash(Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* o_data);
+
+/**
+ * @brief Write data to the PNOR flash
+ *
+ * @param[in] Pointer to Sfc struct
+ * @parm i_addr PNOR flash Address to write
+ * @parm i_size Amount of data to write, in bytes.
+ * @parm i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeFlash(Sfc_t* i_sfc,
+ uint32_t i_addr,
+ size_t i_size,
+ void* i_data);
+
+/**
+ * @brief Erase a block of flash
+ */
+errorHndl_t eraseFlash( Sfc_t* i_sfc,
+ uint32_t i_addr );
+
+/** @brief Constant for sendSpiCmd parameter */
+static const uint32_t NO_ADDRESS = UINT32_MAX;
+
+
+/**
+ * @brief Send a SPI command
+ *
+ * @param[in] Pointer to Sfc struct
+ * @parm[in] i_opCode: command to send into controller first
+ * @parm[in] i_address: address for those commands that need it
+ * @parm[in] i_writeCnt: number of bytes to write to device
+ * @parm[in] i_writeData: write data buffer
+ * @parm[in] i_readCnt: number of bytes to read from device
+ * @parm[out] o_readData: read data buffer
+ *
+ * @return Error from operation
+ */
+errorHndl_t sendSpiCmd( Sfc_t* i_sfc,
+ uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData );
+
+/**
+ * @brief List of registers in the SPI Controller logic
+ */
+typedef enum
+{
+ CONFREG_00 = 0x00,
+ CTLREG_04 = 0x04,
+ MISCCTLREG_10 = 0x10,
+ READTIMEREG_14 = 0x14
+} SpicReg_t;
+
+/**
+ * @brief Write a SPI Controller register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t i_data );
+
+/**
+ * @brief Write a SPI Controller register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to write
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+errorHndl_t readRegSPIC( Sfc_t* i_sfc,
+ SpicReg_t i_reg,
+ uint32_t* o_data );
+
+/**
+ * @brief Write a single byte into a SIO register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+errorHndl_t writeRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t i_data );
+
+/**
+ * @brief Read a single byte from a SIO register
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_reg: Register to read
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+errorHndl_t readRegSIO( Sfc_t* i_sfc,
+ uint8_t i_regAddr,
+ uint8_t* o_data );
+
+/**
+ * @brief Enable write mode
+ *
+ * @param[in] Pointer to Sfc struct
+ * @return Error from operation
+ */
+errorHndl_t enableWriteMode( Sfc_t* i_sfc );
+
+/**
+ * @brief Enter/exit command mode
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_enter: true=enter cmd mode, false=exit cmd mode
+ *
+ * @return Error from operation
+ */
+errorHndl_t commandMode( Sfc_t* i_sfc,
+ bool i_enter );
+
+/**
+ * @brief Poll for completion of SPI operation
+ *
+ * @param[in] Pointer to Sfc struct
+ * @return Error from operation
+ */
+errorHndl_t pollOpComplete( Sfc_t* i_sfc );
+
+/**
+ * @brief Prepare the iLPC2AHB address regs
+ *
+ * @param[in] Pointer to Sfc struct
+ * @param[in] i_addr: LPC address to access
+ *
+ * @return Error from operation
+ */
+errorHndl_t setupAddrLPC2AHB( Sfc_t* i_sfc,
+ uint32_t i_addr );
+
+
+/**
+ * @brief SPI0 Configuration Register
+ */
+typedef union
+{
+ uint32_t data32;
+ struct
+ { /*Little-endian bit positions*/
+ uint32_t rsvd : 30; /*31:2*/
+ uint32_t inactiveX2mode : 1; /*1*/
+ uint32_t enableWrite : 1; /*0*/
+ };
+} SpiConfigReg00_t;
+
+/** @brief General Constants */
+enum
+{
+ LPC_TOP_OF_FLASH_OFFSET = 0x0FFFFFFF,
+
+ /**< Offset to SPI Controller Register Space */
+ LPC_SFC_CTLR_BASE = 0x1E789000,
+
+ /**< AHB address of SPI Flash controller */
+ SPIC_BASE_ADDR_AHB = 0x1E630000,
+
+ /**< AHB address of flash */
+ FLASH_BASE_ADDR_AHB = 0x30000000,
+
+ /**< AHB address of LPC registers */
+ LPC_CTLR_BASE_ADDR_AHB = 0x1E789000,
+
+ /**< Maximum time to wait for a write/erase */
+ MAX_WRITE_TIME_NS = NS_PER_SEC,
+
+ /**< SuperIO Address Cycle */
+ SIO_ADDR_2E = 0x2E,
+
+ /**< SuperIO Data Cycle */
+ SIO_DATA_2F = 0x2F,
+};
+
+
+#endif
diff --git a/src/occ/homer.c b/src/occ/homer.c
index d7b2a3b..67ada05 100755
--- a/src/occ/homer.c
+++ b/src/occ/homer.c
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -26,6 +26,9 @@
// Description: HOMER specific functions.
#include "ssx.h"
+#include <errl.h>
+#include <occ_service_codes.h>
+#include <occ_common.h>
#include <homer.h>
/*
@@ -49,26 +52,22 @@
*/
homer_rc_t homer_hd_map_read_unmap(const homer_read_var_t i_id,
- uint32_t *o_host_data,
- int *o_ssx_rc)
+ void * const o_host_data,
+ int * const o_ssx_rc)
{
- // Locals
Ppc405MmuMap l_mmuMapHomer = 0;
homer_rc_t l_rc = HOMER_SUCCESS;
occHostConfigDataArea_t *l_hdcfg_data = 0x00000000;
- *o_ssx_rc = SSX_OK;
- // Validate the parms and id
- if (!o_host_data)
+ // Validate the pointers
+ if (!o_host_data || !o_ssx_rc || ((uint32_t)o_host_data % 4))
{
l_rc = HOMER_BAD_PARM;
}
- else if (HOMER_LAST_VAR <= i_id)
- {
- l_rc = HOMER_UNKNOWN_ID;
- }
else
{
+ *o_ssx_rc = SSX_OK;
+
/*
* Map to mainstore at HOMER host data offset. The first parameter is
* the effective address where the data can be accessed once mapped, the
@@ -88,31 +87,79 @@ homer_rc_t homer_hd_map_read_unmap(const homer_read_var_t i_id,
}
else
{
- // Check version, if ok return data requested. We need to support
+ // Check version, if ok handle ID requested. We need to support
// current version as well as older ones
- if (HOMER_HD_VERSION_SUPPORT < l_hdcfg_data->version)
+ if ((HOMER_VERSION_MIN > l_hdcfg_data->version)
+ ||
+ (HOMER_VERSION_MAX < l_hdcfg_data->version))
{
l_rc = HOMER_UNSUPPORTED_HD_VERSION;
}
else
{
- switch (i_id)
+ // Version guaranteed to be within supported range
+
+ // HOMER Version 1 support
+ if (HOMER_VERSION_1 == l_hdcfg_data->version)
+ {
+ switch (i_id)
+ {
+ case HOMER_VERSION:
+ *(uint32_t *)o_host_data = l_hdcfg_data->version;
+ break;
+ case HOMER_NEST_FREQ:
+ *(uint32_t *)o_host_data = l_hdcfg_data->nestFrequency;
+ break;
+ default:
+ l_rc = HOMER_UNKNOWN_ID;
+ break;
+ }
+ }
+ else if (HOMER_VERSION_2 == l_hdcfg_data->version)
{
- case HOMER_VERSION:
- *o_host_data = l_hdcfg_data->version;
- break;
- case HOMER_NEST_FREQ:
- *o_host_data = l_hdcfg_data->nestFrequency;
- break;
- case HOMER_INT_TYPE:
- *o_host_data = l_hdcfg_data->occInterruptType;
- break;
- default:
- // Nothing to do, range checked above
- break;
+ switch (i_id)
+ {
+ case HOMER_VERSION:
+ *(uint32_t *)o_host_data = l_hdcfg_data->version;
+ break;
+ case HOMER_NEST_FREQ:
+ *(uint32_t *)o_host_data = l_hdcfg_data->nestFrequency;
+ break;
+ case HOMER_INT_TYPE:
+ *(uint32_t *)o_host_data = l_hdcfg_data->occInterruptType;
+ break;
+ default:
+ l_rc = HOMER_UNKNOWN_ID;
+ break;
+ }
+ }
+ else if (HOMER_VERSION_3 == l_hdcfg_data->version)
+ {
+ switch (i_id)
+ {
+ case HOMER_VERSION:
+ *(uint32_t *)o_host_data = l_hdcfg_data->version;
+ break;
+ case HOMER_NEST_FREQ:
+ *(uint32_t *)o_host_data = l_hdcfg_data->nestFrequency;
+ break;
+ case HOMER_INT_TYPE:
+ *(uint32_t *)o_host_data = l_hdcfg_data->occInterruptType;
+ break;
+ case HOMER_FIR_MASTER:
+ *(uint32_t *)o_host_data = l_hdcfg_data->firMaster;
+ break;
+ case HOMER_FIR_PARMS:
+ memcpy(o_host_data, &(l_hdcfg_data->firParms[0]), HOMER_FIR_PARM_SIZE);
+ break;
+ default:
+ l_rc = HOMER_UNKNOWN_ID;
+ break;
+ }
}
}
+ // Unmap the HOMER before returning to caller
*o_ssx_rc = ppc405_mmu_unmap(&l_mmuMapHomer);
if ((SSX_OK != *o_ssx_rc) && (HOMER_SUCCESS == l_rc))
{
@@ -125,4 +172,75 @@ homer_rc_t homer_hd_map_read_unmap(const homer_read_var_t i_id,
}
// End of homer_hd_map_read_unmap
+
+/*
+ * Function Specification
+ *
+ * Name: homer_log_access_error
+ *
+ * Description: Utility function to log an error that occurred while accessing
+ * the HOMER.
+ *
+ * End Function Specification
+ */
+void homer_log_access_error(const homer_rc_t i_homer_rc,
+ const int i_ssx_rc,
+ const uint32_t i_usr_data2)
+{
+ // Catch and log the homer error
+ if (HOMER_SUCCESS != i_homer_rc)
+ {
+ // We could potentially have both an internal error dealing with the
+ // homer and an SSX error, for example we could find an unsupported
+ // version number in the homer and then have an ssx error trying to
+ // unmap the homer address space. This check catches all those cases.
+ if (SSX_OK != i_ssx_rc)
+ {
+ /* @
+ * @errortype
+ * @moduleid MAIN_MID
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 HOMER and SSX return codes
+ * @userdata2 Host interrupt type used
+ * @userdata4 ERC_HOMER_MAIN_SSX_ERROR
+ * @devdesc An SSX error occurred mapping the HOMER host data
+ * into the OCC address space. User word 1 contains
+ * both the internal and SSX return codes returned
+ * by the method used to access the HOMER data.
+ */
+ errlHndl_t l_err = createErrl(MAIN_MID, //modId
+ SSX_GENERIC_FAILURE, //reasoncode
+ ERC_HOMER_MAIN_SSX_ERROR, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ (i_homer_rc << 16) | (0xFFFF & (uint32_t)i_ssx_rc), //userdata1
+ i_usr_data2); //userdata2
+ commitErrl(&l_err);
+ }
+ else
+ {
+ /* @
+ * @errortype
+ * @moduleid MAIN_MID
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 HOMER return code
+ * @userdata2 Default host interrupt type used.
+ * @userdata4 ERC_HOMER_MAIN_ACCESS_ERROR
+ * @devdesc Error accessing initialization data
+ */
+ errlHndl_t l_err = createErrl(MAIN_MID, //modId
+ INTERNAL_FAILURE, //reasoncode
+ ERC_HOMER_MAIN_ACCESS_ERROR,//Extended reason code
+ ERRL_SEV_INFORMATIONAL, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ i_homer_rc, //userdata1
+ i_usr_data2); //userdata2
+ commitErrl(&l_err);
+ }
+ }
+}
+// End of homer_log_access_error
+
// End of homer.c
diff --git a/src/occ/homer.h b/src/occ/homer.h
index 4a0036d..b4d94ee 100755
--- a/src/occ/homer.h
+++ b/src/occ/homer.h
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -32,9 +32,17 @@
// Offset into the HOMER of the host data section and the size
#define HOMER_HD_OFFSET 0x00100000
#define HOMER_HD_SZ (128 * 1024)
+#define HOMER_FIR_PARM_SIZE (3 * 1024)
-// Version of HOMER host data currently supported
-#define HOMER_HD_VERSION_SUPPORT 2
+// Version(s) of HOMER host data currently supported
+typedef enum homer_version
+{
+ HOMER_VERSION_MIN = 1,
+ HOMER_VERSION_1 = 1,
+ HOMER_VERSION_2 = 2,
+ HOMER_VERSION_3 = 3,
+ HOMER_VERSION_MAX = 3,
+} homer_version_t;
// ID of host data variables
typedef enum homer_read_var
@@ -42,6 +50,8 @@ typedef enum homer_read_var
HOMER_VERSION,
HOMER_NEST_FREQ,
HOMER_INT_TYPE,
+ HOMER_FIR_MASTER,
+ HOMER_FIR_PARMS,
HOMER_LAST_VAR
} homer_read_var_t;
@@ -63,10 +73,13 @@ struct occHostConfigDataArea
uint32_t version;
uint32_t nestFrequency;
uint32_t occInterruptType;
- uint8_t __reserved[(1024*128)-12];
+ uint32_t firMaster;
+ uint8_t firParms[HOMER_FIR_PARM_SIZE];
+ uint8_t __reserved[HOMER_HD_SZ - (4 * sizeof(uint32_t)) - HOMER_FIR_PARM_SIZE];
}__attribute__ ((__packed__));
typedef struct occHostConfigDataArea occHostConfigDataArea_t;
-homer_rc_t homer_hd_map_read_unmap(const homer_read_var_t, uint32_t *, int *);
+homer_rc_t homer_hd_map_read_unmap(const homer_read_var_t, void * const, int * const);
+void homer_log_access_error(const homer_rc_t, const int, const uint32_t);
#endif // _homer_h
diff --git a/src/occ/incl/common_types.h b/src/occ/incl/common_types.h
index f13f99a..51ea3ed 100755
--- a/src/occ/incl/common_types.h
+++ b/src/occ/incl/common_types.h
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -59,6 +59,9 @@ typedef enum
} BOOLEAN;
#endif
+#define true 1
+#define false 0
+
#ifndef NULL
#define NULL (VOID *) 0
#endif
diff --git a/src/occ/incl/occ_common.h b/src/occ/incl/occ_common.h
index 0c28f89..032683f 100755
--- a/src/occ/incl/occ_common.h
+++ b/src/occ/incl/occ_common.h
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -31,12 +31,11 @@
// From Linker Script
extern void _LINEAR_WR_WINDOW_SECTION_BASE;
-// From Linker Script
extern void _LINEAR_WR_WINDOW_SECTION_SIZE;
-// From Linker Script
extern void _LINEAR_RD_WINDOW_SECTION_BASE;
-// From Linker Script
extern void _LINEAR_RD_WINDOW_SECTION_SIZE;
+extern void _FIR_PARMS_SECTION_BASE;
+extern void _FIR_HEAP_SECTION_BASE;
// Declare aligned data structures for Async access in a noncacheable section
//
@@ -60,6 +59,12 @@ extern void _LINEAR_RD_WINDOW_SECTION_SIZE;
#define GPE_BUFFER(declaration) \
declaration __attribute__ ((__aligned__ (8))) __attribute__ ((section (".noncacheable")))
+#define FIR_HEAP_BUFFER(declaration) \
+ declaration __attribute__ ((section (".firHeap")))
+
+#define FIR_PARMS_BUFFER(declaration) \
+ declaration __attribute__ ((section (".firParms")))
+
#define LINEAR_WINDOW_WR_BUFFER(declaration) \
declaration __attribute__ ((section (".linear_wr")))
@@ -74,6 +79,9 @@ extern void _LINEAR_RD_WINDOW_SECTION_SIZE;
#define LINEAR_WR_WINDOW_SECTION_SIZE ((uint32_t) &_LINEAR_WR_WINDOW_SECTION_SIZE)
#define CMDH_OCC_RESPONSE_BASE_ADDRESS ((uint32_t) &_LINEAR_RD_WINDOW_SECTION_BASE)
#define LINEAR_RD_WINDOW_SECTION_SIZE ((uint32_t) &_LINEAR_RD_WINDOW_SECTION_SIZE)
+#define FIR_PARMS_SECTION_BASE_ADDRESS ((uint32_t) &_FIR_PARMS_SECTION_BASE)
+#define FIR_HEAP_SECTION_BASE_ADDRESS ((uint32_t) &_FIR_HEAP_SECTION_BASE)
+
// Conversion Macro's
@@ -231,6 +239,7 @@ enum
SSX_STARTING = 0x0210,
SSX_INITIALIZED = 0x02ff,
TRACE_INITIALIZED = 0x0310,
+ HOMER_ACCESS_INITS = 0x0318,
INITIALIZING_IRQS = 0x0320,
IRQS_INITIALIZED = 0x032f,
MAIN_THREAD_STARTED = 0x03ff,
diff --git a/src/occ/linkocc.cmd b/src/occ/linkocc.cmd
index 783b414..0deabc5 100755
--- a/src/occ/linkocc.cmd
+++ b/src/occ/linkocc.cmd
@@ -1,27 +1,27 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/occ/linkocc.cmd $
-//
-// OpenPOWER OnChipController Project
-//
-// Contributors Listed Below - COPYRIGHT 2011,2014
-// [+] Google Inc.
-// [+] International Business Machines Corp.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied. See the License for the specific language governing
-// permissions and limitations under the License.
-//
-// IBM_PROLOG_END_TAG
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ/linkocc.cmd $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
// Description
@@ -546,12 +546,32 @@ SECTIONS
__WRITEABLE_DATA_LEN__ = . - __WRITEABLE_DATA_ADDR__ ;
_EX_FREE_SECTION_SIZE = 0 - _EX_FREE_SECTION_BASE;
#else
- _DATA_SECTION_SIZE = _LINEAR_WR_WINDOW_SECTION_BASE - _DATA_SECTION_BASE;
- __WRITEABLE_DATA_LEN__ = _LINEAR_WR_WINDOW_SECTION_BASE - __WRITEABLE_DATA_ADDR__ ;
+ _DATA_SECTION_SIZE = _FIR_HEAP_SECTION_BASE - _DATA_SECTION_BASE;
+ __WRITEABLE_DATA_LEN__ = _FIR_HEAP_SECTION_BASE - __WRITEABLE_DATA_ADDR__ ;
_EX_FREE_SECTION_SIZE = 0;
#endif
- _SSX_FREE_END = _LINEAR_WR_WINDOW_SECTION_BASE - 1;
+ _SSX_FREE_END = _FIR_HEAP_SECTION_BASE - 1;
+
+ ////////////////////////////////
+ // FIR data heap section
+ ////////////////////////////////
+ __CUR_COUNTER__ = .;
+ _FIR_HEAP_SECTION_BASE = 0xffff2000;
+ _FIR_HEAP_SECTION_SIZE = 0x3000;
+ . = _FIR_HEAP_SECTION_BASE;
+ .firHeap . : {*(firHeap) . = ALIGN(1024);} > sram
+ . = __CUR_COUNTER__;
+
+ ////////////////////////////////
+ // FIR data parms section
+ ////////////////////////////////
+ __CUR_COUNTER__ = .;
+ _FIR_PARMS_SECTION_BASE = 0xffff5000;
+ _FIR_PARMS_SECTION_SIZE = 0x1000;
+ . = _FIR_PARMS_SECTION_BASE;
+ .firParms . : {*(firParms) . = ALIGN(1024);} > sram
+ . = __CUR_COUNTER__;
////////////////////////////////
// FSP Command Buffer
diff --git a/src/occ/main.c b/src/occ/main.c
index 6700964..06e9702 100755
--- a/src/occ/main.c
+++ b/src/occ/main.c
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -53,6 +53,7 @@
#include <amec_freq.h>
#include <thrm_thread.h>
#include "scom.h"
+#include <fir_data_collect.h>
extern void __ssx_boot;
extern uint32_t G_occ_phantom_critical_count;
@@ -68,7 +69,6 @@ IMAGE_HEADER (G_mainAppImageHdr,__ssx_boot,MAIN_APP_ID,ID_NUM_INVALID);
SimicsStdio G_simics_stdout;
SimicsStdio G_simics_stderr;
-
// Critical /non Critical Stacks
uint8_t G_noncritical_stack[NONCRITICAL_STACK_SIZE];
uint8_t G_critical_stack[CRITICAL_STACK_SIZE];
@@ -85,8 +85,14 @@ SsxSemaphore G_ffdcSem;
// Timer for posting thermal, health monitor and FFDC semaphore
SsxTimer G_mainThrdTimer;
-// @sb022 Variable holding main thread loop count
+// Variable holding main thread loop count
uint32_t G_mainThreadLoopCounter = 0x0;
+// Global flag indicating FIR collection is required
+bool G_fir_collection_required = FALSE;
+
+extern uint8_t g_trac_inf_buffer[];
+extern uint8_t g_trac_imp_buffer[];
+extern uint8_t g_trac_err_buffer[];
void pmc_hw_error_isr(void *private, SsxIrqId irq, int priority);
@@ -337,7 +343,7 @@ void occ_irq_setup()
if(l_rc)
{
//single error for all error cases, just look at trace to see where it failed.
- /*@
+ /* @
* @moduleid OCC_IRQ_SETUP
* @reasonCode SSX_GENERIC_FAILURE
* @severity ERRL_SEV_UNRECOVERABLE
@@ -703,7 +709,7 @@ void Main_thread_routine(void *private)
TRAC_INFO("Main Thread Started ... " );
- workaround_HW258436(); //gm016
+ workaround_HW258436();
// NOTE: At present, we are not planning to use any config data from
// mainstore. OCC Role will be provided by FSP after FSP communication
@@ -711,7 +717,6 @@ void Main_thread_routine(void *private)
// dcom_initialize_roles. If in future design changes, we will make
// change to use config_data_init at that time.
// Default role initialization and determine OCC/Chip Id
- // @03a get our role
dcom_initialize_roles();
CHECKPOINT(ROLES_INITIALIZED);
@@ -721,16 +726,9 @@ void Main_thread_routine(void *private)
sensor_init_all();
CHECKPOINT(SENSORS_INITIALIZED);
- // SPIVID Initialization
- // Must be done before Pstates
- // @sb001 Removed SPIVID inits
+ // SPIVID Initialization must be done before Pstates
// All SPIVID inits are done by Hostboot, remove this section.
- //#if 0
- // o2s_initialize();
- // spivid_initialize(7);
- //#endif
- //@04a
//Initialize structures for collecting core data.
//It needs to run before RTLoop start as pore initialization needs to be
// done before task to collect core data starts.
@@ -739,10 +737,9 @@ void Main_thread_routine(void *private)
// Run slave OCC init on all OCCs. Master-only initialization will be
// done after determining actual role. By default all OCCs are slave.
- slave_occ_init(); // @th00b - Moved after proc core init
+ slave_occ_init();
CHECKPOINT(SLAVE_OCC_INITIALIZED);
-#ifndef OCC_SIMICS_RESPONDER
// Initialize watchdog timers. This needs to be right before
// start rtl to make sure timer doesn't timeout. This timer is being
// reset from the rtl task.
@@ -753,18 +750,13 @@ void Main_thread_routine(void *private)
// Initialize Real time Loop Timer Interrupt
rtl_ocb_init();
CHECKPOINT(RTL_TIMER_INITIALIZED);
-#else
- TRAC_ERR("---------------------------------");
- TRAC_ERR(" OCC Responder for Simics");
- TRAC_ERR("---------------------------------");
-#endif
// Initialize semaphores and timer for handling thermal, health monitor and
// FFDC functions.
initMainThrdSemAndTimer();
CHECKPOINT(SEMS_AND_TIMERS_INITIALIZED);
- //Initialize the Applet Manager @02a
+ //Initialize the Applet Manager
// This needs to be done before initThreadScheduler because command line
// handler thread might start using applet as soon as it starts. Command
// line handler thread is started as part of the initThreadScheduler along
@@ -778,28 +770,57 @@ void Main_thread_routine(void *private)
// through cmd handler thread in middle of the initialization.
initThreadScheduler();
-#ifdef FSPLESS_SIMICS
- // In order to avoid having to run a ton of separate commands to each
- // occ when we want to test in Simics w/o FSP, we can run with a FSPLESS
- // config, using hardcoded default data from occ_sys_config.c
- sysConfigFspLess();
-#endif
-
int l_ssxrc = SSX_OK;
- // @sb022 initWatchdogTimers called before will start running the timer but
+ // initWatchdogTimers called before will start running the timer but
// the interrupt handler will just restart the timer until we use this
// enable switch to actually start the watchdog function.
ENABLE_WDOG;
while (TRUE)
{
- // @sb022 Count each loop so the watchdog can tell the main thread is
+ // Count each loop so the watchdog can tell the main thread is
// running.
G_mainThreadLoopCounter++;
+ // Flush the loop counter and trace buffers on each loop, this makes
+ // debug easier if the cmd interface doesn't respond
+ dcache_flush_line(&G_mainThreadLoopCounter);
+ dcache_flush(g_trac_inf_buffer, TRACE_BUFFER_SIZE);
+ dcache_flush(g_trac_imp_buffer, TRACE_BUFFER_SIZE);
+ dcache_flush(g_trac_err_buffer, TRACE_BUFFER_SIZE);
+
// Wait for thermal semaphore
l_ssxrc = ssx_semaphore_pend(&G_thrmSem,SSX_WAIT_FOREVER);
+ static bool L_fir_collection_completed = FALSE;
+ // Look for FIR collection flag and status
+ if (G_fir_collection_required && !L_fir_collection_completed)
+ {
+ // If this OCC is the FIR master and PNOR access is allowed perform
+ // FIR collection
+ if (OCC_IS_FIR_MASTER() && pnor_access_allowed())
+ {
+ fir_data_collect();
+ L_fir_collection_completed = TRUE;
+ }
+
+ G_fir_collection_required = FALSE;
+ // Error reporting is skipped while FIR collection is required so we
+ // don't get reset in flight. If anyone is listening send the
+ // error alert now.
+ // If this system is using PSIHB complex, send an interrupt to Host so that
+ // Host can inform HTMGT to collect the error log
+ if (G_occ_interrupt_type == PSIHB_INTERRUPT)
+ {
+ // From OCC OpenPower Interface v1.1, OCC needs to set bits 0 and 1 of
+ // the OCB_OCCMISC register
+ ocb_occmisc_t l_occmiscreg;
+ l_occmiscreg.fields.core_ext_intr = 1;
+ l_occmiscreg.fields.reason_intr = 1;
+ out32(OCB_OCCMISC_OR, l_occmiscreg.value);
+ }
+ }
+
if ( l_ssxrc != SSX_OK )
{
TRAC_ERR("thermal Semaphore pending failure RC[0x%08X]", -l_ssxrc );
@@ -883,6 +904,7 @@ void Main_thread_routine(void *private)
int main(int argc, char **argv)
{
int l_ssxrc;
+ int l_ssxrc2;
// ----------------------------------------------------
// Initialize TLB for Linear Window access here so we
@@ -896,6 +918,7 @@ int main(int argc, char **argv)
TLBLO_WR | TLBLO_I,
NULL
);
+
if(l_ssxrc != SSX_OK)
{
//failure means we can't talk to FSP.
@@ -910,26 +933,58 @@ int main(int argc, char **argv)
TLBLO_I,
NULL
);
+
if(l_ssxrc != SSX_OK)
{
//failure means we can't talk to FSP.
SSX_PANIC(0x01000002);
}
+ // Setup the TLB for writing to the FIR parms section
+ l_ssxrc = ppc405_mmu_map(FIR_PARMS_SECTION_BASE_ADDRESS,
+ FIR_PARMS_SECTION_BASE_ADDRESS,
+ FIR_PARMS_SECTION_SIZE,
+ 0,
+ TLBLO_WR | TLBLO_I,
+ NULL);
+
+ if (l_ssxrc != SSX_OK)
+ {
+ // Panic, this section is required for FIR collection on checkstops
+ SSX_PANIC(0x01000003);
+ }
+
+ // Setup the TLB for writing to the FIR heap section
+ l_ssxrc = ppc405_mmu_map(FIR_HEAP_SECTION_BASE_ADDRESS,
+ FIR_HEAP_SECTION_BASE_ADDRESS,
+ FIR_HEAP_SECTION_SIZE,
+ 0,
+ TLBLO_WR | TLBLO_I,
+ NULL);
+
+ if (l_ssxrc != SSX_OK)
+ {
+ // Panic, this section is required for FIR collection on checkstops
+ SSX_PANIC(0x01000004);
+ }
+
CHECKPOINT_INIT();
CHECKPOINT(MAIN_STARTED);
- // Initialize stdout so we can do printf from within simics env
-#ifdef OCC_SIMICS_RESPONDER
- simics_stdout_create(&G_simics_stdout);
- simics_stderr_create(&G_simics_stderr);
- stdout = (FILE *)(&G_simics_stdout);
- stderr = (FILE *)(&G_simics_stderr);
- ssxout = (FILE *)(&G_simics_stdout);
-#endif
+ homer_rc_t l_homerrc = HOMER_SUCCESS;
+ homer_rc_t l_homerrc2 = HOMER_SUCCESS;
+
+ // Get the homer version
+ uint32_t l_homer_version = 0;
+ l_homerrc = homer_hd_map_read_unmap(HOMER_VERSION,
+ &l_homer_version,
+ &l_ssxrc);
- // Initialize SSX Stacks
- // NOTE: This also reinitializes the time base to 0
+ if ((HOMER_SUCCESS != l_homerrc) && (HOMER_SSX_UNMAP_ERR != l_homerrc))
+ {
+ // Attempt to use max version if we can't read the homer.
+ l_homer_version = HOMER_VERSION_MAX;
+ }
// Get proc_pb_frequency from HOMER host data and calculate the timebase
// frequency for the OCC. Pass the timebase frequency to ssx_initialize.
@@ -937,16 +992,19 @@ int main(int argc, char **argv)
// frequency so the passed value is 1/4 of the proc_pb_frequency from the
// HOMER, ie. if the MRW says that proc_pb_frequency is 2400 MHz, then
// pass 600000000 (600MHz)
+
// The offset from the start of the HOMER is 0x00100000, we will need to
// create a temporary mapping to this section of the HOMER with ppc405_mmu_map
// (at address 0x00000000) read the value, convert it, and then unmap.
- homer_rc_t l_homerrc = HOMER_SUCCESS;
+
+ // Don't do a version check before reading the nest freq, it's present in
+ // all HOMER versions.
uint32_t l_tb_freq_hz = 0;
- l_homerrc = homer_hd_map_read_unmap(HOMER_NEST_FREQ,
- &l_tb_freq_hz,
- &l_ssxrc);
+ l_homerrc2 = homer_hd_map_read_unmap(HOMER_NEST_FREQ,
+ &l_tb_freq_hz,
+ &l_ssxrc2);
- if ((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc))
+ if ((HOMER_SUCCESS == l_homerrc2) || (HOMER_SSX_UNMAP_ERR == l_homerrc2))
{
// Data is in Mhz upon return and needs to be converted to Hz and then
// quartered.
@@ -958,25 +1016,9 @@ int main(int argc, char **argv)
l_tb_freq_hz = 400000000;
}
-
- // Get OCC interrupt type from HOMER host data area. This will tell OCC
- // which interrupt to Host it should be using.
- uint32_t l_occ_int_type = 0;
- l_homerrc = homer_hd_map_read_unmap(HOMER_INT_TYPE,
- &l_occ_int_type,
- &l_ssxrc);
-
- if ((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc))
- {
- G_occ_interrupt_type = (uint8_t) l_occ_int_type;
- }
- else
- {
- G_occ_interrupt_type = FSP_SUPPORTED_OCC;
- }
-
CHECKPOINT(SSX_STARTING);
+ // Initialize SSX Stacks. This also reinitializes the time base to 0
ssx_initialize((SsxAddress)G_noncritical_stack,
NONCRITICAL_STACK_SIZE,
(SsxAddress)G_critical_stack,
@@ -986,67 +1028,104 @@ int main(int argc, char **argv)
CHECKPOINT(SSX_INITIALIZED);
- // TRAC_XXX needs ssx service, so they can only be called after ssx_initialize
+ // TRAC_XXX needs ssx services, traces can only be done after ssx_initialize
TRAC_init_buffers();
CHECKPOINT(TRACE_INITIALIZED);
TRAC_INFO("Inside OCC Main");
// Trace what happened before ssx initialization
- TRAC_INFO("HOMER accessed, rc=%d, nest_freq=%d, int_type=%d, ssx_rc=%d",
- l_homerrc, l_tb_freq_hz, l_occ_int_type, l_ssxrc);
+ TRAC_INFO("HOMER accessed, rc=%d, version=%d, ssx_rc=%d",
+ l_homerrc, l_homer_version, l_ssxrc);
+
+ TRAC_INFO("HOMER accessed, rc=%d, nest_freq=%d, ssx_rc=%d",
+ l_homerrc2, l_tb_freq_hz, l_ssxrc2);
+
+ // Handle any errors from the version access
+ homer_log_access_error(l_homerrc,
+ l_ssxrc,
+ l_homer_version);
+
+ // Handle any errors from the nest freq access
+ homer_log_access_error(l_homerrc2,
+ l_ssxrc2,
+ l_tb_freq_hz);
+
+ // Time to access any initialization data needed from the HOMER (besides the
+ // nest frequency which was required above to enable SSX and tracing).
+ CHECKPOINT(HOMER_ACCESS_INITS);
- // Catch and log the homer error after inits are done
- if (HOMER_SUCCESS != l_homerrc)
+ if (l_homer_version >= HOMER_VERSION_2)
{
- // We could potentially have both an internal error dealing with the
- // homer and an SSX error, for example we could find an unsupported
- // version number in the homer and then have an ssx error trying to
- // unmap the homer address space. This in catches all those cases
- if (SSX_OK != l_ssxrc)
+ // Get OCC interrupt type from HOMER host data area. This will tell OCC
+ // which interrupt to Host it should be using.
+ uint32_t l_occ_int_type = 0;
+ l_homerrc = homer_hd_map_read_unmap(HOMER_INT_TYPE,
+ &l_occ_int_type,
+ &l_ssxrc);
+
+ if ((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc))
{
- /* @
- * @errortype
- * @moduleid MAIN_MID
- * @reasoncode SSX_GENERIC_FAILURE
- * @userdata1 HOMER and SSX return codes
- * @userdata2 Timebase frequency applied
- * @userdata4 ERC_HOMER_MAIN_SSX_ERROR
- * @devdesc An SSX error ocurred mapping the HOMER host data
- * into the OCC address space. User word 1 contains
- * both the internal and SSX return codes returned
- * by the method used to access the HOMER data.
- */
- errlHndl_t l_err = createErrl(MAIN_MID, //modId
- SSX_GENERIC_FAILURE, //reasoncode
- ERC_HOMER_MAIN_SSX_ERROR, //Extended reason code
- ERRL_SEV_PREDICTIVE, //Severity
- NULL, //Trace Buf
- DEFAULT_TRACE_SIZE, //Trace Size
- (l_homerrc << 16) | (0xFFFF & (uint32_t)l_ssxrc), //userdata1
- l_tb_freq_hz); //userdata2
- commitErrl(&l_err);
+ G_occ_interrupt_type = (uint8_t) l_occ_int_type;
}
else
{
- /* @
- * @errortype
- * @moduleid MAIN_MID
- * @reasoncode INTERNAL_FAILURE
- * @userdata1 HOMER return code
- * @userdata2 Default timebase frequency applied
- * @userdata4 ERC_HOMER_MAIN_ACCESS_ERROR
- * @devdesc Error accessing initialization data
- */
- errlHndl_t l_err = createErrl(MAIN_MID, //modId
- INTERNAL_FAILURE, //reasoncode
- ERC_HOMER_MAIN_ACCESS_ERROR,//Extended reason code
- ERRL_SEV_INFORMATIONAL, //Severity
- NULL, //Trace Buf
- DEFAULT_TRACE_SIZE, //Trace Size
- l_homerrc, //userdata1
- l_tb_freq_hz); //userdata2
- commitErrl(&l_err);
+ G_occ_interrupt_type = FSP_SUPPORTED_OCC;
+ }
+
+ TRAC_INFO("HOMER accessed, rc=%d, host interrupt type=%d, ssx_rc=%d",
+ l_homerrc, l_occ_int_type, l_ssxrc);
+
+ // Handle any errors from the interrupt type access
+ homer_log_access_error(l_homerrc,
+ l_ssxrc,
+ l_occ_int_type);
+ }
+
+ if (l_homer_version >= HOMER_VERSION_3)
+ {
+ // Get the FIR Master indicator
+ uint32_t l_fir_master = FIR_OCC_NOT_FIR_MASTER;
+ l_homerrc = homer_hd_map_read_unmap(HOMER_FIR_MASTER,
+ &l_fir_master,
+ &l_ssxrc);
+
+ if (((HOMER_SUCCESS == l_homerrc) || (HOMER_SSX_UNMAP_ERR == l_homerrc))
+ &&
+ (FIR_OCC_IS_FIR_MASTER == l_fir_master))
+ {
+ OCC_SET_FIR_MASTER(FIR_OCC_IS_FIR_MASTER);
+ }
+ else
+ {
+ OCC_SET_FIR_MASTER(FIR_OCC_NOT_FIR_MASTER);
+ }
+
+ TRAC_INFO("HOMER accessed, rc=%d, FIR master=%d, ssx_rc=%d",
+ l_homerrc, l_fir_master, l_ssxrc);
+
+ // Handle any errors from the FIR master access
+ homer_log_access_error(l_homerrc,
+ l_ssxrc,
+ l_fir_master);
+
+ // If this OCC is the FIR master read in the FIR collection parms
+ if (OCC_IS_FIR_MASTER())
+ {
+ TRAC_IMP("I am the FIR master");
+
+ // Read the FIR parms buffer
+ l_homerrc = homer_hd_map_read_unmap(HOMER_FIR_PARMS,
+ &G_fir_data_parms[0],
+ &l_ssxrc);
+
+ TRAC_INFO("HOMER accessed, rc=%d, FIR parms buffer 0x%x, ssx_rc=%d",
+ l_homerrc, &G_fir_data_parms[0], l_ssxrc);
+
+ // Handle any errors from the FIR master access
+ homer_log_access_error(l_homerrc,
+ l_ssxrc,
+ (uint32_t)&G_fir_data_parms[0]);
}
}
@@ -1086,7 +1165,7 @@ int main(int argc, char **argv)
-l_rc, //userdata1
0); //userdata2
// Commit Error log
- REQUEST_RESET(l_err); // @gm006
+ REQUEST_RESET(l_err);
}
// Enter SSX Kernel
diff --git a/src/occ/occLinkInputFile b/src/occ/occLinkInputFile
index 7e5dd54..892bcd4 100644
--- a/src/occ/occLinkInputFile
+++ b/src/occ/occLinkInputFile
@@ -1 +1,109 @@
-INPUT ( amec_init.o amec_tasks.o amec_slave_smh.o amec_master_smh.o amec_sensors_core.o amec_sensors_centaur.o amec_sensors_power.o amec_sensors_fw.o amec_data.o amec_freq.o amec_amester.o amec_dps.o amec_part.o amec_perfcount.o amec_controller.o amec_oversub.o amec_pcap.o amec_health.o amec_parm.o amec_parm_table.o amec_analytics.o appletManager.o centaur_data.o centaur_control.o cmdh_fsp.o cmdh_thread.o cmdh_fsp_cmds.o cmdh_fsp_cmds_datacnfg.o cmdh_mnfg_intf.o cmdh_tunable_parms.o cmdh_snapshot.o ffdc.o dcom.o dcom_thread.o dcomSlaveTx.o dcomSlaveRx.o dcomMasterTx.o dcomMasterRx.o errl.o proc_data.o proc_data_control.o proc_pstate.o apss.o dpss.o rtls_tables.o rtls.o sensor.o sensor_table.o threadSch.o chom.o thrm_thread.o timer.o trac_interface.o occ_sys_config.o arl_test.o state.o reset.o mode.o main.o scom.o homer.o occbuildname.o common.o ll_ffdc.o ssx_core.o ssx_init.o ssx_stack_init.o ssx_timer_core.o ssx_timer_init.o ssx_thread_init.o ssx_thread_core.o ssx_semaphore_init.o ssx_semaphore_core.o pgp_init.o pgp_irq_init.o pgp_pmc.o pgp_ocb.o pgp_pba.o pgp_id.o pgp_centaur.o pgp_cache.o pgp_async.o pgp_async_pore.o pgp_async_ocb.o pgp_async_pba.o ppc405_core.o ppc405_lib_core.o ppc405_cache_core.o ppc405_init.o ppc405_irq_core.o ppc405_irq_init.o ppc405_boot.o ppc405_exceptions.o ppc405_cache_init.o ppc405_mmu_asm.o ppc405_breakpoint.o ppc405_thread_init.o ppc405_mmu.o )
+INPUT ( amec_init.o
+ amec_tasks.o
+ amec_slave_smh.o
+ amec_master_smh.o
+ amec_sensors_core.o
+ amec_sensors_centaur.o
+ amec_sensors_power.o
+ amec_sensors_fw.o
+ amec_data.o
+ amec_freq.o
+ amec_amester.o
+ amec_dps.o amec_part.o
+ amec_perfcount.o
+ amec_controller.o
+ amec_oversub.o
+ amec_pcap.o
+ amec_health.o
+ amec_parm.o
+ amec_parm_table.o
+ amec_analytics.o
+ appletManager.o
+ centaur_data.o
+ centaur_control.o
+ cmdh_fsp.o
+ cmdh_thread.o
+ cmdh_fsp_cmds.o
+ cmdh_fsp_cmds_datacnfg.o
+ cmdh_mnfg_intf.o
+ cmdh_tunable_parms.o
+ cmdh_snapshot.o
+ ffdc.o
+ dcom.o
+ dcom_thread.o
+ dcomSlaveTx.o
+ dcomSlaveRx.o
+ dcomMasterTx.o
+ dcomMasterRx.o
+ errl.o
+ ecc.o
+ fir_data_collect.o
+ firData.o
+ fsi.o
+ lpc.o
+ native.o
+ nor_micron.o
+ pnor_util.o
+ scom_trgt.o
+ scom_util.o
+ sfc_ast2400.o
+ memcpy.o
+ proc_data.o
+ proc_data_control.o
+ proc_pstate.o
+ apss.o
+ dpss.o
+ rtls_tables.o
+ rtls.o
+ sensor.o
+ sensor_table.o
+ threadSch.o
+ chom.o
+ thrm_thread.o
+ timer.o
+ trac_interface.o
+ occ_sys_config.o
+ arl_test.o
+ state.o
+ reset.o
+ mode.o
+ main.o
+ scom.o
+ homer.o
+ occbuildname.o
+ common.o
+ ll_ffdc.o
+ ssx_core.o
+ ssx_init.o
+ ssx_stack_init.o
+ ssx_timer_core.o
+ ssx_timer_init.o
+ ssx_thread_init.o
+ ssx_thread_core.o
+ ssx_semaphore_init.o
+ ssx_semaphore_core.o
+ pgp_init.o
+ pgp_irq_init.o
+ pgp_pmc.o
+ pgp_ocb.o
+ pgp_pba.o
+ pgp_id.o
+ pgp_centaur.o
+ pgp_cache.o
+ pgp_async.o
+ pgp_async_pore.o
+ pgp_async_ocb.o
+ pgp_async_pba.o
+ ppc405_core.o
+ ppc405_lib_core.o
+ ppc405_cache_core.o
+ ppc405_init.o
+ ppc405_irq_core.o
+ ppc405_irq_init.o
+ ppc405_boot.o
+ ppc405_exceptions.o
+ ppc405_cache_init.o
+ ppc405_mmu_asm.o
+ ppc405_breakpoint.o
+ ppc405_thread_init.o
+ ppc405_mmu.o )
diff --git a/src/occ/occ_service_codes.h b/src/occ/occ_service_codes.h
index 313c7fa..f1f4c70 100644
--- a/src/occ/occ_service_codes.h
+++ b/src/occ/occ_service_codes.h
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -53,8 +53,7 @@ enum occReasonCode
PROC_ERROR_TEMP = 0x10,
/// Timed out reading processor temperature
PROC_TEMP_TIMEOUT = 0x11,
- /// @wb003 -- Removed PROCESSOR_NOT_SUPPORTED and changed error to INTERNAL_FAILURE
- /// Processor SCOM failure -- gm025
+ /// Processor SCOM failure
PROC_SCOM_ERROR = 0x16,
/// Any failure coming from the SSX RTOS code
SSX_GENERIC_FAILURE = 0x17,
@@ -88,6 +87,8 @@ enum occReasonCode
INTERNAL_INVALID_INPUT_DATA = 0xB3,
/// A core was not at the expected frequency
TARGET_FREQ_FAILURE = 0xB4,
+ /// RTL detected a system checkstop
+ OCC_SYSTEM_HALTED = 0xB5,
/// Request to read APSS data failed.
APSS_GPE_FAILURE = 0xC0,
/// Connector overcurrent pin still asserted.
@@ -182,6 +183,8 @@ enum occExtReasonCode
ERC_CHIP_IDS_INVALID = 0x00000050,
ERC_GETSCOM_FAILURE = 0x00000051,
+ ERC_GETSCOM_TPC_GP0_FAILURE = 0x00000052,
+ ERC_PNOR_OWNERSHIP_NOT_AVAILABLE = 0x00000053,
ERC_HOMER_MAIN_ACCESS_ERROR = 0x00000060,
ERC_HOMER_MAIN_SSX_ERROR = 0x00000061,
@@ -210,13 +213,14 @@ enum occModuleId
MAIN_THRD_SEM_INIT_MID = MAIN_COMP_ID | 0x04,
MAIN_STATE_TRANSITION_MID = MAIN_COMP_ID | 0x05,
MAIN_MODE_TRANSITION_MID = MAIN_COMP_ID | 0x06,
- MAIN_GPE_HALTED_MID = MAIN_COMP_ID | 0x07,
+ MAIN_SYSTEM_HALTED_MID = MAIN_COMP_ID | 0x07,
OCC_IRQ_SETUP = MAIN_COMP_ID | 0x08,
PMC_HW_ERROR_ISR = MAIN_COMP_ID | 0x09,
GETSCOM_FFDC_MID = MAIN_COMP_ID | 0x0a,
PUTSCOM_FFDC_MID = MAIN_COMP_ID | 0x0b,
HMON_ROUTINE_MID = MAIN_COMP_ID | 0x0c,
- AMEC_VERIFY_FREQ_MID = MAIN_COMP_ID | 0x0d,
+ AMEC_VERIFY_FREQ_MID = MAIN_COMP_ID | 0x0d,
+ FIR_DATA_MID = MAIN_COMP_ID | 0x0e,
};
enum occUserDataType
diff --git a/src/occ/reset.c b/src/occ/reset.c
index 2ec233f..f99fc40 100755
--- a/src/occ/reset.c
+++ b/src/occ/reset.c
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -96,7 +96,7 @@ void reset_state_request(uint8_t i_request)
// state to reset to enter the reset state machine.
if(G_reset_state < RESET_REQUESTED_DUE_TO_ERROR)
{
- TRAC_ERR("Resetting via Reset State Machine");
+ TRAC_IMP("Activating reset required state.");
G_reset_state = RESET_REQUESTED_DUE_TO_ERROR;
@@ -150,50 +150,74 @@ void reset_state_request(uint8_t i_request)
void task_check_for_checkstop(task_t *i_self)
{
pore_status_t l_gpe0_status;
- static bool L_gpe_halt_traced = FALSE;
+ ocb_oisr0_t l_oisr0_status;
+ static bool L_checkstop_traced = FALSE;
+ uint8_t l_reason_code = 0;
do
{
- //only do this once
- if(L_gpe_halt_traced)
+ // This check is disabled once a checkstop or frozen GPE is detected
+ if(L_checkstop_traced)
{
break;
}
- L_gpe_halt_traced = TRUE;
-
+ // Looked for a frozen GPE, a sign that the chip has stopped working or
+ // check-stopped. This check also looks for an interrupt status flag that
+ // indicates if the system has check-stopped.
l_gpe0_status.value = in64(PORE_GPE0_STATUS);
+ l_oisr0_status.value = in32(OCB_OISR0);
- if (l_gpe0_status.fields.freeze_action)
+ if (l_gpe0_status.fields.freeze_action
+ ||
+ l_oisr0_status.fields.check_stop)
{
- errlHndl_t l_err = NULL;
+ errlHndl_t l_err = NULL;
+
+ if (l_gpe0_status.fields.freeze_action)
+ {
+ TRAC_IMP("Frozen GPE0 detected by RTL");
+ l_reason_code = OCC_GPE_HALTED;
+ }
- TRAC_ERR("task_check_for_checkstop: OCC GPE halted due to checkstop");
+ if (l_oisr0_status.fields.check_stop)
+ {
+ TRAC_IMP("System checkstop detected by RTL");
+ l_reason_code = OCC_SYSTEM_HALTED;
+ }
+
+ L_checkstop_traced = TRUE;
/*
* @errortype
- * @moduleid MAIN_GPE_HALTED_MID
+ * @moduleid MAIN_SYSTEM_HALTED_MID
* @reasoncode OCC_GPE_HALTED
- * @userdata1 0
- * @userdata2 0
- * @devdesc OCC GPE halted due to checkstop
+ * @userdata1 High order word of PORE_GPE0_STATUS
+ * @userdata2 OCB_OISR0
+ * @devdesc OCC detected frozen GPE0
*/
- l_err = createErrl(MAIN_GPE_HALTED_MID,
- OCC_GPE_HALTED,
+ /*
+ * @errortype
+ * @moduleid MAIN_SYSTEM_HALTED_MID
+ * @reasoncode OCC_SYSTEM_HALTED
+ * @userdata1 High order word of PORE_GPE0_STATUS
+ * @userdata2 OCB_OISR0
+ * @devdesc OCC detected system checkstop
+ */
+ l_err = createErrl(MAIN_SYSTEM_HALTED_MID,
+ l_reason_code,
OCC_NO_EXTENDED_RC,
ERRL_SEV_INFORMATIONAL,
NULL,
DEFAULT_TRACE_SIZE,
- 0,
- 0);
+ l_gpe0_status.words.high_order,
+ l_oisr0_status.value);
- //This will request safe mode under the covers due to the GPE being halted.
+ // The commit code will check for the frozen GPE0 and system
+ // checkstop conditions and take appropriate actions.
commitErrl(&l_err);
}
-
- } while (0);
+ }
+ while(0);
}
-
-
-
diff --git a/src/occ/state.c b/src/occ/state.c
index 7288191..716c10c 100755
--- a/src/occ/state.c
+++ b/src/occ/state.c
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -38,7 +38,7 @@
#include "proc_data.h"
#include "heartbeat.h"
#include "scom.h"
-
+#include <fir_data_collect.h>
extern proc_gpsm_dcm_sync_occfw_t G_proc_dcm_sync_state;
extern bool G_mem_monitoring_allowed;
@@ -55,7 +55,6 @@ errlHndl_t SMGR_active_to_observation();
errlHndl_t SMGR_active_to_standby();
errlHndl_t SMGR_all_to_safe();
-
// State that OCC is currently in
OCC_STATE G_occ_internal_state = OCC_STATE_STANDBY;
@@ -615,16 +614,15 @@ errlHndl_t SMGR_set_state(OCC_STATE i_new_state)
* @userdata4 ERC_RUNNING_SEM_PENDING_FAILURE
* @devdesc SSX semaphore related failure
*/
- l_transResult = createErrl(MAIN_STATE_TRANSITION_MID, //modId
- SSX_GENERIC_FAILURE, //reasoncode
- ERC_RUNNING_SEM_PENDING_FAILURE, //Extended reason code
- ERRL_SEV_UNRECOVERABLE, //Severity
- NULL, //Trace Buf
- DEFAULT_TRACE_SIZE, //Trace Size
- 0, //userdata1
- 0); //userdata2
-
- // @wb001 -- Callout firmware
+ l_transResult = createErrl(MAIN_STATE_TRANSITION_MID, //modId
+ SSX_GENERIC_FAILURE, //reasoncode
+ ERC_RUNNING_SEM_PENDING_FAILURE, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ 0, //userdata1
+ 0); //userdata2
+
addCalloutToErrl(l_transResult,
ERRL_CALLOUT_TYPE_COMPONENT_ID,
ERRL_COMPONENT_ID_FIRMWARE,
@@ -643,32 +641,34 @@ errlHndl_t SMGR_set_state(OCC_STATE i_new_state)
// transition function that matches the transition we need to do.
for(jj=0; jj<G_smgr_state_trans_count; jj++)
{
- if( ((G_smgr_state_trans[jj].old_state == G_occ_internal_state)
- || (G_smgr_state_trans[jj].old_state == OCC_STATE_ALL) )
- && (G_smgr_state_trans[jj].new_state == i_new_state) )
- {
- // We found the transtion that matches, now run the function
- // that is associated with that state transition.
- if(NULL != G_smgr_state_trans[jj].trans_func_ptr)
- {
- // Signal that we are now in a state transition
- G_state_transition_occuring = TRUE;
- // Run transition function
- l_transResult = (G_smgr_state_trans[jj].trans_func_ptr)();
- // Signal that we are done with the transition
- G_state_transition_occuring = FALSE;
- break;
- }
- }
+ if(((G_smgr_state_trans[jj].old_state == G_occ_internal_state)
+ ||
+ (G_smgr_state_trans[jj].old_state == OCC_STATE_ALL))
+ &&
+ (G_smgr_state_trans[jj].new_state == i_new_state))
+ {
+ // We found the transtion that matches, now run the function
+ // that is associated with that state transition.
+ if(NULL != G_smgr_state_trans[jj].trans_func_ptr)
+ {
+ // Signal that we are now in a state transition
+ G_state_transition_occuring = TRUE;
+ // Run transition function
+ l_transResult = (G_smgr_state_trans[jj].trans_func_ptr)();
+ // Signal that we are done with the transition
+ G_state_transition_occuring = FALSE;
+ break;
+ }
+ }
}
// Check if we hit the end of the table without finding a valid
// state transition. If we did, log an internal error.
if(G_smgr_state_trans_count == jj)
{
- TRAC_ERR("No transition (or NULL) found for the state change\n");
- l_transResult = NULL;
- break;
+ TRAC_ERR("No transition (or NULL) found for the state change");
+ l_transResult = NULL;
+ break;
}
// If the state OCC requested from TMGT is the state we are now in,
@@ -690,14 +690,15 @@ errlHndl_t SMGR_set_state(OCC_STATE i_new_state)
//
// Name: SMGR_validate_get_valid_states
//
-// Description:
+// Description: Return a byte of status masks that correspond to the v10 poll
+// response definition status byte.
//
// End Function Specification
uint8_t SMGR_validate_get_valid_states(void)
{
- uint8_t l_valid_states = 0;
- uint32_t l_datamask = DATA_get_present_cnfgdata();
- static BOOLEAN l_throttle_traced = FALSE;
+ uint8_t l_valid_states = 0;
+ uint32_t l_datamask = DATA_get_present_cnfgdata();
+ static BOOLEAN l_throttle_traced = FALSE;
// If we have everything we need to go to observation state
if((l_datamask & SMGR_VALIDATE_DATA_OBSERVATION_MASK) ==
@@ -731,6 +732,12 @@ uint8_t SMGR_validate_get_valid_states(void)
l_valid_states |= SMGR_MASK_MASTER_OCC;
}
+ // Indicate if this OCC is the FIR master.
+ if (OCC_IS_FIR_MASTER())
+ {
+ l_valid_states |= OCC_ROLE_FIR_MASTER_MASK;
+ }
+
return l_valid_states;
}
diff --git a/src/occ/trac/trac.h b/src/occ/trac/trac.h
index 3ed4b05..87f669b 100755
--- a/src/occ/trac/trac.h
+++ b/src/occ/trac/trac.h
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
@@ -71,7 +71,6 @@
extern void dumpHexString(const void *i_data, const unsigned int len, const char *string);
#define DEBUG_HEXDUMP(data, len, string) \
dumpHexString(data, len, string)
-//TODO: Do we want to have one buffer for tracing binary
#else //TRAC_TO_SIMICS
diff --git a/src/occ/trac/trac_interface.h b/src/occ/trac/trac_interface.h
index 9370e8e..d448a0e 100755
--- a/src/occ/trac/trac_interface.h
+++ b/src/occ/trac/trac_interface.h
@@ -5,10 +5,10 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] Google Inc. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] International Business Machines Corp. */
/* */
+/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
OpenPOWER on IntegriCloud