summaryrefslogtreecommitdiffstats
path: root/src/occ/dcom
diff options
context:
space:
mode:
authorStephan Broyles <sbroyles@us.ibm.com>2014-11-05 19:09:37 -0600
committerStephan Broyles <sbroyles@us.ibm.com>2014-11-05 19:22:32 -0600
commit9976c207cdb20871880bd2f4cf123cf4cb6a8b0f (patch)
tree1cf9ed8f23085e6fe3e0e6046fc30dcb7e02ccf2 /src/occ/dcom
parent2f8ce357b89d361b5091d88aea91416011b73ccb (diff)
downloadtalos-occ-9976c207cdb20871880bd2f4cf123cf4cb6a8b0f.tar.gz
talos-occ-9976c207cdb20871880bd2f4cf123cf4cb6a8b0f.zip
Added remaining occ files.
Change-Id: I91a748d3dcf3161a6a3eedcb376fcaf1e4dfe655
Diffstat (limited to 'src/occ/dcom')
-rwxr-xr-xsrc/occ/dcom/dcom.c902
-rwxr-xr-xsrc/occ/dcom/dcom.h585
-rw-r--r--src/occ/dcom/dcomMasterRx.c430
-rwxr-xr-xsrc/occ/dcom/dcomMasterTx.c628
-rw-r--r--src/occ/dcom/dcomSlaveRx.c671
-rwxr-xr-xsrc/occ/dcom/dcomSlaveTx.c431
-rwxr-xr-xsrc/occ/dcom/dcom_service_codes.h73
-rwxr-xr-xsrc/occ/dcom/dcom_thread.c223
8 files changed, 3943 insertions, 0 deletions
diff --git a/src/occ/dcom/dcom.c b/src/occ/dcom/dcom.c
new file mode 100755
index 0000000..40ae891
--- /dev/null
+++ b/src/occ/dcom/dcom.c
@@ -0,0 +1,902 @@
+/******************************************************************************
+// @file dcom.c
+// @brief OCC to OCC communication handler general functions
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcom.c DCOM.C
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @00 tapiar 09/14/2011 Created
+ * @01 tapiar 10/14/2011 stage 2 updates
+ * @02 tapiar 11/14/2011 stage 3 updates
+ * @th009 thallet 01/31/2012 Changes to allow OCC Slave
+ * @rc003 rickylie 02/03/2012 Verify & Clean Up OCC Headers & Comments
+ * @nh001 neilhsu 05/23/2012 Add missing error log tags
+ * @th010 thallet 07/11/2012 Pstate Enablement
+ * @th022 thallet 10/08/2012 Dcom State/Mode passing
+ * @th025 857856 thallet 10/16/2012 Dcom State/Mode passing part 2
+ * @th034 879027 thallet 04/18/2013 Broadcast Critical Power Data over PBAX
+ * @th032 thallet 04/26/2013 Tuleta Bringup Fixes
+ * @th035 881654 thallet 05/06/2013 Tuleta Bringup Pstate Fixes
+ * @th036 881677 thallet 05/09/2013 New Poll command support
+ * @th037 thallet 05/28/2013 Murano DCM Numbering modification
+ * @th038 thallet 06/03/2013 Disable Centaur since it isn't ready on HW yet
+ * @th040 887069 thallet 06/11/2013 Support Nom & FFO Freq Setting for Mnfg
+ * @th042 892056 thallet 07/19/2013 Send OCC to safe mode if first APSS GPE fails
+ * @th044 892742 thallet 07/24/2013 Added module ID
+ * @gs008 894661 gjsilva 08/08/2013 Initial support for DPS-FP mode
+ * @at018 896098 alvinwan 08/20/2013 Race condition between OCC Master and OCC Slaves in DATA_FORMAT_CLEAR_ALL
+ * @gm006 SW224414 milesg 09/16/2013 Reset and FFDC improvements
+ * @gm007 899876 milesg 09/23/2013 failure to go active on 8 OCC system.
+ * @rt001 901927 tapiar 10/02/2013 Fix src tags
+ * @gs015 905166 gjsilva 11/04/2013 Full support for IPS function
+ * @gs017 905990 gjsilva 11/13/2013 Full support for tunable parameters
+ * @at019 908390 alvinwan 12/05/2013 Disable DPS algorithms from running in Sapphire
+ * @gs020 909320 gjsilva 12/12/2013 Support for VR_FAN thermal control
+ * @gm018 910012 milesg 12/20/2013 autoslew not working on proc0
+ * @gs025 913663 gjsilva 01/30/2014 Full fupport for soft frequency boundaries
+ * @wb001 919163 wilbryan 03/06/2014 Updating error call outs, descriptions, and severities
+ * @gm033 920448 milesg 03/26/2014 use getscom/putscom ffdc wrapper
+ * @gm037 925908 milesg 05/07/2014 Redundant OCC/APSS support
+ * @gs034 929799 gjsilva 06/19/2014 Temporary fix for Brazos SMP wrap-mode
+ *
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOM_C
+#define _DCOM_C
+
+/** \defgroup OCC-OCC Communication
+ *
+ */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <pgp_pmc.h>
+#include "pgp_pba.h"
+#include <rtls.h>
+#include <apss.h>
+#include <dcom.h>
+#include <dcom_service_codes.h>
+#include <occ_service_codes.h>
+#include <trac.h>
+#include <state.h>
+#include <proc_pstate.h>
+#include <amec_data.h>
+#include <amec_sys.h>
+#include "scom.h"
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+#define PBAX_CONFIGURE_RCV_GROUP_MASK 0xff
+
+#define PBAX_BROADCAST_GROUP 0xFF
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+dcom_timing_t G_dcomTime; // @th032
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+DMA_BUFFER( dcom_slv_inbox_t G_dcom_slv_inbox_tx[MAX_OCCS]) = {{0}};
+DMA_BUFFER( dcom_slv_outbox_t G_dcom_slv_outbox_tx) = {0};
+
+DMA_BUFFER( dcom_slv_outbox_t G_dcom_slv_outbox_rx[MAX_OCCS]) = {{0}};
+DMA_BUFFER( dcom_slv_inbox_t G_dcom_slv_inbox_rx) = {0};
+
+// =========================================================
+// Master & Slave
+// =========================================================
+
+
+
+// PBAX Circ Queue buffers (where PBAX will put the data in OCC SRAM, so that OCC
+// can grab it.
+
+PBAX_CQ_READ_BUFFER(G_pbax_queue_rx1_buffer,NUM_ENTRIES_PBAX_QUEUE1);
+PBAX_CQ_READ_BUFFER(G_pbax_queue_rx0_buffer,NUM_ENTRIES_PBAX_QUEUE0);
+
+
+// Initialize Globals
+
+// Indicate that Slave OCC got an inbox from master
+bool G_slv_inbox_received = FALSE;
+
+// Counters to debug Master/Slave communication errors
+dcom_fail_count_t G_dcomSlvInboxCounter = {0};
+
+uint8_t G_occ_role = OCC_SLAVE;
+
+uint8_t G_dcm_occ_role = OCC_DCM_SLAVE;
+
+// PowerBus ID of this OCC. Contains ChipId & NodeId.
+pob_id_t G_pob_id = {0};
+
+// PBAX 'Target' Structure (Register Abstraction) that has the data needed for
+// a multicast operation.
+PbaxTarget G_pbax_multicast_target;
+
+// PBAX 'Target' Structure (Register Abstraction) that has the data needed for
+// a unicast operation from the OCC Slave to the OCC Master.
+PbaxTarget G_pbax_unicast_target;
+
+// Number of occ's that *should* be present
+uint8_t G_occ_num_present; // @th025
+
+// DCM Status from all Slaves
+proc_gpsm_dcm_sync_occfw_t G_dcm_sync_occfw_table[MAX_OCCS]; // @th010
+
+// master/slave event flags
+uint32_t G_master_event_flags = 0;
+uint32_t G_slave_event_flags = 0;
+uint32_t G_master_event_flags_ack = 0 ;
+uint32_t G_slave_event_flags_ack[MAX_OCCS] = {0};
+
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Helper function to determine if slave inboxes are valid
+bool isDcomSlvInboxValid(void){return (G_dcomSlvInboxCounter.currentFailCount ? FALSE : TRUE);}
+
+// Function Specification
+//
+// Name: dcom_initialize_roles
+//
+// Description: Initialize roles so we know if we are master or slave
+//
+// Flow: 09/13/11 FN=dcom_initialize_roles
+//
+// End Function Specification
+void dcom_initialize_roles(void)
+{
+ G_occ_role = OCC_SLAVE;
+
+ // Locals
+ int l_rc = 0;
+ tpc_gp0_t l_tp_gp0_read;
+
+ // Used as a debug tool to correlate time between OCCs & System Time
+ getscom_ffdc( TOD_VALUE_REG, &G_dcomTime.tod, NULL); //commits errors internally -- gm033
+ G_dcomTime.base = ssx_timebase_get(); // @th032
+
+ // Scom will timeout if it can't be read
+ l_rc = getscom_ffdc( TPC_GP0, (uint64_t *) &l_tp_gp0_read, NULL); //commits errors internally -- gm033
+
+ if( l_rc == 0 )
+ {
+ // @th037 - Added check for Murano ChipId swizzle
+ if(CFAM_CHIP_TYPE_MURANO == cfam_chip_type())
+ {
+ /// Murano has a different numbering scheme than you would
+ /// expect. It uses NodeId to denote DCM Id, and ChipId to
+ /// denote chip within the DCM. This is due to they way the
+ /// PowerBus works for routing.
+ ///
+ /// To fix this, we need to manipulate our internal copy of
+ /// ChipId/NodeId to match the way OCC FW uses them. We do this
+ /// multiplying the NodeId by 2 then adding chip Id to get a unique
+ /// new ChipId (Max Node = 3, Max Chip = 1 by design
+ ///
+ /// Note that Murano is not multi-drawer capable, so we can
+ /// fix our node id at 0
+
+#define MAX_MURANO_CHIP_IDS 2
+#define MAX_MURANO_NODE_IDS 4
+ if( (l_tp_gp0_read.fields.tc_chip_id_dc < MAX_MURANO_CHIP_IDS)
+ && (l_tp_gp0_read.fields.tc_node_id_dc < MAX_MURANO_NODE_IDS))
+ {
+ // Tuleta was mis-wired on the backplane, so we need to hack
+ // around this to figure out the module that we are on.
+ // The problem is that we don't really know
+ // at this point in code that we are running on a Tuleta vs
+ // an Orlena. Since Orlena is not yet a thing..we will
+ // assume tuleta.
+ // TODO: Revisit this once Orlena becomes a thing. In
+ // Orlena, it should be possible just to use the
+ // node_id that was read from the chip's GP0
+
+ // Translate between chip ID & Module Id for Tuleta
+ uint8_t tuleta_chip2module[] = {0,0,2,2,1,1,3,3};
+
+ G_pob_id.chip_id = (l_tp_gp0_read.fields.tc_chip_id_dc
+ + ( MAX_MURANO_CHIP_IDS * l_tp_gp0_read.fields.tc_node_id_dc));
+ G_pob_id.node_id = 0;
+
+ // The module id is only used by Power Measurements
+ G_pob_id.module_id = tuleta_chip2module[G_pob_id.chip_id];
+ //G_pob_id.module_id = (l_tp_gp0_read.fields.tc_node_id_dc & 0x03);
+ }
+ else
+ {
+ // Chip Ids don't make any sense
+ TRAC_ERR("Proc ChipId (%d) and/or NodeId (%d) don't make sense for Murano",
+ l_tp_gp0_read.fields.tc_chip_id_dc,
+ l_tp_gp0_read.fields.tc_node_id_dc);
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_INIT_ROLES
+ * @reasoncode INTERNAL_HW_FAILURE
+ * @userdata1 TP.GP0 SCOM (upper)
+ * @userdata2 TP.GP0 SCOM (lower)
+ * @userdata4 ERC_CHIP_IDS_INVALID
+ * @devdesc Failure determining OCC role
+ */
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_INIT_ROLES, //modId
+ INTERNAL_HW_FAILURE, //reasoncode // @nh001c
+ ERC_CHIP_IDS_INVALID, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_tp_gp0_read.words.high_order, //userdata1
+ l_tp_gp0_read.words.low_order //userdata2
+ );
+
+ // @wb001 -- Callout firmware
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ // commit log
+ commitErrl( &l_errl );
+ }
+ }
+ else
+ {
+ // Save off chip and node ids directly as read
+ G_pob_id.chip_id = l_tp_gp0_read.fields.tc_chip_id_dc;
+ G_pob_id.node_id = l_tp_gp0_read.fields.tc_node_id_dc;
+
+ // Check if special SMP wrap mode is turned on. In this mode, a
+ // single drawer is configured as two virtual nodes. However, OCC
+ // still needs to treat it as a single node.
+ // As a temporary solution, HWSV is going to set bit 17 of the GP0
+ // register to inform OCC that SMP wrap is on.
+
+#define SMP_WRAP_MASK 0x00004000
+ if(l_tp_gp0_read.words.high_order & SMP_WRAP_MASK)
+ {
+ TRAC_INFO("dcom_initialize_roles: Temporary fix - SMP wrap mode has been detected");
+
+ // This is a single drawer
+ G_pob_id.node_id = 0;
+
+ // Translate the NodeId and ChipId into the correct internal
+ // representation for OCC to work.
+ if(l_tp_gp0_read.fields.tc_node_id_dc == 0)
+ {
+ G_pob_id.chip_id = 2 * l_tp_gp0_read.fields.tc_chip_id_dc;
+ }
+ else if(l_tp_gp0_read.fields.tc_node_id_dc == 1)
+ {
+ G_pob_id.chip_id = (l_tp_gp0_read.fields.tc_chip_id_dc) ? 1 : 3;
+ }
+ }
+
+ // Save off low 2 bits of chip ID as module ID. Won't be
+ // more than 4 on venice since it is SCMs.
+ G_pob_id.module_id = (G_pob_id.chip_id & 0x03);
+ }
+
+ // Always start as OCC Slave
+ G_occ_role = OCC_SLAVE; // @th022a
+ rtl_set_run_mask(RTL_FLAG_NOTMSTR); // @th022a
+
+ // Save off OCC role inside DCM chip
+ if(gpsm_dcm_slave_p())
+ {
+ G_dcm_occ_role = OCC_DCM_SLAVE;
+ }
+ else
+ {
+ G_dcm_occ_role = OCC_DCM_MASTER;
+ }
+
+ TRAC_IMP("Proc ChipId=%d, NodeId=%d, isDcm=%d, isDcmMaster=%d, ChipEC=0x%08x",
+ G_pob_id.chip_id,
+ G_pob_id.node_id,
+ gpsm_dcm_mode_p(),
+ !gpsm_dcm_slave_p(),
+ cfam_id() ); // @th035
+ }
+ else
+ {
+ //get scom failure
+ TRAC_ERR("getscom failure rc[0x%08X]", -l_rc );
+
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_INIT_ROLES
+ * @reasoncode INTERNAL_HW_FAILURE
+ * @userdata1 getscom failure rc
+ * @userdata4 ERC_GETSCOM_FAILURE
+ * @devdesc Failure determining OCC role
+ */
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_INIT_ROLES, //modId
+ INTERNAL_HW_FAILURE, //reasoncode // @nh001c
+ ERC_GETSCOM_FAILURE, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_rc, //userdata1
+ 0 //userdata2
+ );
+
+ // @wb001 -- Callout firmware
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ // commit log
+ commitErrl( &l_errl );
+
+ // TODO request a reset of OCC
+ // we are toast without this working correctly
+ }
+
+ // Set the initial presence mask, and count the number of occ's present
+ G_sysConfigData.is_occ_present |= (0x01 << G_pob_id.chip_id); // @th036
+ G_occ_num_present = __builtin_popcount(G_sysConfigData.is_occ_present); // @th025
+
+ // Initialize DCOM Thread Sem
+ ssx_semaphore_create( &G_dcomThreadWakeupSem, // Semaphore
+ 1, // Initial Count
+ 0); // No Max Count @th035
+
+}
+
+
+// Function Specification
+//
+// Name: dcom_initialize_pbax_queues
+//
+// Description: Initialize the PBAX Queues for sending doorbells
+//
+// Flow: 09/13/11 FN=dcom_initialize_pbax_queues
+//
+// End Function Specification
+void dcom_initialize_pbax_queues(void)
+{
+ pbax_id_t l_pbaxid = dcom_pbusid2pbaxid(G_pob_id);
+
+ //SSX return codes
+ int l_rc = 0;
+
+ do
+ {
+ pbax_send_disable();
+
+ // check if conversion has valid information
+ if (( l_pbaxid.chip_id > MAX_PBAX_CHIP_ID ) || //@gm007
+ ( l_pbaxid.node_id == INVALID_NODE_ID ))
+ {
+ TRAC_ERR("Error converting pbusids to pbaxids. chip_id[0x%08x], node_id[0x%08x]",
+ l_pbaxid.chip_id, l_pbaxid.node_id);
+ l_rc = -1; //force error to be logged below. //@gm007
+ break;
+ }
+
+ l_rc = pbax_configure(G_occ_role, // master
+ l_pbaxid.node_id, // node id
+ l_pbaxid.chip_id, // chipd id
+ PBAX_CONFIGURE_RCV_GROUP_MASK); // group_mask
+
+ if(l_rc != 0)
+ {
+ TRAC_ERR("Error configuring the pbax rc[%x]",l_rc);
+ break;
+ }
+
+ //enabled pbax send does not return errors
+ pbax_send_enable();
+
+ if(G_occ_role == OCC_SLAVE)
+ {
+ // create pbax rx queue 1
+ l_rc = pbax_queue_create( &G_pbax_read_queue[1], //queue
+ ASYNC_ENGINE_PBAX_PUSH1, //engine
+ G_pbax_queue_rx1_buffer, //cq base
+ NUM_ENTRIES_PBAX_QUEUE1, //cq entries
+ PBAX_INTERRUPT_PROTOCOL_AGGRESSIVE //protocol
+ );
+
+ if(l_rc != 0)
+ {
+ TRAC_ERR("Error creating pbax queue 1 rc[%x]",l_rc);
+ break;
+ }
+
+ // create pbax rx queue o
+ l_rc = pbax_queue_create( &G_pbax_read_queue[0], //queue
+ ASYNC_ENGINE_PBAX_PUSH0, //engine
+ G_pbax_queue_rx0_buffer, //cq base
+ NUM_ENTRIES_PBAX_QUEUE0, //cq entries
+ PBAX_INTERRUPT_PROTOCOL_AGGRESSIVE //protocol
+ );
+
+ if(l_rc != 0)
+ {
+ TRAC_ERR("Error creating pbax queue 0 rc[%x]",l_rc);
+ break;
+ }
+
+ // enable the read 1 queue
+ l_rc = pbax_queue_enable(&G_pbax_read_queue[1]);
+
+ if(l_rc != 0)
+ {
+ TRAC_ERR("Error enabling queue 1 rc[%x]",l_rc);
+ break;
+ }
+
+ /// Don't enable the read 0 queue until we are ready
+ /// to listen
+ //l_rc = pbax_queue_enable(&G_pbax_read_queue[0]); // @th034
+ //if(l_rc != 0)
+ //{
+ // TRAC_ERR("Error enabling queue 0 rc[%x]",l_rc);
+ // break;
+ //}
+
+ }
+
+ if(G_occ_role == OCC_MASTER)
+ {
+ // TODO: Change this to PBAX_GROUP for Venice
+ l_rc = pbax_target_create( &G_pbax_multicast_target, // target,
+ PBAX_BROADCAST, // type
+ PBAX_SYSTEM, // scope TODO @th038
+ 0, //&pbax_read0_queue // queue
+ l_pbaxid.node_id, // node
+ PBAX_BROADCAST_GROUP); // chip_or_group
+
+ if(l_rc != 0)
+ {
+ TRAC_ERR("Error creating pbax target for master TX operations SSXrc[%x]",l_rc);
+ break;
+ }
+
+ }
+
+ }while(0);
+
+ if(l_rc)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_INIT_PBAX_QUEUES
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 SSX RC
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failure initializing the PBAX queues
+ */
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_INIT_PBAX_QUEUES, //modId
+ SSX_GENERIC_FAILURE, //reasoncode // @nh001c
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_rc, //userdata1
+ 0 //userdata2
+ );
+
+ // commit log and request reset -- @gm007
+ REQUEST_RESET(l_errl);
+ }
+}
+
+
+// Function Specification
+//
+// Name: dcom_pbusid2pbaxid
+//
+// Description: translate between powerbus ID and pbax ID
+//
+// Flow: 08/23/11 FN=dcom_pbusid2pbaxid
+//
+// End Function Specification
+pbax_id_t dcom_pbusid2pbaxid(pob_id_t i_pobid)
+{
+ pbax_id_t l_pbax_id_t = {0};
+
+ // check if chip id and nod id are valid
+ if((i_pobid.chip_id < MAX_NUM_OCC)
+ && (i_pobid.node_id < MAX_NUM_NODES))
+ {
+ l_pbax_id_t.chip_id = G_sysConfigData.pob2pbax_chip[i_pobid.chip_id];
+ l_pbax_id_t.node_id = G_sysConfigData.pob2pbax_node[i_pobid.node_id];
+ }
+ else
+ {
+ // invalid data found
+
+ l_pbax_id_t.chip_id = MAX_PBAX_CHIP_ID;
+ l_pbax_id_t.node_id = INVALID_NODE_ID;
+
+ TRAC_ERR("Invalid Powerbus ID, could NOT convert chip id[%x] and node id[%x] to PBAX id",
+ i_pobid.chip_id,i_pobid.node_id);
+ }
+
+ return l_pbax_id_t;
+}
+
+// Function Specification
+//
+// Name: dcom_error_check
+//
+// Description: keep track of failure counts
+//
+// Flow: 10/24/11 FN=dcom_error_check
+//
+// End Function Specification
+void dcom_error_check( const dcom_error_type_t i_error_type, const bool i_clear_error, const uint32_t i_orc, const uint32_t i_orc_ext) // @nh001c
+{
+ static uint16_t L_rx_slv_outbox_fail_count = 0;
+ uint16_t l_modId = 0; // @nh001a
+ uint16_t *l_count_ptr = NULL;
+
+ if ( i_error_type == SLAVE_INBOX )
+ {
+ l_count_ptr = &G_dcomSlvInboxCounter.currentFailCount;
+ l_modId = DCOM_MID_TASK_RX_SLV_INBOX; // @nh001a
+ }
+ // if the i_error_type == SLAVE_OUTBOX then set the outbox count
+ else
+ {
+ l_count_ptr = &L_rx_slv_outbox_fail_count;
+ l_modId = DCOM_MID_TASK_RX_SLV_OUTBOX; // @nh001a
+ }
+
+ if ( i_clear_error )
+ {
+ *l_count_ptr = 0;
+ }
+ else
+ {
+ (*l_count_ptr)++;
+
+ if ( *l_count_ptr == DCOM_250us_GAP )
+ {
+ // trace an imp trace log
+ TRAC_IMP("l_count_ptr[%d], L_outbox[%d], L_inbox[%d]",
+ *l_count_ptr,
+ L_rx_slv_outbox_fail_count,
+ G_dcomSlvInboxCounter.currentFailCount );
+ }
+ else if ( *l_count_ptr == DCOM_4MS_GAP )
+ {
+ // create and commit error log
+
+ // NOTE: SRC tags are NOT needed here, they are
+ // taken care of by the caller
+ errlHndl_t l_errl = createErrl(
+ l_modId, //modId // @nh001c
+ i_orc, //reasoncode
+ i_orc_ext, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ *l_count_ptr, //userdata1
+ 0 //userdata2
+ );
+
+ // commit log
+ commitErrl( &l_errl );
+
+ // call request nominal macro to change state
+ REQUEST_NOMINAL();
+ }
+ else if ( *l_count_ptr == DCOM_1S_GAP )
+ {
+ // create and commit error log
+
+ // NOTE: SRC tags are NOT needed here, they are
+ // taken care of by the caller
+ errlHndl_t l_errl = createErrl(
+ l_modId, //modId // @nh001c
+ i_orc, //reasoncode
+ i_orc_ext, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ *l_count_ptr, //userdata1
+ 0 //userdata2
+ );
+
+ // commit log
+ // call request reset macro
+ REQUEST_RESET(l_errl); //@gm006
+ }
+ }
+}
+
+
+// Function Specification
+//
+// Name: dcom_build_dcm_sync_msg
+//
+// Description: Copy messages from DCM Master (OCC Slave) to
+// DCM Slave (also OCC Slave) and vice versa
+//
+// Flow: xx/xx/xx FN=
+//
+// End Function Specification
+// @th010 - Added function dcom_build_dcm_sync_msg()
+void dcom_build_dcm_sync_msg(const dcom_error_type_t i_which_msg)
+{
+ // If the OCC Master isn't a DCM, no one else is a DCM either, so
+ // no need to bother sending these messages back & forth.
+ if(proc_is_dcm())
+ {
+ if ( i_which_msg == SLAVE_INBOX )
+ {
+ uint32_t l_slv_idx = 0;
+ for(l_slv_idx = 0; l_slv_idx < MAX_OCCS; l_slv_idx++) // @th035
+ {
+ // Populate G_dcm_sync_occfw_table with the data from all OCC Slaves
+ G_dcm_sync_occfw_table[l_slv_idx] = G_dcom_slv_outbox_rx[l_slv_idx].dcm_sync;
+ }
+
+ // DCM are always in even/odd numbered pairs sequentially as
+ // DCM master = even number[0,2,4,6] DCM Slave = odd number [1,3,5,7]
+ // with DCM pairs being [0,1], [2,3], [4,5], [6,7]
+ // so we can do this simple swizzle here and not need a table to
+ // do the conversion.
+ for(l_slv_idx = 0; l_slv_idx < MAX_OCCS; l_slv_idx+=2) // @th035
+ {
+ G_dcom_slv_inbox_tx[l_slv_idx].dcm_sync = G_dcm_sync_occfw_table[l_slv_idx+1];
+ G_dcom_slv_inbox_tx[l_slv_idx+1].dcm_sync = G_dcm_sync_occfw_table[l_slv_idx];
+ }
+ }
+ else if ( i_which_msg == SLAVE_OUTBOX )
+ {
+ G_dcom_slv_outbox_tx.dcm_sync = proc_gpsm_dcm_sync_get_state();
+ }
+ }
+}
+
+
+// Function Specification
+//
+// Name: dcom_build_occfw_msg
+//
+// Description: Copy data into occ fw msg portion
+//
+// Flow: 10/24/11 FN=dcom_build_occfw_msg
+//
+// End Function Specification
+void dcom_build_occfw_msg( const dcom_error_type_t i_which_msg )
+{
+ if ( i_which_msg == SLAVE_INBOX )
+ {
+ uint32_t l_slv_idx = 0;
+
+ // for each occ slave
+ for(; l_slv_idx < MAX_OCCS; l_slv_idx++)
+ {
+ G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox[0] = G_occ_external_req_state;
+ G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox[1] = G_occ_external_req_mode;
+
+ G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox[2] = G_master_event_flags;
+ G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox[3] = G_slave_event_flags_ack[l_slv_idx];
+
+ G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox[4] = 0;
+ }
+ }
+ else if ( i_which_msg == SLAVE_OUTBOX )
+ {
+ G_dcom_slv_outbox_tx.occ_fw_mailbox[0] = CURRENT_STATE();
+
+ // @at019a - start
+ if(G_sysConfigData.system_type.kvm )
+ {
+ G_dcom_slv_outbox_tx.occ_fw_mailbox[1] = G_occ_external_req_mode_kvm;
+ }
+ else
+ {
+ G_dcom_slv_outbox_tx.occ_fw_mailbox[1] = CURRENT_MODE();
+ }
+ // @at019a - end
+
+ G_dcom_slv_outbox_tx.occ_fw_mailbox[2] = G_master_event_flags_ack;
+ G_dcom_slv_outbox_tx.occ_fw_mailbox[3] = G_slave_event_flags;
+
+ G_dcom_slv_outbox_tx.occ_fw_mailbox[4] = SMGR_validate_get_valid_states();
+ }
+
+}
+
+
+// Function Specification
+//
+// Name: task_dcom_parse_occfwmsg
+//
+// Description: Purpose of this task is to handle and acknowledge
+// fw messages passed from Master to Slave and vice versa.
+//
+// Flow: 10-24-11 FN=task_dcom_parse_occfwmsg
+//
+// End Function Specification
+void task_dcom_parse_occfwmsg(task_t *i_self)
+{
+ if(G_occ_role == OCC_MASTER)
+ {
+ //local slave index counter
+ uint32_t l_slv_idx = 0;
+
+ //loop and collect occ data for each slave occ
+ for(; l_slv_idx < MAX_OCCS; l_slv_idx++)
+ {
+ // verify all slave are in correct state and mode
+ G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[0] = CURRENT_STATE();
+ // @at019a - start
+ if(G_sysConfigData.system_type.kvm )
+ {
+ G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[1] = G_occ_external_req_mode_kvm;
+ }
+ else
+ {
+ G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[1] = CURRENT_MODE();
+ }
+ // @at019a - end
+
+
+ // acknowledge all slave event flags
+ G_slave_event_flags_ack[l_slv_idx] = G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[3];
+
+ //Clear master event flags if slave has acknowledged them and the event has cleared
+ G_master_event_flags &= ~G_dcom_slv_outbox_rx[l_slv_idx].occ_fw_mailbox[2];
+
+ }
+
+ }//end master role check
+
+ // check if master has changed state and mode and update if changed
+ // so that we can handle it in a thread.
+ if( (G_occ_master_state != G_dcom_slv_inbox_rx.occ_fw_mailbox[0])
+ || (G_occ_master_mode != G_dcom_slv_inbox_rx.occ_fw_mailbox[1]) ) // @th025
+ {
+ if( ! isSafeStateRequested() ) // @th042
+ {
+ G_occ_master_state = G_dcom_slv_inbox_rx.occ_fw_mailbox[0];
+ G_occ_master_mode = G_dcom_slv_inbox_rx.occ_fw_mailbox[1];
+ ssx_semaphore_post(&G_dcomThreadWakeupSem); // @th025
+ }
+ }
+
+ // If we are master, we don't want to update based on
+ // the data sent to us, because it corrupts the 'golden' data
+ // If we are in standby, we don't want to update because
+ // the data may not have been set up yet, and would be set to zero.
+ if(OCC_MASTER != G_occ_role ) //gm037
+ {
+ // Update the system mode frequencies if they have changed
+ int l_mode = 0;
+ bool l_change = FALSE;
+ bool l_all_zero = TRUE;
+
+ // @at018c - start
+ // Check if all values are zero
+ for(l_mode = 0; l_mode<OCC_MODE_COUNT; l_mode++)
+ {
+ if( (0 != G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode]) )
+ {
+ l_all_zero = FALSE;
+ break;
+ }
+ }
+
+ extern data_cnfg_t * G_data_cnfg;
+ if( l_all_zero == FALSE)
+ {
+ for(l_mode =0; l_mode<OCC_MODE_COUNT; l_mode++)
+ {
+ // Don't trust a frequency of 0x0000
+ if( (0 != G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode]) )
+ {
+ if(G_sysConfigData.sys_mode_freq.table[l_mode]
+ != G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode])
+ {
+ TRAC_INFO("New Frequency for Mode %d: Old: %d MHz -> New: %d MHz",l_mode,
+ G_sysConfigData.sys_mode_freq.table[l_mode],
+ G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode]);
+
+ // Update mode frequency
+ G_sysConfigData.sys_mode_freq.table[l_mode] =
+ G_dcom_slv_inbox_rx.sys_mode_freq.table[l_mode];
+
+ l_change = TRUE;
+ }
+ }
+ }
+
+ if(l_change)
+ {
+ // Update "update count" for debug purposes
+ G_sysConfigData.sys_mode_freq.update_count =
+ G_dcom_slv_inbox_rx.sys_mode_freq.update_count;
+
+ // Change Data Request Mask to indicate we got this data
+ extern data_cnfg_t * G_data_cnfg;
+ G_data_cnfg->data_mask |= DATA_MASK_FREQ_PRESENT;
+
+ // Notify AMEC that the frequencies have changed
+ AMEC_data_change(DATA_MASK_FREQ_PRESENT);
+ }
+ }
+ else
+ {
+ // Clear Data Request Mask and data
+ G_data_cnfg->data_mask &= (~DATA_MASK_FREQ_PRESENT);
+ memset(&G_sysConfigData.sys_mode_freq.table[0], 0, sizeof(G_sysConfigData.sys_mode_freq.table));
+ }
+ // @at018c - end
+ }
+
+ // Copy mnfg parameters into g_amec structure -- gm018
+ g_amec->foverride_enable = G_dcom_slv_inbox_rx.foverride_enable;
+ g_amec->foverride = G_dcom_slv_inbox_rx.foverride;
+
+ // Copy IPS parameters sent by Master OCC
+ g_amec->slv_ips_freq_request = G_dcom_slv_inbox_rx.ips_freq_request;
+
+ // Copy DPS tunable parameters sent by Master OCC if required
+ if(G_dcom_slv_inbox_rx.tunable_param_overwrite)
+ {
+ AMEC_part_overwrite_dps_parameters();
+
+ if(G_dcom_slv_inbox_rx.tunable_param_overwrite == 1)
+ {
+ g_amec->slv_dps_param_overwrite = TRUE;
+ }
+ else
+ {
+ g_amec->slv_dps_param_overwrite = FALSE;
+ }
+ }
+
+ // Copy soft frequency boundaries sent by Master OCC
+ g_amec->part_config.part_list[0].soft_fmin = G_dcom_slv_inbox_rx.soft_fmin;
+ g_amec->part_config.part_list[0].soft_fmax = G_dcom_slv_inbox_rx.soft_fmax;
+
+ // Update DCM Sync var that will be used in thread
+ proc_gpsm_dcm_sync_update_from_mbox(&G_dcom_slv_inbox_rx.dcm_sync); // @th032
+
+ // acknowledge all masters event flags
+ G_master_event_flags_ack = G_dcom_slv_inbox_rx.occ_fw_mailbox[2];
+
+ // clear slave event flags if master has acknowledged them and the event has cleared
+ G_slave_event_flags = (G_slave_event_flags & (~(G_dcom_slv_inbox_rx.occ_fw_mailbox[3])));
+}
+
+
+#endif //_DCOM_C
+
diff --git a/src/occ/dcom/dcom.h b/src/occ/dcom/dcom.h
new file mode 100755
index 0000000..d296c2c
--- /dev/null
+++ b/src/occ/dcom/dcom.h
@@ -0,0 +1,585 @@
+/******************************************************************************
+// @file dcom.h
+// @brief OCC to OCC communication handler
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcom.h DCOM.H
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @00 tapiar 09/14/2011 Created
+ * @01 tapiar 10/04/2011 Stage 2 updates
+ * @th002 thallet 11/01/2011 Misc Changes for Nov 1st Milestone
+ * @th005 thallet 11/23/2011 Sensor Initialization Changes
+ * @02 tapiar 11/14/2011 stage 3 updates
+ * @rc001 rickylie 01/02/2012 Moved debug trace defines to trac.h
+ * @rc003 rickylie 02/03/2012 Verify & Clean Up OCC Headers & Comments
+ * @pb00E pbavari 03/11/2012 Added correct include file
+ * @nh001 neilhsu 05/23/2012 Add missing error log tags
+ * @th010 thallet 07/11/2012 Pstate Enablement
+ * @th022 thallet 10/08/2012 Removed initSection attribute
+ * @th025 857856 thallet 10/16/2012 Dcom State/Mode passing part 2
+ * @th034 879027 thallet 04/18/2013 Broadcast Critical Power Data over PBAX
+ * @th032 thallet 04/16/2013 Tuleta HW Bringup
+ * @th036 881677 thallet 04/16/2013 New Poll Command Support
+ * @th040 887069 thallet 06/11/2013 Support Nom & FFO Freq Setting for Mnfg
+ * @gs007 888247 gjsilva 06/19/2013 OCC mnfg support for frequency distribution
+ * @th044 892742 thallet 07/24/2013 Added module ID
+ * @jh005 894560 joshych 08/14/2013 Create call home data logs every 24 hours
+ * @rt001 897459 tapiar 08/19/2013 add active node pcap field to doorbell structure
+ * @gs015 905166 gjsilva 11/04/2013 Full support for IPS function
+ * @gs016 905781 gjsilva 11/12/2013 Fix for Master->Slave doorbell loss of synchronization
+ * @gs017 905990 gjsilva 11/13/2013 Full support for tunable parameters
+ * @rt004 908817 tapiar 12/11/2013 Expland slave outbox doorbell to include pcap valid
+ * field to be used by master when checking for pcap mismatches
+ * @gs020 909320 gjsilva 12/12/2013 Support for VR_FAN thermal control
+ * @mw626 mware 01/28/2013 Changed freqa250us to be freqa2ms.
+ * @gs025 913663 gjsilva 01/30/2014 Full fupport for soft frequency boundaries
+ * @gs027 918066 gjsilva 03/12/2014 Misc functions from ARL
+ * @gm037 925908 milesg 05/07/2014 Redundant OCC/APSS support
+ *
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOM_H
+#define _DCOM_H
+
+/** \defgroup OCC-OCC Communication
+ *
+ */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+//@pb00Ec - changed from common.h to occ_common.h for ODE support
+#include <occ_common.h>
+#include <common_types.h>
+#include <occ_service_codes.h>
+#include <occ_sys_config.h>
+#include <rtls.h>
+#include <apss.h>
+#include <proc_pstate.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+// Max Centaur Throttles
+#define MAX_CENTAUR_THROTTLES 8
+
+// Max Interleave Group Throttles
+#define MAX_MEM_INTERLEAVE_GROUP_THROTTLES 8
+
+// OCC roles
+#define OCC_SLAVE 0
+#define OCC_MASTER 1
+#define OCC_BACKUP_MASTER 2
+
+// OCC roles inside a DCM socket
+#define OCC_DCM_SLAVE 0
+#define OCC_DCM_MASTER 1
+
+// OCC Master to Slave Messages (inbox ping/pong) - Need to go over BAR3
+#define ADDR_SLAVE_INBOX_MAIN_MEM_PING 0x30000000 // @th032
+#define ADDR_SLAVE_INBOX_MAIN_MEM_PONG 0x30000800 // @th032
+#define NUM_BYTES_IN_SLAVE_INBOX 256
+
+// Magic Number used to denote the end of Master->Slave Broadcast packets
+#define PBAX_MAGIC_NUMBER_32B 0x00123181 // @th034
+// Magic Number used to denote the start of Master->Slave Broadcast packets
+#define PBAX_MAGIC_NUMBER2_32B 0x00474A53
+
+#define MAX_PBAX_CHIP_ID 7
+#define INVALID_NODE_ID 7
+
+// OCC Slave to Master Messages (inbox ping/pong) - Need to go over BAR3
+#define ADDR_SLAVE_OUTBOX_MAIN_MEM_PING 0x30001000 // @th032
+#define ADDR_SLAVE_OUTBOX_MAIN_MEM_PONG 0x30003000 // @th032
+#define NUM_BYTES_IN_SLAVE_OUTBOX 1024
+
+// GP REG0
+#define TP_BRIDGE_GP_REG0 0x01000000
+
+// GP0 Read Chip Id Mask & Offset
+#define GP0_READ_CHIP_ID_MASK 0x00000000001C0000
+#define CHIP_ID_MASK_OFFSET 18
+
+// GP0 Read Node Id Mask & Offset
+#define GP0_READ_NODE_ID_MASK 0x0000000000E00000
+#define NODE_ID_MASK_OFFSET 21
+
+// What should these sizes be?
+#define NUM_ENTRIES_PBAX_QUEUE0 32 // @th034
+#define NUM_ENTRIES_PBAX_QUEUE1 16 // @th034
+
+// Wait for defines number of retries for task
+#define MAX_WAIT_FOR_SLAVES 400
+#define MAX_WAIT_FOR_MASTER 400
+
+// general defines
+#define TOD_SIZE 6
+#define NUM_TOD_SENSORS 3
+#define SLV_INBOX_RSV_SIZE 88
+#define SLV_MAILBOX_SIZE 32
+#define SLV_OUTBOX_RSV_SIZE 758
+#define DOORBELL_RSV_SIZE 1 // @rt001c
+
+#define DCOM_250us_GAP 1
+#define DCOM_4MS_GAP 8
+#define DCOM_1S_GAP 4000
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+// POB Id structure
+typedef struct
+{
+ uint8_t module_id :2;
+ uint8_t node_id :3;
+ uint8_t chip_id :3;
+} pob_id_t;
+
+
+// TODO may change in the future
+// for now pbax structure is same as pob id structure
+typedef pob_id_t pbax_id_t;
+
+
+// SLAVE INBOX structure
+typedef struct
+{
+ // Packet Type & Sequence Information
+ uint8_t seq; // [0]
+ uint8_t version; // [1]
+
+ // From APSS Power Measurement
+ uint16_t adc[MAX_APSS_ADC_CHANNELS]; // [2] - 32 bytes
+ uint16_t gpio[MAX_APSS_GPIO_PORTS]; // [34] - 4 bytes
+ uint16_t ambient_temp; // [38] - 2 bytes
+ uint16_t altitude; // [40] - 2 bytes
+ uint8_t tod[ TOD_SIZE ]; // [42] - 6 bytes
+
+ // AMEC Actuators
+ uint16_t freq250usp0cy[MAX_CORES]; // [48] - 24 bytes
+ uint16_t memsp2msP0MxCyPz[MAX_CENTAUR_THROTTLES]; // [72] - 16 bytes
+ uint16_t memsp2msP0IGx[MAX_MEM_INTERLEAVE_GROUP_THROTTLES]; // [88] - 16 bytes
+
+ // Manufacturing parameters
+ uint16_t foverride; // [104] - 2 bytes
+ uint8_t foverride_enable; // [106] - 1 byte
+ uint8_t emulate_oversub; // [107] - 1 byte
+
+ // Idle Power Saver parameters
+ uint16_t ips_freq_request; // [108] - 2 bytes
+
+ // DPS Tunable Parameters
+ uint16_t alpha_up; // [110] - 2 bytes
+ uint16_t alpha_down; // [112] - 2 bytes
+ uint16_t sample_count_util; // [114] - 2 bytes
+ uint16_t step_up; // [116] - 2 bytes
+ uint16_t step_down; // [118] - 2 bytes
+ uint16_t epsilon_perc; // [120] - 2 bytes
+ uint16_t tlutil; // [122] - 2 bytes
+ uint8_t tunable_param_overwrite; // [124] - 1 byte
+
+ // Soft frequency boundaries
+ uint16_t soft_fmin; // [125] - 2 bytes
+ uint8_t pad; // [127] - 1 bytes
+ uint16_t soft_fmax; // [128] - 2 bytes
+
+
+ // Reserved Bytes
+ union
+ {
+ struct
+ {
+ uint32_t counter; // @th002
+ freqConfig_t sys_mode_freq; // @th040
+ uint8_t tb_record;
+ };
+ uint8_t reserved[ SLV_INBOX_RSV_SIZE ]; // [130] - 88 bytes
+ };
+
+ // GPSM DCM Synchronization
+ proc_gpsm_dcm_sync_occfw_t dcm_sync; // @th010 // [220] - 4 bytes
+
+ // General Firmware Message Passing
+ uint8_t occ_fw_mailbox[ SLV_MAILBOX_SIZE ]; // [224] - 32 bytes
+
+} dcom_slv_inbox_t __attribute ((aligned (128)));
+
+
+
+// SLAVE OUTBOX structure
+typedef struct __attribute__ ((packed))
+{
+ // Packet Type & Sequence Information
+ uint8_t seq; // [0]
+ uint8_t version; // [1]
+
+ // Mini-sensors
+ uint16_t freqa2msp0; // [2] // @mw626
+ uint16_t ips2msp0cy[MAX_CORES]; // [4]
+ uint16_t mcpifd2msp0cy[MAX_CORES]; // [28]
+ uint16_t mcpifi2msp0cy[MAX_CORES]; // [52]
+ uint16_t memsp2msp0mx[MAX_NUM_MEM_CONTROLLERS]; // [76]
+ uint16_t pwr250usp0; // [92]
+ uint16_t pwr250usmemp0; // [94]
+ uint16_t sleepcnt2msp0; // [96]
+ uint16_t winkcnt2msp0; // [98]
+ uint16_t temp2msp0; // [100]
+ uint16_t temp2msp0peak; // [102]
+ uint16_t util2msp0cy[MAX_CORES]; // [104]
+ uint16_t vrfan250usmem; // [128]
+ uint16_t vrfan250usproc; // [130]
+ uint16_t mrd2msp0mx[MAX_NUM_MEM_CONTROLLERS]; // [132]
+ uint16_t mwr2msp0mx[MAX_NUM_MEM_CONTROLLERS]; // [148]
+ uint16_t pwrpx250usp0cy[MAX_CORES]; // [164]
+ uint16_t todclock[NUM_TOD_SENSORS]; // [188]
+ uint16_t temp2mscent; // [194] // @jh005a
+ uint16_t temp2msdimm; // [196] // @jh005a
+ uint16_t util2msp0; // [198] // @jh005a
+ uint16_t ips2msp0; // [200] // @jh005a
+ uint16_t nutil3sp0cy[MAX_CORES]; // [202] - 24 bytes
+
+ // Fwish (i.e., desired frequency that this OCC slave wants based on DPS
+ // algorithms)
+ uint16_t fwish; // [226] - 2 bytes
+ // Factual (i.e., actual frequency requested by this OCC slave)
+ uint16_t factual; // [228] - 2 bytes
+
+ // Reserved Bytes
+ union
+ {
+ uint8_t reserved[SLV_OUTBOX_RSV_SIZE]; // [230] - 758 bytes
+ struct __attribute__ ((packed))
+ {
+ uint8_t _reserved_1;
+ uint8_t _reserved_2;
+ uint32_t counter;
+ };
+ }; // @th002
+
+ // GPSM DCM Synchronization
+ proc_gpsm_dcm_sync_occfw_t dcm_sync; // [988] - 4 bytes
+
+ // General Firmware Message Passing
+ uint8_t occ_fw_mailbox[SLV_MAILBOX_SIZE]; // [992] - 32 bytes
+} dcom_slv_outbox_t __attribute__ ((aligned (128)));
+
+
+// Slave Inbox Doorbell
+// This must be aligned to 8 bytes since that is the unit
+// that the PBAX unit uses to send
+typedef struct
+{
+ union
+ {
+ struct
+ {
+ /// PowerBus ID so that the slave knows who the master is
+ pob_id_t pob_id; // 1 byte
+ /// Magic Number denoting the start of the packet
+ uint32_t magic1 :24; // 3 bytes
+ /// OCI Address where the Slave Inbox Buffer was placed
+ uint32_t addr_slv_inbox_buffer0; // 4 bytes
+ /// PowerCap data sent from master to slaves
+ pcap_config_data_t pcap; // 14 bytes
+ /// PowerPreservingBoundry Fmax to throttle all OCCs the same
+ uint16_t ppb_fmax; // 2 bytes
+ /// GPIO pins from APSS
+ uint16_t gpio[2]; // 4 bytes
+ /// Raw ADC Channels from APSS
+ uint16_t adc[MAX_APSS_ADC_CHANNELS]; // 32 bytes
+ /// Reserved
+ uint8_t _reserved_0[4]; // 4 bytes
+ /// Time of Day Clock from the last APSS reading
+ uint64_t tod; // 8 bytes
+ /// Reserved
+ uint8_t _reserved_1[52]; // 52 bytes
+ /// Counter in case we want to determine sequence errors
+ uint8_t magic_counter; // 1 byte
+ /// Magic Number for denoting the end of the packet
+ uint32_t magic2 :24; // 3 bytes
+ }; // --------
+ uint64_t words[16]; // Total = 128 bytes
+ };
+} __attribute__ ((packed)) dcom_slv_inbox_doorbell_t; // @th034
+
+
+// Slave Outbox Doorbell
+typedef struct
+{
+ pob_id_t pob_id;
+ uint8_t pcap_valid; //@rt004a
+ uint16_t active_node_pcap; //@rt001a
+ uint32_t addr_slv_outbox_buffer;
+} __attribute__ ((packed)) dcom_slv_outbox_doorbell_t;
+
+typedef enum
+{
+ SLAVE_INBOX = 0,
+ SLAVE_OUTBOX
+
+} dcom_error_type_t;
+
+typedef struct
+{
+ uint32_t totalTicks;
+ uint32_t totalSuccessful;
+ uint16_t currentFailCount;
+} dcom_fail_count_t;
+
+typedef struct
+{
+ /// Mask denoting if OCC is currently responding
+ uint8_t alive;
+ /// Mask denoting if OCC has responded in the past, but stopped
+ uint8_t zombie;
+ /// Mask denoting if OCC has never responded
+ uint8_t dead;
+} dcom_present_mask_t; // @th025
+
+// DCOM Timing / Statistics
+// This is a DEBUG ONLY structure that is only used to measure certain
+// characteristics of the distributed communication mechanism.
+// It may be removed at any time without warning.
+//
+// For Reference:
+// Phase(degrees) = (((SsxTimebase % 250us) / 250us) * 360 degrees)
+typedef struct
+{
+ /// Master Only Statistics
+ struct
+ {
+ /// Start Time of the Most Recent Master Doorbell Broadcast
+ SsxTimebase doorbellStartTx;
+ /// Stop Time of the Most Recent Master Doorbell Broadcast
+ SsxTimebase doorbellStopTx;
+ /// The longest it has even taken to send the Master Doorbell Broadcast
+ SsxTimebase doorbellMaxDeltaTx;
+ /// How many Master Doorbell Broadcasts have been sent
+ uint32_t doorbellNumSent;
+ /// What is our "send" phase in relation to our SsxTimebase
+ uint16_t doorbellPhase;
+ /// The Most Recent Master Doorbell Broadcast sequence number
+ uint8_t doorbellSeq;
+ /// Masks of the current status of the slaves
+ dcom_present_mask_t allOccStatusMask; // @th036
+ } master;
+
+ /// Slave Statistics
+ struct
+ {
+ /// Start Time of the Most Recent Wait for Master Doorbell
+ SsxTimebase doorbellStartWaitRx;
+ /// Successful Stop Time of the Most Recent Wait for Master Doorbell
+ SsxTimebase doorbellStopWaitRx;
+ /// Timeout Stop Time of the Most Recent Wait for Master Doorbell
+ SsxTimebase doorbellTimeoutWaitRx;
+ /// The longest it has ever taken us to receive Master Doorbell
+ SsxTimebase doorbellMaxDeltaWaitRx;
+ /// Start Time of the Most Recent Slave Doorbell sent to Master
+ SsxTimebase doorbellStartRx;
+ /// Stop Time of the Most Recent Slave Doorbell sent to Master
+ SsxTimebase doorbellStopRx;
+ /// The longest it has ever taken us to send Slave Doorbell
+ SsxTimebase doorbellMaxDeltaRx;
+ /// How many Master Doorbell Broadcasts have we received
+ uint32_t doorbellNumRx;
+ /// How many Master Doorbell Broadcasts have we received via wait4master
+ uint32_t doorbellNumWaitRx;
+ /// "Receive Phase" of Master Doorbell in relation to our SsxTimebase
+ uint16_t doorbellPhase;
+ /// Most Recent Sequence number received from Master Doorbell
+ uint8_t doorbellSeq;
+ /// Error Flags for receiving Master Doorbell (never cleared)
+ struct
+ {
+ uint8_t timeout :1;
+ uint8_t incomplete :1;
+ uint8_t badSequence :1;
+ uint8_t badMagicNumEnd :1;
+ uint8_t dropPacket :1;
+ uint8_t hwError :1;
+ uint8_t timeoutRx :1;
+ } doorbellErrorFlags;
+ } slave;
+
+ /// General Timing
+ /// Used to calculate the difference between the SsxTimebase and the TOD,
+ /// to correlate between multiple OCCs.
+ SsxTimebase base;
+ uint64_t tod;
+
+} dcom_timing_t; // @th032
+extern dcom_timing_t G_dcomTime; // @th032
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+// Used to tell AMEC code that the slave inbox has been received.
+// This could just be a flag, doesn't have to be semaphore, since
+// the RTL Loop task can't block on Semaphore, it would just have
+// to loop until it got a good return code.
+//SsxSemaphore G_sem_slv_inbox;
+extern bool G_slv_inbox_received;
+
+// Used to tell AMEC code that the slave outbox has been received.
+// This could just be a flag, doesn't have to be semaphore, since
+// the RTL Loop task can't block on Semaphore, it would just have
+// to loop until it got a good return code.
+extern uint8_t G_slv_outbox_complete;
+
+// Specifies if the OCC is a MASTER or SLAVE
+extern uint8_t G_occ_role;
+
+// Specifies if the OCC is configured to be a Master or Slave inside the DCM
+// chip. In the case of SCMs, it will always return the Master role.
+extern uint8_t G_dcm_occ_role;
+
+// Holds PowerBus ID of this OCC (Chip & node). From this we can determine OCC ID
+// and PBAX ID.
+extern pob_id_t G_pob_id;
+
+// PBAX 'Target' Structure (Register Abstraction) that has the data needed for
+// a multicast operation.
+extern PbaxTarget G_pbax_multicast_target;
+
+// PBAX 'Target' Structure (Register Abstraction) that has the data needed for
+// a unicast operation from the OCC Slave to the OCC Master.
+extern PbaxTarget G_pbax_unicast_target;
+
+//Number of occ's that *should* be present
+extern uint8_t G_occ_num_present; // @th025
+
+// master/slave event flags
+extern uint32_t G_master_event_flags;
+extern uint32_t G_slave_event_flags;
+extern uint32_t G_master_event_flags_ack;
+extern uint32_t G_slave_event_flags_ack[MAX_OCCS];
+
+extern dcom_fail_count_t G_dcomSlvInboxCounter;
+
+extern SsxSemaphore G_dcomThreadWakeupSem;
+
+// =========================================================
+// Master Only
+// =========================================================
+
+// Used to house the actuation & power measurement data from the master
+// before it is DMA'd to Main Memory from SRAM.
+//DMA_BUFFER(extern dcom_slv_inbox_t G_dcom_slv_inbox_tx[MAX_OCCS]);
+extern dcom_slv_inbox_t G_dcom_slv_inbox_tx[MAX_OCCS];
+
+// Used to house the Slave Outboxes with the mini-sensor data in in the master
+// after it is DMA'd from main memory.
+extern dcom_slv_outbox_t G_dcom_slv_outbox_rx[MAX_OCCS];
+
+
+// =========================================================
+// Master & Slave
+// =========================================================
+
+// Used to house the actuation & power measurement data coming from the master
+// after it is DMA'd from Main Memory to SRAM.
+extern dcom_slv_inbox_t G_dcom_slv_inbox_rx;
+
+// Used to house the Slave Outboxes with the mini-sensor data in the slave
+// before it is DMA'd to main memory.
+//DMA_BUFFER(extern dcom_slv_outbox_t G_dcom_slv_outbox_tx); // Slave
+extern dcom_slv_outbox_t G_dcom_slv_outbox_tx; // Slave
+
+// Used to house the pcap & power measurement data coming from the master
+// in a more reliable way than Main Memory
+extern dcom_slv_inbox_doorbell_t G_dcom_slv_inbox_doorbell_rx;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//check if slave inbox is valid, or if we are having errors
+bool isDcomSlvInboxValid(void);
+
+// copy data into slave inbox for use by master
+uint32_t dcom_build_slv_inbox(void);
+
+// fill out sensor data from slave to master
+uint32_t dcom_build_slv_outbox(void);
+
+// switch between ping pong buffers
+uint32_t dcom_which_buffer(void);
+
+// switch between ping pong buffers
+uint32_t dcom_which_buffer_slv_outbox(void);
+
+// get address of slave inbox in main memory
+uint32_t dcom_calc_slv_inbox_addr(void);
+
+// get address of slave outbox in main memory
+uint32_t dcom_calc_slv_outbox_addr( const dcom_slv_outbox_doorbell_t * i_doorbell, uint8_t * o_occ_id);
+
+// determine if we are master or slave
+void dcom_initialize_roles(void) INIT_SECTION;
+
+// copy slave inbox from main memory to sram
+void task_dcom_rx_slv_inbox(task_t *i_self);
+
+// copy slave outboxes from main memory to sram
+void task_dcom_rx_slv_outboxes(task_t *i_self);
+
+// copy slave inboxes from sram to main memory
+void task_dcom_tx_slv_inbox(task_t *i_self);
+
+// copy slave outboxes from sram to main memory
+void task_dcom_tx_slv_outbox(task_t *i_self);
+
+// initialize the pbax queues
+void dcom_initialize_pbax_queues(void);
+
+// translate pids to pbax ids
+pbax_id_t dcom_pbusid2pbaxid(pob_id_t i_pobid);
+
+// receive multicast doorbell
+uint32_t dcom_rx_slv_inbox_doorbell( void );
+
+// receive unicast doorbell
+uint32_t dcom_rx_slv_outbox_doorbell( void );
+
+// send multicast doorbells to slaves
+void dcom_tx_slv_inbox_doorbell( void );
+
+// send unicast doorbells to master
+void dcom_tx_slv_outbox_doorbell( void );
+
+//task to wait for the master multicast doorbell
+void task_dcom_wait_for_master( task_t *i_self);
+
+// keep track of failure counts
+#define dcom_error_check_reset(_e_) dcom_error_check( _e_, TRUE, OCC_SUCCESS_REASON_CODE, OCC_NO_EXTENDED_RC) // @nh001c
+void dcom_error_check( dcom_error_type_t i_error_type, bool i_clear_error, uint32_t i_orc , const uint32_t i_orc_ext); // @nh001c
+
+//task to parse occ firmware messages
+void task_dcom_parse_occfwmsg(task_t *i_self);
+
+// copy occ fw msg
+void dcom_build_occfw_msg( dcom_error_type_t i_which_msg );
+
+// Copy OCC DCM Sync Messages
+void dcom_build_dcm_sync_msg(const dcom_error_type_t i_which_msg); // @th010
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+#endif //_DCOM_H
diff --git a/src/occ/dcom/dcomMasterRx.c b/src/occ/dcom/dcomMasterRx.c
new file mode 100644
index 0000000..8ff632a
--- /dev/null
+++ b/src/occ/dcom/dcomMasterRx.c
@@ -0,0 +1,430 @@
+/******************************************************************************
+// @file dcomMasterRx.c
+// @brief Slave OCC to Master OCC communication handler
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcomMasterRx.c DCOMMASTERRX.C
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @th023 thallet 10/08/2012 Moved Master RX function here
+ * @th025 857856 thallet 10/16/2012 Dcom Master Slave SMS part 2
+ * @th036 881677 thallet 05/09/2013 New Poll Command Support
+ * @rt001 897459 tapiar 08/19/2013 Upd: read active node pcaps from doorbell
+ * @rt004 908817 tapiar 12/11/2013 Save off slave pcap information, pcap & pcap valid field
+ * @sb003 908290 sbroyles 12/18/2013 Test BCE request states
+ * @sb013 911625 sbroyles 01/15/2014 Fix to 908290 changes
+ * @wb003 920760 wilbryan 03/25/2014 Update SRCs to match TPMD SRCs
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOMMASTERRX_C
+#define _DCOMMASTERRX_C
+
+/** \defgroup Slave to Master Communication
+ *
+ */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <pgp_pmc.h>
+#include "pgp_pba.h"
+#include <rtls.h>
+#include <apss.h>
+#include <dcom.h>
+#include <dcom_service_codes.h>
+#include <occ_service_codes.h>
+#include <trac.h>
+#include <proc_pstate.h>
+#include <amec_master_smh.h> // @rt001a
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//
+uint8_t G_slv_outbox_complete = 0;
+
+// SSX Block Copy Request for the Slave Outbox Receive Queue
+BceRequest G_slv_outbox_rx_pba_request[MAX_OCCS];
+
+// Used by the master to house the doorbell data that is received from
+// the slave unicast doorbells from each slave, stating that it put its slave
+// outbox in main memory.
+dcom_slv_outbox_doorbell_t G_dcom_slv_outbox_doorbell_rx[MAX_OCCS];
+
+// Make sure that the Slave Outbox RX Buffer is 1kB / OCC, otherwise cause
+// error on the compile.
+STATIC_ASSERT( (NUM_BYTES_IN_SLAVE_OUTBOX != (sizeof(G_dcom_slv_outbox_rx)/MAX_OCCS)) );
+
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: setbit_slvoutbox_complete
+//
+// Description: Helper function to set bit when outbox is complete
+//
+// Flow: 09/21/11 FN=setbit_slvoutbox_complete
+//
+// End Function Specification
+void setbit_slvoutbox_complete(uint8_t i_bit)
+{
+ if(i_bit < MAX_NUM_OCC)
+ {
+ G_slv_outbox_complete |= (1 << i_bit);
+ }
+}
+
+
+// Function Specification
+//
+// Name: task_dcom_rx_slv_outboxes
+//
+// Description: Copy Slave outboxes from Main Memory to SRAM
+// on master
+//
+// Flow: 09/21/11 FN=task_dcom_rx_slv_outboxes
+//
+// Task Flags: RTL_FLAG_OBS, RTL_FLAG_ACTIVE, RTL_FLAG_MSTR,
+// RTL_FLAG_NOAPSS, RTL_FLAG_RUN
+//
+// End Function Specification
+void task_dcom_rx_slv_outboxes( task_t *i_self)
+{
+ static uint32_t L_wait4slaves = 0;
+ uint32_t l_orc = OCC_SUCCESS_REASON_CODE;
+ uint32_t l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ uint8_t l_slv_response_mask = 0; // @th025
+ // @sb003 Use a static local bool to track whether the BCE request used
+ // here has ever been successfully created at least once
+ static bool L_bce_slv_outbox_rx_request_created_once[MAX_OCCS] = {FALSE,};
+
+ DCOM_DBG("2. RX Slave Outboxes\n");
+
+ do
+ {
+ // doorbell from the slave
+ uint32_t l_num_doorbells_rxd = dcom_rx_slv_outbox_doorbell();
+
+ // how many doorbells were received?
+ if( l_num_doorbells_rxd < G_occ_num_present ) // @th025
+ {
+ if ( L_wait4slaves > MAX_WAIT_FOR_SLAVES )
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_OUTBOX
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_GENERIC_TIMEOUT
+ * @devdesc Generic timeout failure
+ */
+ TRAC_ERR("Time out waiting for slaves" );
+ l_orc = INTERNAL_FAILURE; // @nh001c
+ l_orc_ext = ERC_GENERIC_TIMEOUT; // @nh001a
+ break;
+ }
+
+ L_wait4slaves++;
+ }
+
+ uint32_t l_slv_idx = 0;
+
+ //loop through all doorbells received
+ for(; l_slv_idx < l_num_doorbells_rxd; l_slv_idx++)
+ {
+ // index/occ id
+ uint8_t l_slv = 0;
+
+ // main memory address
+ uint32_t l_addr = dcom_calc_slv_outbox_addr( &G_dcom_slv_outbox_doorbell_rx[l_slv_idx], &l_slv);
+
+ G_slave_active_pcaps[l_slv].active_pcap = G_dcom_slv_outbox_doorbell_rx[l_slv_idx].active_node_pcap; //@rt001a rt004c
+ G_slave_active_pcaps[l_slv].pcap_valid = G_dcom_slv_outbox_doorbell_rx[l_slv_idx].pcap_valid; //@rt004a
+
+ // Add slave to mask of responding slaves
+ l_slv_response_mask |= (0x01 << l_slv); // @th025
+
+ //check valid address (should be inside inbox addresses range)
+ if ( (ADDR_SLAVE_OUTBOX_MAIN_MEM_PING <= l_addr) &&
+ ((ADDR_SLAVE_OUTBOX_MAIN_MEM_PONG+(sizeof(dcom_slv_outbox_t)*MAX_OCCS)) > l_addr) )
+ {
+ DCOM_DBG("2.X. Copy down Slave Outboxes from %x\n",l_addr);
+ uint32_t l_ssxrc = 0;
+
+ // @sb003
+ // Using a global bce request requires some special consideration
+ // of the possible request states. Note that since this task
+ // runs in the critical section of the RTL tick that external
+ // non-critical interrupts are disabled. This includes the PIT
+ // interrupt from the OCB timer used to generate the interrupt
+ // that runs the RTL tick code which led us here. The point is
+ // that this code cannot be re-entrant which implies that if a
+ // request is created without error then it will also be
+ // scheduled before this task runs again. In the good path we
+ // can never get here and have a BCE request that was not yet
+ // scheduled.
+ // There are four possible request states:
+ // 1. request is idle and complete: The request was created
+ // and scheduled and has completed without error.
+ // 2. request is idle and not complete: The request was created
+ // and scheduled but was either canceled, killed or has errored
+ // out, or there was an error scheduling the request.
+ // 3. request is not idle and not complete: The request was
+ // created and scheduled but is still in progress or still
+ // enqueued. Note that there is a special case here where this
+ // could also mean that this is the first time we are running
+ // this task so the global request is uninitialized. It could
+ // also mean there was an error creating the request (unlikely)
+ // so it was never scheduled.
+ // 4. request is not idle and complete: This can't happen.
+ //
+ bool l_proceed_with_request_and_schedule = FALSE;
+ int l_req_idle = async_request_is_idle(&(G_slv_outbox_rx_pba_request[l_slv].request));
+ int l_req_complete = async_request_completed(&(G_slv_outbox_rx_pba_request[l_slv].request));
+
+ if (!L_bce_slv_outbox_rx_request_created_once[l_slv])
+ {
+ // Do this case first, all other cases assume that this is
+ // true!
+ // This is the first time we have created a request so
+ // always proceed with request create and schedule
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && l_req_complete)
+ {
+ // Most likely case first. The request was created
+ // and scheduled and has completed without error. Proceed.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && !l_req_complete)
+ {
+ // There was an error on the schedule request or the request
+ // was scheduled but was canceled, killed or errored out.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv outbox rx request idle but not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_outbox_rx_pba_request[l_slv].request.callback_rc,
+ G_slv_outbox_rx_pba_request[l_slv].request.options,
+ G_slv_outbox_rx_pba_request[l_slv].request.state,
+ G_slv_outbox_rx_pba_request[l_slv].request.abort_state,
+ G_slv_outbox_rx_pba_request[l_slv].request.completion_state);
+ TRAC_INFO("Proceeding with BCE slv outbox rx request and schedule");
+ }
+ else if (!l_req_idle && !l_req_complete)
+ {
+ // The request was created and scheduled but is still in
+ // progress or still enqueued OR there was some error
+ // creating the request so it was never scheduled. The latter
+ // case is unlikely and will generate an error message when
+ // it occurs. It will also have to happen after the request
+ // was created at least once or we'll never get here. If the
+ // request does fail though before the state parms in the
+ // request are reset (like a bad parameter error), then this
+ // represents a hang condition that we can't recover from.
+ // DO NOT proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = FALSE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv outbox rx request not idle and not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_outbox_rx_pba_request[l_slv].request.callback_rc,
+ G_slv_outbox_rx_pba_request[l_slv].request.options,
+ G_slv_outbox_rx_pba_request[l_slv].request.state,
+ G_slv_outbox_rx_pba_request[l_slv].request.abort_state,
+ G_slv_outbox_rx_pba_request[l_slv].request.completion_state);
+ TRAC_INFO("NOT proceeding with BCE slv outbox rx request and schedule");
+ }
+ // else {// This case can't happen, ignore it.}
+
+ // @sb003 Only proceed if the BCE request state checked out
+ if (l_proceed_with_request_and_schedule)
+ {
+ // copy request from main memory to SRAM
+ l_ssxrc = bce_request_create(
+ &G_slv_outbox_rx_pba_request[l_slv], // block copy object
+ &G_pba_bcde_queue, // mainstore to sram copy engine
+ l_addr, // mainstore address
+ (uint32_t)&G_dcom_slv_outbox_rx[l_slv], // sram starting address
+ sizeof(dcom_slv_outbox_t), // size of copy
+ SSX_WAIT_FOREVER, // no timeout
+ (AsyncRequestCallback)setbit_slvoutbox_complete, // call back
+ &l_slv, // call back arguments
+ ASYNC_CALLBACK_IMMEDIATE // blocking request
+ );
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_OUTBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request create failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_CREATE_FAILURE; // @nh001a
+ break;
+ }
+
+ // @sb003 Request created at least once
+ L_bce_slv_outbox_rx_request_created_once[l_slv] = TRUE; // @sb013
+ l_ssxrc = bce_request_schedule(&G_slv_outbox_rx_pba_request[l_slv]); // actual copying
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_OUTBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request schedule failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_SCHEDULE_FAILURE; // @nh001a
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_OUTBOX
+ * @reasoncode INTERNAL_INVALID_INPUT_DATA
+ * @userdata1 N/A
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Memory related failure
+ */
+ TRAC_ERR("Invalid address from calculate slave inbox address function [%08X]", l_addr );
+ l_orc = INTERNAL_INVALID_INPUT_DATA; // @wb003
+ l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ break;
+ }
+ }
+
+ L_wait4slaves = 0;
+ }
+ while( 0 );
+
+ // Update the number of OCCs only if there is a new one that showed up
+ if((G_sysConfigData.is_occ_present | l_slv_response_mask) != G_sysConfigData.is_occ_present)
+ {
+ uint8_t l_temp = G_sysConfigData.is_occ_present;
+
+ // Update the mask that stores which OCCs we know are present because they
+ // are responding to master OCC (via doorbell). Only set, never clear.
+ // i.e. Don't remove the old ones. This is what is reported to TMGT
+ G_sysConfigData.is_occ_present |= l_slv_response_mask; // @th036
+
+ // Since we changed the mask, also update which ones are present.
+ G_occ_num_present = __builtin_popcount(G_sysConfigData.is_occ_present);
+ TRAC_IMP("Updated OCCs Present -- OldMask: 0x%02x, NewMask: 0x%02x",
+ l_temp,
+ G_sysConfigData.is_occ_present);
+ }
+
+
+
+ //<DEBUG>
+ // Activly responding to master
+ G_dcomTime.master.allOccStatusMask.alive = l_slv_response_mask; // @th036
+ // Was here, but stopped responding to master
+ G_dcomTime.master.allOccStatusMask.zombie =
+ ( G_sysConfigData.is_occ_present & ~l_slv_response_mask ); // @th036
+ // Has never been here or has never responded
+ G_dcomTime.master.allOccStatusMask.dead = ~G_sysConfigData.is_occ_present; // @th036
+ //</DEBUG>
+
+ if ( l_orc != OCC_SUCCESS_REASON_CODE )
+ {
+ // create and commit error
+ dcom_error_check( SLAVE_OUTBOX, FALSE, l_orc, l_orc_ext);
+ }
+ else
+ {
+ // done, lets clear our counter
+ dcom_error_check_reset( SLAVE_OUTBOX );
+ }
+
+}
+
+
+// Function Specification
+//
+// Name: dcom_rx_slv_outbox_doorbell
+//
+// Description: receive unicast doorbell and save data
+// from slave (slave to master)
+//
+// Flow: 09/22/11 FN=dcom_rx_slv_outbox_doorbell
+//
+// End Function Specification
+uint32_t dcom_rx_slv_outbox_doorbell( void )
+{
+ static bool l_error = FALSE;
+ int l_pbarc = 0;
+ uint32_t l_read = 0;
+
+ // grab doorbells from slave
+ l_pbarc = pbax_read(
+ &G_pbax_read_queue[1],
+ &G_dcom_slv_outbox_doorbell_rx[0],
+ sizeof(dcom_slv_outbox_doorbell_t)*MAX_OCCS,
+ &l_read
+ );
+
+ if ( l_pbarc != 0 && l_error == FALSE )
+ {
+ // failure occurred but only trace it once
+ TRAC_ERR("PBAX Read Failure in receiving unicast doorbell - RC[%08X]", l_pbarc);
+
+ l_error = TRUE;
+ }
+ else
+ {
+ l_error = FALSE;
+ }
+ // return the number of doorbells read by dividing the bytes read by the number of occs slaves
+ return (l_read/sizeof(dcom_slv_outbox_doorbell_t));
+}
+
+
+#endif // DCOMMASTERRX_C
+
diff --git a/src/occ/dcom/dcomMasterTx.c b/src/occ/dcom/dcomMasterTx.c
new file mode 100755
index 0000000..d0efa5a
--- /dev/null
+++ b/src/occ/dcom/dcomMasterTx.c
@@ -0,0 +1,628 @@
+/******************************************************************************
+// @file dcomMasterToSlave.c
+// @brief Master OCC to Slave OCC communication handler
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcomMasterToSlave.c DCOMMASTERTOSLAVE.C
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @00 abagepa 10/10/2011 Created
+ * @th002 thallet 11/01/2011 Misc Changes for Nov 1st Milestone
+ * @pb00A pbavari 11/15/2011 Set G_ApssPwrMeasCompleted to TRUE
+ * for SVN SIMICS
+ * @th005 thallet 11/01/2011 Added STATIC_ASSERT checks
+ * @01 tapiar 11/12/2011 Stage 3 updates
+ * @rc003 rickylie 02/03/2012 Verify & Clean Up OCC Headers & Comments
+ * @nh001 neilhsu 05/23/2012 Add missing error log tags
+ * @th010 thallet 07/11/2012 Pstate Enablement
+ * @th022 thallet 10/08/2012 Moved CNFG Data commands to diff file
+ * @ly003 861535 lychen 11/19/2012 Remove APSS configuration/gathering of Altitude & Temperature
+ * @th034 879027 thallet 04/18/2013 Broadcast Power Data over PBAX
+ * @at013 878755 alvinwan 04/17/2013 OCC power capping implementation
+ * @th032 thallet 04/16/2013 Tuleta HW Bringup
+ * @th040 887069 thallet 06/11/2013 Support Nom & FFO Freq Setting for Mnfg
+ * @fk001 879727 fmkassem 04/16/2013 OCC powercap support.
+ * @gs007 888247 gjsilva 06/19/2013 OCC mnfg support for frequency distribution
+ * @gs015 905166 gjsilva 11/04/2013 Full support for IPS function
+ * @gs016 905781 gjsilva 11/12/2013 Fix for Master->Slave doorbell loss of synchronization
+ * @gs017 905990 gjsilva 11/13/2013 Full support for tunable parameters
+ * @rt004 905638 tapiar 11/13/2013 Tunable parameters
+ * @gm014 907707 milesg 12/05/2013 don't panic on pbax_send timeout failures
+ * @jh00a 909791 joshych 12/16/2013 Enhance APSS pwr meas trace
+ * @sb003 908290 sbroyles 12/18/2013 Test BCE request states
+ * @jh00b 910184 joshych 01/10/2014 Add check for checkstop
+ * @sb013 911625 sbroyles 01/15/2014 Fix to 908290 changes
+ * @fk005 911760 fmkassem 01/14/2014 APSS data collection retry support.
+ * @gs025 913663 gjsilva 01/30/2014 Full fupport for soft frequency boundaries
+ * @sb023 913769 sbroyles 02/08/2014 Fix task_dcom_tx_slv_inbox !idle &&
+ * !complete hang.
+ * @gm028 911670 milesg 02/27/2014 Fixed compiler fails from stradale
+ * @gs027 918066 gjsilva 03/12/2014 Misc functions from ARL
+ * @wb001 919163 wilbryan 03/06/2014 Updating error call outs, descriptions, and severities
+ *
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOMMASTERTX_C
+#define _DCOMMASTERTX_C
+
+/** \defgroup Master-Slave Communication
+ *
+ */
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <pgp_pmc.h>
+#include "pgp_pba.h"
+#include <rtls.h>
+#include <apss.h>
+#include <dcom.h>
+#include <dcom_service_codes.h>
+#include <occ_service_codes.h>
+#include <trac.h>
+#include <proc_pstate.h>
+#include <amec_sys.h>
+#include <amec_master_smh.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+extern UINT8 g_amec_tb_record; // from amec_amester.c for syncronized traces
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+
+// SSX Block Copy Request for the Slave Inbox Transmit Queue
+BceRequest G_slv_inbox_tx_pba_request;
+
+// Used by the master to house the doorbell data that is sent in
+// the master multicast doorbell, stating that it put slave inbox in main memory.
+dcom_slv_inbox_doorbell_t G_dcom_slv_inbox_doorbell_tx;
+
+// Make sure that the Slave Inbox TX Buffer is 256B, otherwise cause
+// error on the compile.
+STATIC_ASSERT( (NUM_BYTES_IN_SLAVE_INBOX != (sizeof(G_dcom_slv_inbox_tx)/MAX_OCCS)) );
+
+// Store return code and failed packet # from pbax_send so we can trace it
+uint32_t G_pbax_rc = 0;
+uint32_t G_pbax_packet = 0xffffffff;
+
+//Used to keep count of number of APSS data collection fails.
+uint8_t G_apss_fail_updown_count = 0x00;
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: dcom_build_slv_inbox
+//
+// Description: The purpose of this function is to copy the Control Data into
+// the Slave inbox structures so that the Master can send it out.
+// Build the slave inboxes so master can send them to slaves
+//
+// Flow: 06/19/13 FN=dcom_build_slv_inbox
+//
+// changedby: @at013c, @fk001c
+//
+// End Function Specification
+
+uint32_t dcom_build_slv_inbox(void)
+{
+ // Locals
+ uint32_t l_addr_of_slv_inbox_in_main_mem = 0;
+ uint32_t l_slv_idx = 0;
+ uint32_t l_core_idx = 0;
+ uint32_t l_cntr_idx = 0;
+ uint32_t l_mem_intr_idx = 0;
+
+ static uint8_t L_seq = 0xFF;
+
+ L_seq++;
+
+ //If there was a pbax_send failure, trace it here since we can't do it in the critical
+ //interrupt context.
+ if(G_pbax_rc)
+ {
+ TRAC_INFO("PBAX Send Failure in transimitting multicast doorbell - RC[%08X], packet[%d]", G_pbax_rc, G_pbax_packet);
+ }
+
+
+ //INBOX...............
+ //For each occ slave collect its occ data.
+ for(; l_slv_idx < MAX_OCCS; l_slv_idx++)
+ {
+ G_dcom_slv_inbox_tx[l_slv_idx].seq = L_seq;
+ G_dcom_slv_inbox_tx[l_slv_idx].version = 0;
+ //G_dcom_slv_inbox_tx[l_slv_idx].ambient_temp = //Activate when ambient temperature is available.
+ //G_dcom_slv_inbox_tx[l_slv_idx].altitude = //Acitivate when altitude is available.
+
+ //TODO: adc,gpio,and tod are only sent here for sanity check and for bringup only.
+ //If the values are needed by the slaves, they should use the values sent in the doorbell.
+ //Probably remove them after bringup is complete.
+ memcpy( G_dcom_slv_inbox_tx[l_slv_idx].adc, G_apss_pwr_meas.adc, sizeof(G_dcom_slv_inbox_tx[l_slv_idx].adc));
+ memcpy( G_dcom_slv_inbox_tx[l_slv_idx].gpio, G_apss_pwr_meas.gpio, sizeof(G_dcom_slv_inbox_tx[l_slv_idx].gpio));
+ memcpy( G_dcom_slv_inbox_tx[l_slv_idx].tod, &G_apss_pwr_meas.tod, sizeof( G_dcom_slv_inbox_tx[l_slv_idx].tod )); //TODO - this doesn't work
+
+ memset( G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox, 0, sizeof( G_dcom_slv_inbox_tx[l_slv_idx].occ_fw_mailbox ));
+
+ //Collect frequency data for each core
+ for( l_core_idx = 0; l_core_idx < MAX_CORES; l_core_idx++)
+ {
+ // TODO - uncomment once macro exists
+ //G_dcom_slv_inbox_tx[l_slv_idx].freq250usp0cy = FREQ250USPC[l_core_idx];
+ G_dcom_slv_inbox_tx[l_slv_idx].freq250usp0cy[l_core_idx] = l_core_idx;
+ }
+
+ //collect data for each centaur throttle
+ for( l_cntr_idx = 0; l_cntr_idx < MAX_CENTAUR_THROTTLES; l_cntr_idx++)
+ {
+ // TODO - uncomment once macro exists
+ //G_dcom_slv_inbox_tx[l_slv_idx].memsp2msP0MxCyPz = MEMSP2MSP0MxCyPz[l_cntr_idx];
+ G_dcom_slv_inbox_tx[l_slv_idx].memsp2msP0MxCyPz[l_cntr_idx] = l_cntr_idx;
+ }
+
+ //collect data for each mem interleave group throttle
+ for( l_mem_intr_idx = 0; l_mem_intr_idx < MAX_MEM_INTERLEAVE_GROUP_THROTTLES; l_mem_intr_idx++)
+ {
+ // TODO - uncomment once macro exists
+ //G_dcom_slv_inbox_tx[l_slv_idx].memsp2msP0IGx = MEMSP2MSP0IG[l_mem_intr_idx];
+ G_dcom_slv_inbox_tx[l_slv_idx].memsp2msP0IGx[l_mem_intr_idx] = l_mem_intr_idx;
+ }
+
+ //collect mnfg parameters that need to be sent to slaves
+ G_dcom_slv_inbox_tx[l_slv_idx].foverride_enable = g_amec->mnfg_parms.auto_slew;
+ G_dcom_slv_inbox_tx[l_slv_idx].foverride = g_amec->mnfg_parms.foverride;
+ G_dcom_slv_inbox_tx[l_slv_idx].emulate_oversub = AMEC_INTF_GET_OVERSUBSCRIPTION_EMULATION();
+
+ //collect Idle Power Saver parameters to be sent to slaves
+ G_dcom_slv_inbox_tx[l_slv_idx].ips_freq_request = g_amec->mst_ips_parms.freq_request;
+
+ //collect Tunable Paramaters to be sent to slaves
+ G_dcom_slv_inbox_tx[l_slv_idx].alpha_up = G_mst_tunable_parameter_table_ext[0].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].alpha_down = G_mst_tunable_parameter_table_ext[1].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].sample_count_util = G_mst_tunable_parameter_table_ext[2].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].step_up = G_mst_tunable_parameter_table_ext[3].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].step_down = G_mst_tunable_parameter_table_ext[4].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].epsilon_perc = G_mst_tunable_parameter_table_ext[5].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].tlutil = G_mst_tunable_parameter_table_ext[6].adj_value;
+ G_dcom_slv_inbox_tx[l_slv_idx].tunable_param_overwrite = G_mst_tunable_parameter_overwrite;
+
+ //collect soft frequency bondaries to be sent to slaves
+ G_dcom_slv_inbox_tx[l_slv_idx].soft_fmin = G_mst_soft_fmin;
+ G_dcom_slv_inbox_tx[l_slv_idx].soft_fmax = G_mst_soft_fmax;
+
+ //send trace recording bit to slaves for synchronized tracing. //Lefurgy
+ G_dcom_slv_inbox_tx[l_slv_idx].tb_record = g_amec_tb_record;
+
+ G_dcom_slv_inbox_tx[l_slv_idx].counter++; // @th002
+
+ memcpy( &G_dcom_slv_inbox_tx[l_slv_idx].sys_mode_freq,
+ &G_sysConfigData.sys_mode_freq,
+ sizeof( freqConfig_t )); // @th040
+ }
+
+ //Clear the tunable parameter overwrite once we collect the new values
+ G_mst_tunable_parameter_overwrite = 0;
+
+ //@01a
+ dcom_build_occfw_msg( SLAVE_INBOX );
+
+ // Copy Data from one DCM pair's Outbox to other DCM pair's inbox
+ dcom_build_dcm_sync_msg( SLAVE_INBOX ); // @th010
+
+ l_addr_of_slv_inbox_in_main_mem = dcom_which_buffer();
+
+ //DOORBELL.................
+ //Prepare data for doorbell. This is sent to all OCCs
+
+ G_dcom_slv_inbox_doorbell_tx.pob_id = G_pob_id;
+ G_dcom_slv_inbox_doorbell_tx.magic1 = PBAX_MAGIC_NUMBER2_32B;
+ G_dcom_slv_inbox_doorbell_tx.addr_slv_inbox_buffer0 = l_addr_of_slv_inbox_in_main_mem;
+
+ memcpy( (void *) &G_dcom_slv_inbox_doorbell_tx.pcap,
+ (void *) &G_master_pcap_data, // @at013c @fk001c
+ sizeof(pcap_config_data_t));
+
+ G_dcom_slv_inbox_doorbell_tx.ppb_fmax = G_sysConfigData.master_ppb_fmax; //master ppb fmax is calculated in amec_ppb_fmax_calc
+
+ memcpy( (void *) &G_dcom_slv_inbox_doorbell_tx.adc[0],
+ (void *) &G_apss_pwr_meas.adc[0],
+ sizeof( G_dcom_slv_inbox_doorbell_tx.adc ));
+
+ G_dcom_slv_inbox_doorbell_tx.gpio[0] = G_apss_pwr_meas.gpio[0];
+ G_dcom_slv_inbox_doorbell_tx.gpio[1] = G_apss_pwr_meas.gpio[1];
+ G_dcom_slv_inbox_doorbell_tx.tod = G_apss_pwr_meas.tod;
+
+ G_dcom_slv_inbox_doorbell_tx.magic_counter++;
+ G_dcom_slv_inbox_doorbell_tx.magic2 = PBAX_MAGIC_NUMBER_32B;
+
+ return l_addr_of_slv_inbox_in_main_mem;
+}
+
+
+// Function Specification
+//
+// Name: dcom_which_buffer
+//
+// Description: Determines which buffer in the 'double buffer'
+// or ping/pong to use. Basically alternates between
+// returning the ping or the pong address
+//
+// Flow: 08/23/11 FN=dcom_which_buffer
+//
+// End Function Specification
+
+uint32_t dcom_which_buffer(void)
+{
+ //Locals
+ uint32_t l_mem_address = ADDR_SLAVE_INBOX_MAIN_MEM_PONG;
+
+ // switch back and forth based on tick
+ if( CURRENT_TICK & 1 )
+ {
+ l_mem_address = ADDR_SLAVE_INBOX_MAIN_MEM_PING;
+ }
+
+ return l_mem_address;
+}
+
+
+// Function Specification
+//
+// Name: task_dcom_tx_slv_inbox
+//
+// Description: Copy slave inboxes from SRAM to main memory
+// so master can send data to slave
+//
+// Flow: 08/23/11 FN=task_dcom_tx_slv_inbox
+//
+// Task Flags: RTL_FLAG_MSTR, RTL_FLAG_OBS, RTL_FLAG_ACTIVE
+//
+// Changes: @fk005c
+//
+// End Function Specification
+void task_dcom_tx_slv_inbox( task_t *i_self)
+{
+ static bool l_error = FALSE;
+ uint32_t l_orc = OCC_SUCCESS_REASON_CODE;
+ uint32_t l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ uint64_t l_start = ssx_timebase_get();
+ bool l_pwr_meas = FALSE; // @th002
+ bool l_request_reset = FALSE; // @fk005a
+ bool l_ssx_failure = FALSE;
+ // @sb003 Use a static local bool to track whether the BCE request used
+ // here has ever been successfully created at least once
+ static bool L_bce_slv_inbox_tx_request_created_once = FALSE;
+
+ DCOM_DBG("4. TX Slave Inbox\n");
+
+ do
+ {
+ // If we are in standby, we need to fake out
+ // the APSS data since we aren't talking to APSS.
+ if( OCC_STATE_STANDBY == CURRENT_STATE() ) // @th022
+ {
+ G_ApssPwrMeasCompleted = TRUE; // @th022
+ }
+
+ l_pwr_meas = G_ApssPwrMeasCompleted; // @th002
+
+ //did apss pwr complete?
+ if( l_pwr_meas == TRUE ) // @th002
+ {
+#ifdef DCOM_DEBUG
+ uint64_t l_end = ssx_timebase_get();
+ DCOM_DBG("Got APSS after waiting %d us\n",(int)( (l_end-l_start) / ( SSX_TIMEBASE_FREQUENCY_HZ / 1000000 ) ));
+#endif
+
+ //@fk005a
+ APSS_SUCCESS();
+
+ // build/setup inboxes
+ uint32_t l_addr_in_mem = dcom_build_slv_inbox();
+ uint32_t l_ssxrc = 0;
+
+ // @sb003
+ // See dcomMasterRx.c/task_dcom_rx_slv_outboxes for details on the
+ // checking done here before creating and scheduling the request.
+ bool l_proceed_with_request_and_schedule = FALSE;
+ int l_req_idle = async_request_is_idle(&(G_slv_inbox_tx_pba_request.request));
+ int l_req_complete = async_request_completed(&(G_slv_inbox_tx_pba_request.request));
+
+ if (!L_bce_slv_inbox_tx_request_created_once)
+ {
+ // Do this case first, all other cases assume that this is
+ // true!
+ // This is the first time we have created a request so
+ // always proceed with request create and schedule
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && l_req_complete)
+ {
+ // Most likely case first. The request was created
+ // and scheduled and has completed without error. Proceed.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && !l_req_complete)
+ {
+ // There was an error on the schedule request or the request
+ // was scheduled but was canceled, killed or errored out.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv inbox tx request idle but not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_inbox_tx_pba_request.request.callback_rc,
+ G_slv_inbox_tx_pba_request.request.options,
+ G_slv_inbox_tx_pba_request.request.state,
+ G_slv_inbox_tx_pba_request.request.abort_state,
+ G_slv_inbox_tx_pba_request.request.completion_state);
+ TRAC_INFO("Proceeding with BCE slv inbox tx request and schedule");
+ }
+ else if (!l_req_idle && !l_req_complete)
+ {
+ // The request was created and scheduled but is still in
+ // progress or still enqueued OR there was some error
+ // creating the request so it was never scheduled. The latter
+ // case is unlikely and will generate an error message when
+ // it occurs. It will also have to happen after the request
+ // was created at least once or we'll never get here. If the
+ // request does fail though before the state parms in the
+ // request are reset (like a bad parameter error), then this
+ // represents a hang condition that we can't recover from.
+ // DO NOT proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = FALSE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv inbox tx request not idle and not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_inbox_tx_pba_request.request.callback_rc,
+ G_slv_inbox_tx_pba_request.request.options,
+ G_slv_inbox_tx_pba_request.request.state,
+ G_slv_inbox_tx_pba_request.request.abort_state,
+ G_slv_inbox_tx_pba_request.request.completion_state);
+ TRAC_INFO("NOT proceeding with BCE slv inbox tx request and schedule");
+ }
+ // else {// This case can't happen, ignore it.}
+
+ // @sb003 Only proceed if the BCE request state checked out
+ if (l_proceed_with_request_and_schedule)
+ {
+ // set up inboxes copy request
+ l_ssxrc = bce_request_create(
+ &G_slv_inbox_tx_pba_request, // block copy object
+ &G_pba_bcue_queue, // mainstore to sram copy engine
+ l_addr_in_mem, // mainstore address
+ (uint32_t) &G_dcom_slv_inbox_tx[0], // sram starting address
+ sizeof(G_dcom_slv_inbox_tx), // size of copy // @th002
+ SSX_WAIT_FOREVER, // no timeout
+ (AsyncRequestCallback)dcom_tx_slv_inbox_doorbell, // call back
+ NULL, // call back arguments
+ ASYNC_CALLBACK_IMMEDIATE // callback mask
+ );
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_TX_SLV_INBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request create failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_CREATE_FAILURE; // @nh001a
+ l_ssx_failure = TRUE; // @wb001
+ break;
+ }
+
+ // @sb003 Request created at least once
+ L_bce_slv_inbox_tx_request_created_once = TRUE; // @sb013
+ l_ssxrc = bce_request_schedule(&G_slv_inbox_tx_pba_request); // actual copying
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_TX_SLV_INBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request schedule failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_SCHEDULE_FAILURE; // @nh001a
+ l_ssx_failure = TRUE; // @wb001
+ break;
+ }
+ }
+ // @sb023 Moved the break statement here in case we decide not to
+ // schedule the BCE request.
+ break;
+ }
+ else
+ {
+ // check time and break out if we reached limit
+ // @th032 -- TODO: shrink this later depending on how much
+ // work we are doing in RTL
+ if ((ssx_timebase_get() - l_start) < SSX_MICROSECONDS(150))
+ {
+ continue;
+ }
+ else
+ {
+ //Failure occurred, step up the FAIL_COUNT
+ APSS_FAIL();
+
+
+ if (G_apss_fail_updown_count >= APSS_DATA_FAIL_MAX)
+ {
+ TRAC_ERR("task_dcom_tx_slv_inbox: APSS data collection failure exceeded threshold. fail_count=%i, threshold:%i",
+ G_apss_fail_updown_count, APSS_DATA_FAIL_MAX);
+
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_TX_SLV_INBOX
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 N/A
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Time out waiting on power measurement completion
+ */
+ TRAC_ERR("Timed out waiting apss meas completion (dcom_start:%d us, apss_start:%d us, apss_end:%d us)",
+ (int) ((l_start)/(SSX_TIMEBASE_FREQUENCY_HZ/1000000)),
+ (int) ((G_gpe_apss_time_start)/(SSX_TIMEBASE_FREQUENCY_HZ/1000000)),
+ (int) ((G_gpe_apss_time_end)/(SSX_TIMEBASE_FREQUENCY_HZ/1000000))); // @jh00ac
+ l_orc = INTERNAL_FAILURE; // @nh001c
+ l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ l_request_reset = TRUE; // @fk005a
+
+ }
+ break;
+ }
+ }
+
+ } while (1); // @th002
+
+ //If an error exists and we have not logged one before or there's a new request to reset, then log error.
+ if ( (l_orc != OCC_SUCCESS_REASON_CODE) && ((l_error == FALSE) || (l_request_reset == TRUE)))
+ {
+ // create and commit error only once.
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_TASK_TX_SLV_INBOX, //modId
+ l_orc, //reasoncode // @nh001c
+ l_orc_ext, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ 0, //userdata1
+ 0 //userdata2
+ );
+
+ // @wb001 -- Callout to firmware
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ if ( FALSE == l_ssx_failure ) // @wb001
+ {
+ // Callout to processor
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.proc_huid,
+ ERRL_CALLOUT_PRIORITY_LOW);
+
+ // Callout to APSS
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.apss_huid,
+ ERRL_CALLOUT_PRIORITY_LOW);
+ }
+
+ if (l_request_reset)
+ {
+ REQUEST_RESET(l_errl);
+ }
+ else
+ {
+ commitErrl(&l_errl);
+ }
+
+ l_error = TRUE;
+ l_request_reset = FALSE;
+ }
+
+}
+
+
+// Function Specification
+//
+// Name: dcom_tx_slv_inbox_doorbell
+//
+// Description: transmit doorbells to slaves
+// from master
+//
+// Flow: 08/23/11 FN=dcom_tx_slv_inbox_doorbell
+//
+// End Function Specification
+void dcom_tx_slv_inbox_doorbell( void )
+{
+ int l_pbarc = 0;
+ int l_tmp = 0;
+ int l_jj = 0;
+ uint64_t l_start = ssx_timebase_get();
+
+ /// Caclulate how many 8 byte packets are in the doorbell
+ l_tmp = sizeof( G_dcom_slv_inbox_doorbell_tx ) / sizeof(uint64_t);
+
+ /// Loop through all packets, sending one at a time. It should send
+ /// the previous packet almost immediately, but it is worth noting that
+ /// it is *possible* that the PowerBus is backed up, in which case it may
+ /// take a short amount of time (~1us <TBD>) to send each packet.
+ /// Estimated transfer time, under normal circumstances is 1kB/1us.
+ for(l_jj=0; l_jj<l_tmp; l_jj++)
+ {
+ // Send 8 bytes of multicast doorbell
+ l_pbarc = _pbax_send( &G_pbax_multicast_target, //gm014
+ G_dcom_slv_inbox_doorbell_tx.words[l_jj],
+ SSX_MICROSECONDS(15));
+
+ //Set this global so we know to trace this in the non-critical interrupt context
+ G_pbax_rc = l_pbarc;
+ if ( (l_pbarc != 0 ) )
+ {
+ G_pbax_packet = l_jj;
+ //Trace causes a panic in a critical interrupt! Don't trace here!(tries to pend a semaphore)
+
+ /// Break out of for loop and stop sending the rest of the doorbell
+ /// packets, since this likely occured b/c of a timeout.
+ break;
+ }
+ }
+
+ // <TULETA HW BRINGUP TIMING> @th032
+ uint64_t l_delta = (ssx_timebase_get() - l_start);
+ G_dcomTime.master.doorbellStartTx = l_start;
+ G_dcomTime.master.doorbellStopTx = ssx_timebase_get();
+ G_dcomTime.master.doorbellMaxDeltaTx = (l_delta > G_dcomTime.master.doorbellMaxDeltaTx) ?
+ l_delta : G_dcomTime.master.doorbellMaxDeltaTx;
+ G_dcomTime.master.doorbellSeq = G_dcom_slv_inbox_doorbell_tx.magic_counter;
+ G_dcomTime.master.doorbellNumSent++;
+ // </TULETA HW BRINGUP TIMING> @th032
+
+ DCOM_DBG("Sent multicast doorbell\n");
+} // @th034 - rewrote most of functino
+
+#endif //_DCOMMASTERTOSLAVE_C
+
diff --git a/src/occ/dcom/dcomSlaveRx.c b/src/occ/dcom/dcomSlaveRx.c
new file mode 100644
index 0000000..d7406d8
--- /dev/null
+++ b/src/occ/dcom/dcomSlaveRx.c
@@ -0,0 +1,671 @@
+/******************************************************************************
+// @file dcomSlaveRx.c
+// @brief Slave OCC to Master OCC communication handler
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcomSlaveRx.c DCOMSLAVERX.C
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @th022 thallet 10/08/2012 Changes for OCC Comm
+ * @th024 thallet 10/16/2012 Cleanup to use modifier function
+ * @th034 879027 thallet 04/18/2013 Broadcast Critical Power over PBAX
+ * @th032 thallet 04/26/2013 Added a bunch of timings for PBAX characterization
+ * @gs016 905781 gjsilva 11/12/2013 Fix for Master->Slave doorbell loss of synchronization
+ * @rt004 908817 tapiar 12/11/2013 Update pcap infromation via write_data_pcap
+ * once doorbell data is verfied
+ * @sb003 908290 sbroyles 12/18/2013 Test BCE request states
+ * @sb013 911625 sbroyles 01/15/2014 Fix to 908290 changes
+ * @wb003 920760 wilbryan 03/25/2014 Update SRCs to match TPMD SRCs
+ * @gm037 925908 milesg 05/07/2014 Redundant OCC/APSS support
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOMSLAVERX_C
+#define _DCOMSLAVERX_C
+
+/** \defgroup Slave to Master Communication
+ *
+ */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <pgp_pmc.h>
+#include "pgp_pba.h"
+#include <rtls.h>
+#include <apss.h>
+#include <dcom.h>
+#include <dcom_service_codes.h>
+#include <occ_service_codes.h>
+#include <trac.h>
+#include <proc_pstate.h>
+#include <amec_data.h> // @rt004a
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+// SSX Block Copy Request for the Slave Inbox Receive Queue
+BceRequest G_slv_inbox_rx_pba_request;
+
+// SSX PBAX Request for Multicast PBAX Queue (Master Doorbell to Slaves)
+PbaxRequest G_pbax_multicast_request; //does not get used should it??
+
+// SSX PBAX Request for Receiving PBAX Messages
+PbaxRequest G_pbax_rx_request;
+
+// Used by the slave to house the doorbell data that is received from
+// the master multicast doorbell, stating that it put slave inbox in main memory.
+dcom_slv_inbox_doorbell_t G_dcom_slv_inbox_doorbell_rx;
+
+// Make sure that the Slave Inbox RX Buffer is 256B, otherwise cause
+// error on the compile.
+STATIC_ASSERT( (NUM_BYTES_IN_SLAVE_INBOX != (sizeof(G_dcom_slv_inbox_rx))) );
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: dcom_calc_slv_inbox_addr
+//
+// Description: get slave inbox main memory address
+//
+// Flow: 08/23/11 FN=dcom_calc_slv_inbox_addr
+//
+// End Function Specification
+uint32_t dcom_calc_slv_inbox_addr(void)
+{
+ return (G_dcom_slv_inbox_doorbell_rx.addr_slv_inbox_buffer0 + ( G_pob_id.chip_id * sizeof(dcom_slv_inbox_t) ));
+}
+
+
+// Function Specification
+//
+// Name: dcom_rx_slv_inbox_callback
+//
+// Description: Callback to set inbox received to true
+//
+// Flow: FN=None
+//
+// End Function Specification
+void dcom_rx_slv_inbox_callback( void )
+{
+ // AMEC will use this, and reset it when done
+ G_slv_inbox_received = TRUE;
+}
+
+
+// Function Specification
+//
+// Name: task_dcom_rx_slv_inbox
+//
+// Description: Copy Slave inbox from Main Memory to SRAM
+// on slave
+//
+// Flow: 10/24/11 FN=task_dcom_rx_slv_inbox
+//
+// Task Flags: RTL_FLAG_OBS, RTL_FLAG_ACTIVE
+//
+// End Function Specification
+void task_dcom_rx_slv_inbox( task_t *i_self)
+{
+ uint32_t l_orc = OCC_SUCCESS_REASON_CODE;
+ uint32_t l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ uint64_t l_start = ssx_timebase_get();
+ uint32_t l_bytes = 0;
+ // @sb003 Use a static local bool to track whether the BCE request used
+ // here has ever been successfully created at least once
+ static bool L_bce_slv_inbox_rx_request_created_once = FALSE;
+
+ DCOM_DBG("1. RX Slave Inbox\n");
+
+ // Increment debug counter
+ G_dcomSlvInboxCounter.totalTicks++;
+ G_dcomTime.slave.doorbellStartWaitRx = l_start;
+
+ do
+ {
+ l_bytes = dcom_rx_slv_inbox_doorbell();
+ // doorbell from the master
+ if(l_bytes >= sizeof(G_dcom_slv_inbox_doorbell_rx))
+ {
+
+ // looks like we got a valid doorbell so notify slave
+ // code of pcap info @rt004a
+ amec_data_write_pcap();
+
+#ifdef DCOM_DEBUG
+ uint64_t l_end = ssx_timebase_get();
+ DCOM_DBG("Got Doorbell from Master after waiting %d us\n",(int)( (l_end-l_start) / ( SSX_TIMEBASE_FREQUENCY_HZ / 1000000 ) ));
+#endif
+ // <TULETA HW BRINGUP TIMING>
+ G_dcomTime.slave.doorbellStopWaitRx = ssx_timebase_get();
+ uint64_t l_delta = G_dcomTime.slave.doorbellStopWaitRx - G_dcomTime.slave.doorbellStartWaitRx;
+ G_dcomTime.slave.doorbellMaxDeltaWaitRx = (l_delta > G_dcomTime.slave.doorbellMaxDeltaWaitRx) ?
+ l_delta : G_dcomTime.slave.doorbellMaxDeltaWaitRx;
+ G_dcomTime.slave.doorbellNumRx++;
+ // </TULETA HW BRINGUP TIMING>
+
+ // Increment debug counter
+ G_dcomSlvInboxCounter.totalSuccessful++;
+
+ // main memory address
+ uint32_t l_addr_in_mem = dcom_calc_slv_inbox_addr();
+
+ //check valid address (should be inside inbox addresses range)
+ if ( (ADDR_SLAVE_INBOX_MAIN_MEM_PING <= l_addr_in_mem) &&
+ ((ADDR_SLAVE_INBOX_MAIN_MEM_PONG+(sizeof(dcom_slv_inbox_t)*MAX_OCCS)) > l_addr_in_mem) )
+ {
+ uint32_t l_ssxrc = 0;
+ // @sb003
+ // See dcomMasterRx.c/task_dcom_rx_slv_outboxes for details on the
+ // checking done here before creating and scheduling the request.
+ bool l_proceed_with_request_and_schedule = FALSE;
+ int l_req_idle = async_request_is_idle(&(G_slv_inbox_rx_pba_request.request));
+ int l_req_complete = async_request_completed(&(G_slv_inbox_rx_pba_request.request));
+
+ if (!L_bce_slv_inbox_rx_request_created_once)
+ {
+ // Do this case first, all other cases assume that this is
+ // true!
+ // This is the first time we have created a request so
+ // always proceed with request create and schedule
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && l_req_complete)
+ {
+ // Most likely case first. The request was created
+ // and scheduled and has completed without error. Proceed.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && !l_req_complete)
+ {
+ // There was an error on the schedule request or the request
+ // was scheduled but was canceled, killed or errored out.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv inbox rx request idle but not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_inbox_rx_pba_request.request.callback_rc,
+ G_slv_inbox_rx_pba_request.request.options,
+ G_slv_inbox_rx_pba_request.request.state,
+ G_slv_inbox_rx_pba_request.request.abort_state,
+ G_slv_inbox_rx_pba_request.request.completion_state);
+ TRAC_INFO("Proceeding with BCE slv inbox rx request and schedule");
+ }
+ else if (!l_req_idle && !l_req_complete)
+ {
+ // The request was created and scheduled but is still in
+ // progress or still enqueued OR there was some error
+ // creating the request so it was never scheduled. The latter
+ // case is unlikely and will generate an error message when
+ // it occurs. It will also have to happen after the request
+ // was created at least once or we'll never get here. If the
+ // request does fail though before the state parms in the
+ // request are reset (like a bad parameter error), then this
+ // represents a hang condition that we can't recover from.
+ // DO NOT proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = FALSE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv inbox rx request not idle and not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_inbox_rx_pba_request.request.callback_rc,
+ G_slv_inbox_rx_pba_request.request.options,
+ G_slv_inbox_rx_pba_request.request.state,
+ G_slv_inbox_rx_pba_request.request.abort_state,
+ G_slv_inbox_rx_pba_request.request.completion_state);
+ TRAC_INFO("NOT proceeding with BCE slv inbox rx request and schedule");
+ }
+ // else {// This case can't happen, ignore it.}
+
+ // @sb003 Only proceed if the BCE request state checked out
+ if (l_proceed_with_request_and_schedule)
+ {
+ // copy request from main memory to SRAM
+ l_ssxrc = bce_request_create(
+ &G_slv_inbox_rx_pba_request, // block copy object
+ &G_pba_bcde_queue, // mainstore to sram copy engine
+ l_addr_in_mem, // mainstore address
+ (uint32_t)&G_dcom_slv_inbox_rx, // sram starting address
+ sizeof(G_dcom_slv_inbox_rx), // size of copy
+ SSX_WAIT_FOREVER, // no timeout
+ (AsyncRequestCallback)dcom_rx_slv_inbox_callback, // call back
+ NULL, // call back arguments
+ ASYNC_CALLBACK_IMMEDIATE // blocking request
+ );
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_INBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request create failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_CREATE_FAILURE; // @nh001a
+ break;
+ }
+
+ // @sb003 Request created at least once
+ L_bce_slv_inbox_rx_request_created_once = TRUE; // @sb013
+ l_ssxrc = bce_request_schedule(&G_slv_inbox_rx_pba_request); // actual copying
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_INBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request schedule failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_SCHEDULE_FAILURE; // @nh001a
+ break;
+ }
+ break; // @th002
+ }
+ }
+ else
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_INBOX
+ * @reasoncode INTERNAL_INVALID_INPUT_DATA
+ * @userdata1 N/A
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Firmware related internal error
+ */
+ TRAC_ERR("Invalid address from calculate slave inbox address function [%08X]", l_addr_in_mem );
+ l_orc = INTERNAL_INVALID_INPUT_DATA; // @wb003
+ l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ break;
+ }
+ break; // @th002
+ }
+ else
+ {
+ if(l_bytes)
+ {
+ TRAC_INFO("Only got %d bytes from master",l_bytes);
+ }
+ // check time and break out if we reached limit
+ if ((ssx_timebase_get() - l_start) < SSX_MICROSECONDS(100)) // @th002 -- TODO: shrink this down later
+ {
+ continue;
+ }
+ else
+ {
+#if 0
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_RX_SLV_INBOX
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_GENERIC_TIMEOUT
+ * @devdesc Generic timeout failure
+ */
+ TRAC_ERR("Time out waiting for receive doorbell" );
+ l_orc = INTERNAL_FAILURE; // @nh001c
+ l_orc_ext = ERC_GENERIC_TIMEOUT; // @nh001a
+#endif
+ // TODO: We need to signal this
+
+ // <TULETA HW BRINGUP TIMING>
+ G_dcomTime.slave.doorbellErrorFlags.timeoutRx = 1;
+ G_dcomTime.slave.doorbellTimeoutWaitRx = ssx_timebase_get();
+ // <TULETA HW BRINGUP TIMING>
+
+ // Let's signal that master is not ready, and then
+ // start task waiting for master to talk again.
+ rtl_start_task(TASK_ID_DCOM_WAIT_4_MSTR); // @th024
+ rtl_set_run_mask_deferred(RTL_FLAG_MSTR_READY);
+ TRAC_INFO("[%d]: Lost connection to master",(int) G_pob_id.chip_id);
+ break;
+ }
+ }
+ }
+ while( 1 ); // @th002
+
+
+ if ( l_orc != OCC_SUCCESS_REASON_CODE )
+ {
+ // create and commit error
+ dcom_error_check( SLAVE_INBOX, FALSE, l_orc, l_orc_ext); // @nh001c
+ }
+ else
+ {
+ // done, lets clear our counter
+ dcom_error_check_reset( SLAVE_INBOX );
+ }
+
+}
+
+
+// Function Specification
+//
+// Name: dcom_rx_slv_inbox_doorbell
+//
+// Description: receive multicast doorbell and save data
+// from master (master to slave)
+//
+// Flow: 09/02/11 FN=dcom_rx_slv_inbox_doorbell
+//
+// End Function Specification
+uint32_t dcom_rx_slv_inbox_doorbell( void )
+{
+ static bool l_trace_once = FALSE;
+ int l_pbarc = 0;
+ uint32_t l_read = 0;
+ uint32_t l_bytes_so_far = 0;
+ uint64_t l_start = ssx_timebase_get();
+
+ G_dcomTime.slave.doorbellStartRx = l_start;
+
+ while(l_bytes_so_far < sizeof(G_dcom_slv_inbox_doorbell_rx))
+ {
+ /// Read 8 bytes of the doorbell from master
+ l_pbarc = pbax_read(
+ &G_pbax_read_queue[0],
+ &G_dcom_slv_inbox_doorbell_rx.words[(l_bytes_so_far / sizeof(uint64_t))],
+ sizeof(uint64_t), // Must read 8 bytes at a time
+ &l_read
+ );
+
+ DCOM_DBG("Doorbell (Multicast) Read: %d bytes\n",l_read);
+
+ /// We got an error reading from the PBAX, return to caller
+ if ( l_pbarc != 0 )
+ {
+ G_dcomTime.slave.doorbellErrorFlags.hwError = 1;
+ if ( FALSE == l_trace_once )
+ {
+ // failure occurred but only trace it once
+ TRAC_ERR("PBAX Read Failure in receiving multicast doorbell - RC[%08X]", l_pbarc);
+ l_trace_once = TRUE;
+ }
+ break;
+ }
+
+ /// Didn't read any bytes from pbax. We are either done, or we
+ /// simply don't have any data to read
+ if(0 == l_read){
+ if ((ssx_timebase_get() - l_start) > SSX_MICROSECONDS(3))
+ {
+ // <TULETA HW BRINGUP TIMING>
+ if(l_bytes_so_far){
+ G_dcomTime.slave.doorbellErrorFlags.incomplete = 1;
+ }
+ else{
+ G_dcomTime.slave.doorbellErrorFlags.timeout = 1;
+ }
+ // </TULETA HW BRINGUP TIMING>
+ break;
+ }
+ }
+ else{
+ /// If we just read some data, reset this EndOfMessage counter
+ l_start = ssx_timebase_get();
+ }
+
+ /// Increment the number of bytes we have in the buffer
+ l_bytes_so_far += l_read;
+
+ /// If it doesnt match the magic number, and it's the first
+ /// packet we read, just drop it on the floor and start over
+ if( 8 == l_bytes_so_far)
+ {
+ if(PBAX_MAGIC_NUMBER2_32B != G_dcom_slv_inbox_doorbell_rx.magic1)
+ {
+ l_read = 0;
+ l_bytes_so_far = 0;
+ G_dcomTime.slave.doorbellErrorFlags.dropPacket = 1;
+
+ TRAC_INFO("Slave Inbox - Start Magic Number Mismatch [0x%08X]",
+ G_dcom_slv_inbox_doorbell_rx.magic1);
+ }
+ }
+ /// If this is the last packet, make sure the magic number matches
+ else if (sizeof(G_dcom_slv_inbox_doorbell_rx) == l_bytes_so_far)
+ {
+ if(PBAX_MAGIC_NUMBER_32B != G_dcom_slv_inbox_doorbell_rx.magic2)
+ {
+ TRAC_INFO("Slave Inbox - End Magic Number Mismatch [0x%08X]",
+ G_dcom_slv_inbox_doorbell_rx.magic2);
+ G_dcomTime.slave.doorbellErrorFlags.badMagicNumEnd = 1;
+
+ /// Decrement the number of bytes we return so it fails
+ /// any valid length checks, but still indicates to us that
+ /// we 'got' data, just not good data if it is included in
+ /// an error log.
+ l_bytes_so_far = (sizeof(G_dcom_slv_inbox_doorbell_rx) - 1);
+ }
+ else
+ {
+ // <TULETA HW BRINGUP TIMING>
+ if(G_dcom_slv_inbox_doorbell_rx.magic_counter != (G_dcomTime.slave.doorbellSeq + 1))
+ {
+ G_dcomTime.slave.doorbellErrorFlags.badSequence = 1;
+ }
+ G_dcomTime.slave.doorbellSeq = G_dcom_slv_inbox_doorbell_rx.magic_counter;
+ // </TULETA HW BRINGUP TIMING>
+ }
+ break;
+ }
+ }
+
+ // <TULETA HW BRINGUP TIMING>
+ G_dcomTime.slave.doorbellStopRx = ssx_timebase_get();
+ uint64_t l_delta = G_dcomTime.slave.doorbellStopRx - G_dcomTime.slave.doorbellStartRx;
+ G_dcomTime.slave.doorbellMaxDeltaRx = (l_delta > G_dcomTime.slave.doorbellMaxDeltaRx) ?
+ l_delta : G_dcomTime.slave.doorbellMaxDeltaRx;
+ // </TULETA HW BRINGUP TIMING>
+
+ return l_bytes_so_far;
+} // @th034 -- rewrote most of function
+
+
+// Function Specification
+//
+// Name: task_dcom_wait_for_master
+//
+// Description: The purpose of this task is to wait for the reception of the
+// first master multicast doorbell. After it is received, it sets
+// a RTL flag indicating as such.
+//
+// Flow: 09/27/11 FN=task_dcom_wait_for_master
+//
+// End Function Specification
+#define POBID_RETRIES 2
+void task_dcom_wait_for_master( task_t *i_self)
+{
+ // Don't try and read the doorbell on the first tick of the RTL.
+ // If we do, then we will clear the RTL flags too early, and the actual
+ // task will miss the doorbell.
+ // This task will skip executing once every 12.41 days b/c of a rollover of
+ // CURRENT_TICK. This is not a concern, so we won't bother to check that case.
+ int l_rc = 0;
+ pbax_id_t l_pbaxid;
+ uint32_t l_num_read = 0; // @th034
+ static bool L_first_doorbell_rcvd = FALSE;
+ static bool L_queue_enabled = FALSE;
+ static uint32_t L_pobid_retries_left = POBID_RETRIES;
+
+ DCOM_DBG("0. Wait for Master\n");
+
+
+ do
+ {
+ /// If this is the first time we are in this task, enable
+ /// the queue, since now until forever we are able to read from it.
+ if(!L_queue_enabled)
+ {
+ pbax_queue_enable(&G_pbax_read_queue[0]);
+ L_queue_enabled = TRUE;
+ }
+
+ l_num_read = (CURRENT_TICK) ? dcom_rx_slv_inbox_doorbell() : 0; // @th034
+
+ G_dcomSlvInboxCounter.totalTicks++;
+
+ if(l_num_read < sizeof(G_dcom_slv_inbox_doorbell_rx))
+ {
+ // Don't log an error if we don't get doorbell within any certain timeout
+ // period. This will be taken care of by another function
+ break;
+ }
+
+ // Special handling for recieving the 1st master doorbell since we need to also
+ // set up a unicast PBAX target to the master -- gm037
+ if(!L_first_doorbell_rcvd)
+ {
+ //convert powerbus id to pbax id (sets node_id to INVALID_NODE_ID on failure)
+ l_pbaxid = dcom_pbusid2pbaxid(G_dcom_slv_inbox_doorbell_rx.pob_id); //traces failure internally
+ if(l_pbaxid.node_id == INVALID_NODE_ID)
+ {
+ //we received an invalid power bus id from the master.
+ //This may be a communication failure, so allow some retries
+ if(L_pobid_retries_left)
+ {
+ L_pobid_retries_left--;
+ break;
+ }
+
+ //retries exceeded. Log error and request reset.
+
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_WAIT_FOR_MASTER
+ * @reasoncode INTERNAL_FAILURE
+ * @userdata1 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc An invalid power bus ID was sent from the master OCC
+ */
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_WAIT_FOR_MASTER, //modId
+ INTERNAL_FAILURE, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ 0, //userdata1
+ 0 //userdata2
+ );
+
+ // commit log and request reset
+ REQUEST_RESET(l_errl);
+
+ break;
+ }
+
+ //Set up the master pbax unicast target for sending doorbells to the master
+ l_rc = pbax_target_create(&G_pbax_unicast_target, //target
+ PBAX_UNICAST, //type
+ PBAX_GROUP, //scope
+ 1, //queue
+ l_pbaxid.node_id, //node
+ l_pbaxid.chip_id); //chip (or group) id
+ if(l_rc)
+ {
+ //log an error and request reset when pbax_target_create fails
+
+ TRAC_ERR("pbax_target_create failed creating pbax target to master OCC. rc=%d, node=%d, chip=%d",
+ l_rc,
+ l_pbaxid.node_id,
+ l_pbaxid.chip_id);
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_WAIT_FOR_MASTER
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 SSX RC
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failure initializing a PBAX queue
+ */
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_WAIT_FOR_MASTER, //modId
+ SSX_GENERIC_FAILURE, //reasoncode // @nh001c
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_rc, //userdata1
+ 0 //userdata2
+ );
+
+ // commit log and request reset -- @gm007
+ REQUEST_RESET(l_errl);
+
+ break;
+ }
+
+ TRAC_IMP("Slave OCC[%d] Received first doorbell from Master OCC[%d]",
+ (int) G_pob_id.chip_id,
+ G_dcom_slv_inbox_doorbell_rx.pob_id.chip_id);
+
+ // First message is dropped, so mark it as counted.
+ G_dcomSlvInboxCounter.totalTicks = 0;
+ G_dcomSlvInboxCounter.totalSuccessful = 0;
+ G_dcomSlvInboxCounter.currentFailCount = 0;
+
+ // initialization was successful
+ L_first_doorbell_rcvd = TRUE;
+
+ }
+ else
+ {
+ TRAC_INFO("[%d] Restablished contact via doorbell from Master",(int) G_pob_id.chip_id); // @th002
+ }
+
+ //got a multicast doorbell
+ G_dcomTime.slave.doorbellNumWaitRx++; // @th032
+
+ //set MASTER READY on global RTL FLAG
+ rtl_clr_run_mask_deferred(RTL_FLAG_MSTR_READY); // @th032
+
+ //CLEAR the RTL run FLAG for current task
+ rtl_stop_task(TASK_ID_DCOM_WAIT_4_MSTR); // @th024
+
+ }while(0);
+
+}
+
+
+#endif //_DCOMSLAVERX_C
+
diff --git a/src/occ/dcom/dcomSlaveTx.c b/src/occ/dcom/dcomSlaveTx.c
new file mode 100755
index 0000000..b259607
--- /dev/null
+++ b/src/occ/dcom/dcomSlaveTx.c
@@ -0,0 +1,431 @@
+/******************************************************************************
+// @file dcomSlaveTx.c
+// @brief Slave OCC to Master OCC communication handler
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcomSlaveTx.c DCOMSLAVETX.C
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @00 abagepa 10/10/2011 Created
+ * @th002 thallet 11/01/2011 Misc Changes for Nov 1st Milestone
+ * @th005 thallet 11/23/2011 Added STATIC_ASSERT checks
+ * @01 tapiar 11/12/2011 Stage 3 updates
+ * @rc003 rickylie 02/03/2012 Verify & Clean Up OCC Headers & Comments
+ * @nh001 neilhsu 05/23/2012 Add missing error log tags
+ * @th010 thallet 07/11/2012 Pstate Enablement`
+ * @th022 thallet 10/08/2012 Changes for OCC Comm
+ * @rt001 897459 tapiar 08/19/2013 Upd: save active node pcap from doorbell
+ * @gm014 907707 milesg 12/05/2013 don't panic on pbax_send timeout failures
+ * @rt004 908817 tapiar 12/11/2013 Save of valid pcap field so master can use it
+ * @sb003 908290 sbroyles 12/18/2013 Test BCE request states
+ * @sb013 911625 sbroyles 01/15/2014 Fix to 908290 changes
+ * @wb001 919163 wilbryan 03/06/2014 Updating error call outs, descriptions, and severities
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOMSLAVETX_C
+#define _DCOMSLAVETX_C
+
+/** \defgroup Slave to Master Communication
+ *
+ */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <pgp_pmc.h>
+#include "pgp_pba.h"
+#include <rtls.h>
+#include <apss.h>
+#include <dcom.h>
+#include <dcom_service_codes.h>
+#include <occ_service_codes.h>
+#include <trac.h>
+#include <proc_pstate.h>
+#include <amec_sys.h> // @rt001a
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+// SSX Block Copy Request for the Slave Outbox Transmit Queue
+BceRequest G_slv_outbox_tx_pba_request;
+
+// SSX PBAX Request for Unicast PBAX Queue (Slave Doorbell to Master)
+PbaxRequest G_pbax_unicast_request;
+
+// Used by the slave to house the doorbell data that is sent in
+// the slave unicast doorbell, stating that it put slave outbox in main memory.
+// *
+dcom_slv_outbox_doorbell_t G_dcom_slv_outbox_doorbell_tx;
+
+// Make sure that the Slave Outbox TX Buffer is 1kB, otherwise cause
+// error on the compile.
+STATIC_ASSERT( (NUM_BYTES_IN_SLAVE_OUTBOX != (sizeof(G_dcom_slv_outbox_tx))) );
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+// Function Specification
+//
+// Name: dcom_build_slv_outbox
+//
+// Description: The purpose of this function is to fill out the Sensor Data into the
+// Slave Outbox Structures for transfer to the Master.
+// Build the slave outboxes so slave can send to master
+//
+// Flow: 09/21/11 FN=dcom_build_slv_outbox
+//
+// End Function Specification
+
+uint32_t dcom_build_slv_outbox(void)
+{
+ // Locals
+ uint32_t l_addr_of_slv_outbox_in_main_mem = 0;
+
+ static uint8_t L_seq = 0xFF;
+
+ L_seq++;
+
+ G_dcom_slv_outbox_tx.seq = L_seq;
+ G_dcom_slv_outbox_tx.version = 0;
+
+ memset( G_dcom_slv_outbox_tx.occ_fw_mailbox, 0, sizeof( G_dcom_slv_outbox_tx.occ_fw_mailbox ));
+
+ G_dcom_slv_outbox_tx.counter++; // @th002
+
+ // @01
+ // call dcom_build_occfw_msg
+ dcom_build_occfw_msg( SLAVE_OUTBOX );
+
+ // Create message that will be sent to DCM peer
+ dcom_build_dcm_sync_msg( SLAVE_OUTBOX ); // @th010
+
+ l_addr_of_slv_outbox_in_main_mem = dcom_which_buffer_slv_outbox();
+
+ l_addr_of_slv_outbox_in_main_mem += G_pob_id.chip_id*sizeof(dcom_slv_outbox_t);
+
+ G_dcom_slv_outbox_doorbell_tx.pob_id = G_pob_id;
+ G_dcom_slv_outbox_doorbell_tx.pcap_valid = g_amec->pcap_valid; //@rt004a
+ G_dcom_slv_outbox_doorbell_tx.active_node_pcap = g_amec->pcap.active_node_pcap; //@rt001a
+ G_dcom_slv_outbox_doorbell_tx.addr_slv_outbox_buffer = l_addr_of_slv_outbox_in_main_mem;
+
+
+ return l_addr_of_slv_outbox_in_main_mem;
+}
+
+
+// Function Specification
+//
+// Name: dcom_which_buffer_slv_outbox
+//
+// Description: Determines which buffer in the 'double buffer'
+// or ping/pong to use. Basically alternates between
+// returning the ping or the pong address
+//
+// Flow: 09/21/11 FN=dcom_which_buffer_slv_outbox
+//
+// End Function Specification
+
+uint32_t dcom_which_buffer_slv_outbox(void)
+{
+ //Locals
+ uint32_t l_mem_address = ADDR_SLAVE_OUTBOX_MAIN_MEM_PONG;
+
+ // switch back and forth based on tick
+ if( CURRENT_TICK & 1 )
+ {
+ l_mem_address = ADDR_SLAVE_OUTBOX_MAIN_MEM_PING;
+ }
+
+ return l_mem_address;
+}
+
+
+// Function Specification
+//
+// Name: dcom_calc_slv_outbox_addr
+//
+// Description: get slave outbox main memory address
+//
+// Flow: 09/20/11 FN=dcom_calc_slv_outbox_addr
+//
+// End Function Specification
+uint32_t dcom_calc_slv_outbox_addr( const dcom_slv_outbox_doorbell_t * i_doorbell, uint8_t * o_occ_id )
+{
+ *o_occ_id = i_doorbell->pob_id.chip_id;
+ return i_doorbell->addr_slv_outbox_buffer;
+}
+
+
+// Function Specification
+//
+// Name: task_dcom_tx_slv_outbox
+//
+// Description: Copy slave outboxes from SRAM to main memory
+// so slave can send data to master
+//
+// Flow: 09/21/11 FN=task_dcom_tx_slv_outbox
+//
+// Task Flags: RTL_FLAG_NONMSTR, RTL_FLAG_MSTR, RTL_FLAG_OBS, RTL_FLAG_ACTIVE,
+// RTL_FLAG_NOAPSS, RTL_FLAG_RUN, RTL_FLAG_MSTR_READY
+//
+// End Function Specification
+void task_dcom_tx_slv_outbox( task_t *i_self)
+{
+ static bool l_error = FALSE;
+ uint32_t l_orc = OCC_SUCCESS_REASON_CODE;
+ uint32_t l_orc_ext = OCC_NO_EXTENDED_RC; // @nh001a
+ // @sb003 Use a static local bool to track whether the BCE request used
+ // here has ever been successfully created at least once
+ static bool L_bce_slv_outbox_tx_request_created_once = FALSE;
+
+ DCOM_DBG("3. TX Slave Outboxes\n");
+
+ do
+ {
+ // build/setup outbox
+ uint32_t l_addr_in_mem = dcom_build_slv_outbox();
+ uint32_t l_ssxrc = 0;
+
+ // @sb003
+ // See dcomMasterRx.c/task_dcom_rx_slv_outboxes for details on the
+ // checking done here before creating and scheduling the request.
+ bool l_proceed_with_request_and_schedule = FALSE;
+ int l_req_idle = async_request_is_idle(&(G_slv_outbox_tx_pba_request.request));
+ int l_req_complete = async_request_completed(&(G_slv_outbox_tx_pba_request.request));
+
+ if (!L_bce_slv_outbox_tx_request_created_once)
+ {
+ // Do this case first, all other cases assume that this is
+ // true!
+ // This is the first time we have created a request so
+ // always proceed with request create and schedule
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && l_req_complete)
+ {
+ // Most likely case first. The request was created
+ // and scheduled and has completed without error. Proceed.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ }
+ else if (l_req_idle && !l_req_complete)
+ {
+ // There was an error on the schedule request or the request
+ // was scheduled but was canceled, killed or errored out.
+ // Proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = TRUE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv outbox tx request idle but not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_outbox_tx_pba_request.request.callback_rc,
+ G_slv_outbox_tx_pba_request.request.options,
+ G_slv_outbox_tx_pba_request.request.state,
+ G_slv_outbox_tx_pba_request.request.abort_state,
+ G_slv_outbox_tx_pba_request.request.completion_state);
+ TRAC_INFO("Proceeding with BCE slv outbox tx request and schedule");
+ }
+ else if (!l_req_idle && !l_req_complete)
+ {
+ // The request was created and scheduled but is still in
+ // progress or still enqueued OR there was some error
+ // creating the request so it was never scheduled. The latter
+ // case is unlikely and will generate an error message when
+ // it occurs. It will also have to happen after the request
+ // was created at least once or we'll never get here. If the
+ // request does fail though before the state parms in the
+ // request are reset (like a bad parameter error), then this
+ // represents a hang condition that we can't recover from.
+ // DO NOT proceed with request create and schedule.
+ l_proceed_with_request_and_schedule = FALSE;
+ // Trace important information from the request
+ TRAC_INFO("BCE slv outbox tx request not idle and not complete, \
+ callback_rc=%d options=0x%x state=0x%x abort_state=0x%x \
+ completion_state=0x%x",
+ G_slv_outbox_tx_pba_request.request.callback_rc,
+ G_slv_outbox_tx_pba_request.request.options,
+ G_slv_outbox_tx_pba_request.request.state,
+ G_slv_outbox_tx_pba_request.request.abort_state,
+ G_slv_outbox_tx_pba_request.request.completion_state);
+ TRAC_INFO("NOT proceeding with BCE slv outbox tx request and schedule");
+ }
+ // else {// This case can't happen, ignore it.}
+
+ // @sb003 Only proceed if the BCE request state checked out
+ if (l_proceed_with_request_and_schedule)
+ {
+ // set up outbox copy request
+ l_ssxrc = bce_request_create(
+ &G_slv_outbox_tx_pba_request, // block copy object
+ &G_pba_bcue_queue, // mainstore to sram copy engine
+ l_addr_in_mem, // mainstore address
+ (uint32_t) &G_dcom_slv_outbox_tx, // sram starting address
+ sizeof(G_dcom_slv_outbox_tx), // size of copy
+ SSX_WAIT_FOREVER, // no timeout
+ (AsyncRequestCallback)dcom_tx_slv_outbox_doorbell, // call back
+ NULL, // call back arguments
+ ASYNC_CALLBACK_IMMEDIATE // callback mask
+ );
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_TX_SLV_OUTBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_CREATE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request create failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_CREATE_FAILURE; // @nh001a
+ break;
+ }
+
+ // @sb003 Request created at least once
+ L_bce_slv_outbox_tx_request_created_once = TRUE; // @sb013
+ l_ssxrc = bce_request_schedule(&G_slv_outbox_tx_pba_request); // actual copying
+
+ if(l_ssxrc != SSX_OK)
+ {
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_TASK_TX_SLV_OUTBOX
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 ERC_BCE_REQUEST_SCHEDULE_FAILURE
+ * @devdesc SSX BCE related failure
+ */
+ TRAC_ERR("PBA request schedule failure rc=[%08X]",l_ssxrc);
+ l_orc = SSX_GENERIC_FAILURE; // @nh001c
+ l_orc_ext = ERC_BCE_REQUEST_SCHEDULE_FAILURE; // @nh001a
+ break;
+ }
+ }
+
+ } while (0);
+
+
+ if ( l_orc != OCC_SUCCESS_REASON_CODE && l_error == FALSE)
+ {
+ // create and commit error
+ // see return code doxygen tags for error description
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_TASK_TX_SLV_OUTBOX, //modId
+ l_orc, //reasoncode // @nh001c
+ l_orc_ext, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ 0, //userdata1
+ 0 //userdata2
+ );
+
+ // @wb001 -- Callout firmware
+ addCalloutToErrl(l_errl,
+ ERRL_CALLOUT_TYPE_COMPONENT_ID,
+ ERRL_COMPONENT_ID_FIRMWARE,
+ ERRL_CALLOUT_PRIORITY_HIGH);
+
+ commitErrl( &l_errl );
+
+ // TODO request a reset
+ l_error = TRUE;
+ }
+
+}
+
+
+// Function Specification
+//
+// Name: dcom_tx_slv_outbox_doorbell
+//
+// Description: transmit unicast doorbell to master
+// from slaves
+//
+// Flow: 09/21/11 FN=dcom_tx_slv_outbox_doorbell
+//
+// End Function Specification
+void dcom_tx_slv_outbox_doorbell( void )
+{
+ static bool l_error = FALSE;
+ int l_pbarc = 0;
+ uint64_t l_tmp =0;
+
+ // save into temp
+ memcpy( &l_tmp, &G_dcom_slv_outbox_doorbell_tx, sizeof(dcom_slv_outbox_doorbell_t));
+
+ // send unicast doorbell
+ l_pbarc = _pbax_send( //gm014
+ &G_pbax_unicast_target,
+ l_tmp,
+ SSX_MICROSECONDS(15));
+
+ if ( l_pbarc != 0 && l_error == FALSE )
+ {
+ //failure occurred
+ //This is running in a critical interrupt context. Tracing not allowed!
+ //TRAC_ERR("PBAX Send Failure in transimitting unicast doorbell - RC[%08X]", l_pbarc);
+
+ l_error = TRUE;
+
+ // create and commit error
+#if 0 //try again on the next tick
+ /* @
+ * @errortype
+ * @moduleid DCOM_MID_SLV_OUTBOX_TX_DOORBELL
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 N/A
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc SSX PBAX related failure
+ */
+ errlHndl_t l_errl = createErrl(
+ DCOM_MID_SLV_OUTBOX_TX_DOORBELL, //modId
+ SSX_GENERIC_FAILURE, //reasoncode // @nh001c
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ 0, //userdata1
+ 0 //userdata2
+ );
+
+ commitErrl( &l_errl );
+
+ //TODO request a reset
+#endif
+ }
+}
+
+
+#endif //_DCOMSLAVETOMASTER_C
+
diff --git a/src/occ/dcom/dcom_service_codes.h b/src/occ/dcom/dcom_service_codes.h
new file mode 100755
index 0000000..761e95e
--- /dev/null
+++ b/src/occ/dcom/dcom_service_codes.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+// @file dcom_service_codes.h
+// @brief Error codes for dcom component.
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section _dcom_service_codes_h dcom_service_codes.h
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * abagepa 09/19/2011 Created new file
+ * @01 tapiar 10/09/2011 State 2 updates
+ * @02 tapiar 11/09/2011 State 3 updates
+ * @rc003 rickylie 02/03/2012 Verify & Clean Up OCC Headers & Comments
+ * @pb00E pbavari 03/11/2012 Added correct include file
+ * @gm037 925908 milesg 05/07/2014 Redundant OCC/APSS support
+ *
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOM_SERVICE_CODES_H_
+#define _DCOM_SERVICE_CODES_H_
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <comp_ids.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+enum dcomModuleId
+{
+ DCOM_MID_INIT_ROLES = DCOM_COMP_ID | 0x00,
+ DCOM_MID_TASK_RX_SLV_INBOX = DCOM_COMP_ID | 0x01,
+ DCOM_MID_TASK_TX_SLV_INBOX = DCOM_COMP_ID | 0x02,
+ DCOM_MID_INIT_PBAX_QUEUES = DCOM_COMP_ID | 0x03,
+ DCOM_MID_TASK_RX_SLV_OUTBOX = DCOM_COMP_ID | 0x04, //@01a
+ DCOM_MID_TASK_TX_SLV_OUTBOX = DCOM_COMP_ID | 0x05, //@01a
+ DCOM_MID_SLV_OUTBOX_TX_DOORBELL = DCOM_COMP_ID | 0x06, //@01a
+ DCOM_MID_TASK_WAIT_FOR_MASTER = DCOM_COMP_ID | 0x07, //@01a
+ DCOM_MID_ERROR_CHECK = DCOM_COMP_ID | 0x08, //@02a
+ DCOM_MID_WAIT_FOR_MASTER = DCOM_COMP_ID | 0x09, //@gm037
+};
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+#endif /* #ifndef _DCOM_SERVICE_CODES_H_ */
diff --git a/src/occ/dcom/dcom_thread.c b/src/occ/dcom/dcom_thread.c
new file mode 100755
index 0000000..fe62a1f
--- /dev/null
+++ b/src/occ/dcom/dcom_thread.c
@@ -0,0 +1,223 @@
+/******************************************************************************
+// @file dcom_thread.c
+// @brief OCC to OCC communication handler thread
+*/
+/******************************************************************************
+ *
+ * @page ChangeLogs Change Logs
+ * @section dcom_thread.c DCOM_THREAD.C
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * ------- ---------- -------- ---------- ----------------------------------
+ * @th022 thallet 07/11/2012 Pstate Enablement
+ * @th025 857856 thallet 10/16/2012 Dcom Master/Slave SMS part 2
+ * @th032 thallet 04/16/2013 Tuleta HW Bringup
+ * @th035 881654 thallet 05/06/2013 Tuleta Bringup Pstate Fixes
+ * @at015 885884 alvinwan 06/10/2013 Support Observation/Active state change
+ * @th042 892056 thallet 07/19/2013 Send OCC to safe mode if first APSS GPE fails
+ * @gm025 915973 milesg 02/14/2014 Full support for sapphire (KVM) mode
+ *
+ * @endverbatim
+ *
+ *///*************************************************************************/
+
+#ifndef _DCOM_THREAD_C
+#define _DCOM_THREAD_C
+
+/** \defgroup OCC-OCC Communication
+ *
+ */
+
+//*************************************************************************
+// Includes
+//*************************************************************************
+#include <pgp_pmc.h>
+#include "pgp_pba.h"
+#include <rtls.h>
+#include <apss.h>
+#include <dcom.h>
+#include <dcom_service_codes.h>
+#include <occ_service_codes.h>
+#include <trac.h>
+#include <state.h>
+#include <proc_pstate.h>
+
+//*************************************************************************
+// Externs
+//*************************************************************************
+
+//*************************************************************************
+// Macros
+//*************************************************************************
+
+//*************************************************************************
+// Defines/Enums
+//*************************************************************************
+
+//*************************************************************************
+// Structures
+//*************************************************************************
+
+//*************************************************************************
+// Globals
+//*************************************************************************
+
+// Debug Counter to make sure dcom thread is running
+uint16_t G_dcom_thread_counter = 0;
+
+SsxSemaphore G_dcomThreadWakeupSem; // @th025
+
+//*************************************************************************
+// Function Prototypes
+//*************************************************************************
+
+//*************************************************************************
+// Functions
+//*************************************************************************
+
+
+// Function Specification
+//
+// Name: Dcom_thread_routine
+//
+// Description: Purpose of this task is to handle messages passed from
+// Master to Slave and vice versa.
+//
+// Nothing in this thread should be time-critical, but should
+// happen more often than the 1-second that other threads run
+// at.
+//
+// This thread currently runs ~1ms, based on the RTL loop of
+// 250us.
+//
+// FWIW -- It is pointless to set this thread to run any more
+// often than the length of the RTL loop, since it is acting
+// on data passed back and forth via that loop.
+//
+// Flow: XX-XX-XX FN=
+//
+// End Function Specification
+void Dcom_thread_routine(void *arg)
+{
+ OCC_STATE l_newOccState = 0;
+ OCC_MODE l_newOccMode = 0;
+ SsxTimer l_timeout_timer;
+ errlHndl_t l_errlHndl = NULL; // @at015a
+ // --------------------------------------------------
+ // Create a timer that pops every 10 seconds to wake up
+ // this thread, in case a semaphore never gets posted.
+ // TODO: Is this really needed? @th035
+ // --------------------------------------------------
+ ssx_timer_create(&l_timeout_timer,
+ (SsxTimerCallback) ssx_semaphore_post,
+ (void *) &G_dcomThreadWakeupSem);
+ ssx_timer_schedule(&l_timeout_timer,
+ SSX_SECONDS(10),
+ SSX_SECONDS(10));
+
+ for(;;)
+ {
+ // --------------------------------------------------
+ // Wait on Semaphore until we get new data over DCOM
+ // (signalled by sem_post() or timeout occurs.
+ // Sem timeout is designed to be the slowest
+ // interval we will attempt to run this thread at.
+ // --------------------------------------------------
+
+ // Wait for sem_post before we run through this thread.
+ ssx_semaphore_pend(&G_dcomThreadWakeupSem, SSX_WAIT_FOREVER); // @th035
+
+ // --------------------------------------------------
+ // Counter to ensure thread is running (can wrap)
+ // --------------------------------------------------
+ G_dcom_thread_counter++;
+
+ // --------------------------------------------------
+ // Check if we need to update the sapphire table
+ // --------------------------------------------------
+ if(G_sysConfigData.system_type.kvm) //gm025
+ {
+ proc_check_for_sapphire_updates();
+ }
+
+ // --------------------------------------------------
+ // Set Mode and State Based on Master
+ // --------------------------------------------------
+ l_newOccState = (G_occ_master_state == CURRENT_STATE()) ? OCC_STATE_NOCHANGE : G_occ_master_state;
+ // @at019a
+ if(G_sysConfigData.system_type.kvm)
+ {
+ l_newOccMode = (G_occ_master_mode == G_occ_external_req_mode_kvm ) ? OCC_MODE_NOCHANGE : G_occ_master_mode;
+ }
+ else
+ {
+ l_newOccMode = (G_occ_master_mode == CURRENT_MODE() ) ? OCC_MODE_NOCHANGE : G_occ_master_mode;
+ }
+
+ // Override State if SAFE state is requested -- @th042
+ l_newOccState = ( isSafeStateRequested() ) ? OCC_STATE_SAFE : l_newOccState;
+
+ // Override State if we are in SAFE state already -- @th042
+ l_newOccState = ( OCC_STATE_SAFE == CURRENT_STATE() ) ? OCC_STATE_NOCHANGE : l_newOccState;
+
+ if( (OCC_STATE_NOCHANGE != l_newOccState)
+ || (OCC_MODE_NOCHANGE != l_newOccMode) )
+ {
+ // If we're active, then we should always process the mode change first
+ // If we're not active, then we should always process the state change first
+ // @at015c - start
+ if(OCC_STATE_ACTIVE == CURRENT_STATE())
+ {
+ // Set the new mode
+ l_errlHndl = SMGR_set_mode(l_newOccMode, 0 /* TODO V/F */ );
+ if(l_errlHndl)
+ {
+ commitErrl(&l_errlHndl);
+ }
+ // Set the new state
+ l_errlHndl = SMGR_set_state(l_newOccState);
+ if(l_errlHndl)
+ {
+ commitErrl(&l_errlHndl);
+ }
+ }
+ else
+ {
+ // Set the new state
+ l_errlHndl = SMGR_set_state(l_newOccState);
+ if(l_errlHndl)
+ {
+ commitErrl(&l_errlHndl);
+ }
+ // Set the new mode
+ l_errlHndl = SMGR_set_mode(l_newOccMode, 0 /* TODO V/F */ );
+ if(l_errlHndl)
+ {
+ commitErrl(&l_errlHndl);
+ }
+ }
+ // @at015c - end
+ }
+
+ // --------------------------------------------------
+ // DCM PStates
+ // \_ can do sem_post to increment through state machine
+ // --------------------------------------------------
+ if(OCC_STATE_SAFE != CURRENT_STATE()) // @th042
+ {
+ proc_gpsm_dcm_sync_enable_pstates_smh();
+ }
+
+ // --------------------------------------------------
+ // SSX Sleep
+ // --------------------------------------------------
+ // Even if semaphores are continually posted, there is no reason
+ // for us to run this thread any more often than once every 250us
+ // so we don't starve any other thread
+ ssx_sleep(SSX_MICROSECONDS(250)); // @th025
+ }
+}
+
+#endif //_DCOM_THREAD_C
+
OpenPOWER on IntegriCloud