diff options
author | Stephan Broyles <sbroyles@us.ibm.com> | 2014-11-05 19:09:37 -0600 |
---|---|---|
committer | Stephan Broyles <sbroyles@us.ibm.com> | 2014-11-05 19:22:32 -0600 |
commit | 9976c207cdb20871880bd2f4cf123cf4cb6a8b0f (patch) | |
tree | 1cf9ed8f23085e6fe3e0e6046fc30dcb7e02ccf2 /src/occ/dcom | |
parent | 2f8ce357b89d361b5091d88aea91416011b73ccb (diff) | |
download | talos-occ-9976c207cdb20871880bd2f4cf123cf4cb6a8b0f.tar.gz talos-occ-9976c207cdb20871880bd2f4cf123cf4cb6a8b0f.zip |
Added remaining occ files.
Change-Id: I91a748d3dcf3161a6a3eedcb376fcaf1e4dfe655
Diffstat (limited to 'src/occ/dcom')
-rwxr-xr-x | src/occ/dcom/dcom.c | 902 | ||||
-rwxr-xr-x | src/occ/dcom/dcom.h | 585 | ||||
-rw-r--r-- | src/occ/dcom/dcomMasterRx.c | 430 | ||||
-rwxr-xr-x | src/occ/dcom/dcomMasterTx.c | 628 | ||||
-rw-r--r-- | src/occ/dcom/dcomSlaveRx.c | 671 | ||||
-rwxr-xr-x | src/occ/dcom/dcomSlaveTx.c | 431 | ||||
-rwxr-xr-x | src/occ/dcom/dcom_service_codes.h | 73 | ||||
-rwxr-xr-x | src/occ/dcom/dcom_thread.c | 223 |
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 + |