diff options
author | William Bryan <wilbryan@us.ibm.com> | 2015-08-03 12:38:58 -0500 |
---|---|---|
committer | William A. Bryan <wilbryan@us.ibm.com> | 2015-08-03 15:32:27 -0500 |
commit | 420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch) | |
tree | c9f6691eddba39193e39aa769367e1267fb9fc86 /src/occ_405/dcom/dcom.c | |
parent | adade8c8ef30ed519322674c762d95663009c5d4 (diff) | |
download | talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip |
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503
Reviewed-by: William A. Bryan <wilbryan@us.ibm.com>
Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/occ_405/dcom/dcom.c')
-rwxr-xr-x | src/occ_405/dcom/dcom.c | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/src/occ_405/dcom/dcom.c b/src/occ_405/dcom/dcom.c new file mode 100755 index 0000000..5b9f112 --- /dev/null +++ b/src/occ_405/dcom/dcom.c @@ -0,0 +1,814 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ/dcom/dcom.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef _DCOM_C +#define _DCOM_C + +#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" + +#define PBAX_CONFIGURE_RCV_GROUP_MASK 0xff + +#define PBAX_BROADCAST_GROUP 0xFF + +extern uint8_t G_occ_interrupt_type; + +dcom_timing_t G_dcomTime; + +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; + +// DCM Status from all Slaves +proc_gpsm_dcm_sync_occfw_t G_dcm_sync_occfw_table[MAX_OCCS]; + +// 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}; + +// 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 +// +// 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 + G_dcomTime.base = ssx_timebase_get(); + + // 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 + + if( l_rc == 0 ) + { + // 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 by + // 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)) + { + // TODO: Check if possible to use node_id read from the chip GPIOs + + // 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]; + } + 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 + ERC_CHIP_IDS_INVALID, //Extended reasoncode + 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 + ); + + // 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; + } + } + + // If this is a FSP-less system, then use the node ID as the + // chip ID. This is because the HW assigns the OCCs as being in + // different nodes with the same chip IDs. + if (G_occ_interrupt_type != FSP_SUPPORTED_OCC) + { + G_pob_id.node_id = 0; + G_pob_id.chip_id = l_tp_gp0_read.fields.tc_node_id_dc; + + TRAC_IMP("dcom_initialize_roles: Overriding chip_id[%d] with node_id[%d]", + l_tp_gp0_read.fields.tc_chip_id_dc, + l_tp_gp0_read.fields.tc_node_id_dc); + } + + // 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; + //rtl_set_run_mask(RTL_FLAG_NOTMSTR); + + // For Simics, we need to start as OCC Master + G_occ_role = OCC_MASTER; + rtl_set_run_mask(RTL_FLAG_MSTR); + + // 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() ); + } + 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 + ERC_GETSCOM_FAILURE, //Extended reasoncode + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + l_rc, //Userdata1 + 0 //Userdata2 + ); + + // Callout firmware + addCalloutToErrl(l_errl, + ERRL_CALLOUT_TYPE_COMPONENT_ID, + ERRL_COMPONENT_ID_FIRMWARE, + ERRL_CALLOUT_PRIORITY_HIGH); + + // Commit log + commitErrl( &l_errl ); + + // 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); + G_occ_num_present = __builtin_popcount(G_sysConfigData.is_occ_present); + + // Initialize DCOM Thread Sem + ssx_semaphore_create( &G_dcomThreadWakeupSem, // Semaphore + 1, // Initial Count + 0); // No Max Count + +} + +// Function Specification +// +// Name: dcom_initialize_pbax_queues +// +// Description: Initialize the PBAX Queues for sending doorbells +// +// 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 ) || + ( 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. + 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; + } + } + + 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 + 0, // 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 + OCC_NO_EXTENDED_RC, //Extended reasoncode + ERRL_SEV_UNRECOVERABLE, //Severity + NULL, //Trace Buf + DEFAULT_TRACE_SIZE, //Trace Size + l_rc, //Userdata1 + 0 //Userdata2 + ); + + // Commit log and request reset + REQUEST_RESET(l_errl); + } +} + +// Function Specification +// +// Name: dcom_pbusid2pbaxid +// +// Description: Translate between PowerBus ID and pbax ID +// +// 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 +// +// 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) +{ + static uint16_t L_rx_slv_outbox_fail_count = 0; + uint16_t l_modId = 0; + 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; + } + // 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; + } + + 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 + i_orc, //Reasoncode + i_orc_ext, //Extended reasoncode + 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 + i_orc, //Reasoncode + i_orc_ext, //Extended reasoncode + 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); + } + } +} + +// 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 +// +// End Function Specification +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++) + { + // 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) + { + 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 +// +// 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(); + + 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(); + } + + 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. +// +// 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(); + + 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(); + } + + // 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]) ) + { + if( ! isSafeStateRequested() ) + { + 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); + } + } + + // 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 ) + { + // Update the system mode frequencies if they have changed + int l_mode = 0; + bool l_change = FALSE; + bool l_all_zero = TRUE; + + // 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)); + } + } + + // Copy mnfg parameters into g_amec structure + 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); + + // 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 + |