diff options
Diffstat (limited to 'src/usr/htmgt')
-rw-r--r-- | src/usr/htmgt/htmgt.C | 169 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_activate.C | 148 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_activate.H | 79 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_common.mk | 10 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_config.H | 70 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_occ.C | 286 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_occ.H | 268 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_occcmd.C | 1210 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_occcmd.H | 304 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_poll.C | 141 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_poll.H | 78 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_utility.C | 79 | ||||
-rw-r--r-- | src/usr/htmgt/htmgt_utility.H | 65 | ||||
-rw-r--r-- | src/usr/htmgt/test/htmgt_occcmd_test.H | 335 | ||||
-rw-r--r-- | src/usr/htmgt/test/htmgt_test.H | 225 | ||||
-rw-r--r-- | src/usr/htmgt/test/makefile | 1 |
16 files changed, 3453 insertions, 15 deletions
diff --git a/src/usr/htmgt/htmgt.C b/src/usr/htmgt/htmgt.C new file mode 100644 index 000000000..e4625b0af --- /dev/null +++ b/src/usr/htmgt/htmgt.C @@ -0,0 +1,169 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/tmgtutility.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <htmgt/htmgt.H> +#include <htmgt/htmgt_reasoncodes.H> +#include "htmgt_activate.H" +#include "htmgt_config.H" +#include "htmgt_utility.H" + +// Targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> + + +namespace HTMGT +{ + + // Move the OCCs to active state or log unrecoverable error and + // stay in safe mode + void processOccStartStatus(const bool i_startCompleted, + TARGETING::Target * i_failedOccTarget) + { + errlHndl_t l_err = NULL; + + uint32_t l_huid = 0; + if (i_failedOccTarget) + { + l_huid = TARGETING::get_huid(i_failedOccTarget); + } + TMGT_INF("processOccStartStatus(Start Success=%c, failedOcc=0x%08X)", + i_startCompleted?'y':'n', l_huid); + if (i_startCompleted) + { + // Query functional OCCs + if (occMgr::instance().buildOccs() > 0) + { + // Build pstate tables + // TODO RTC 114284 + + // Calc memory throttles + // TODO RTC 116306 + + // Send ALL config data + sendOccConfigData(); + + // Wait for all OCCs to go active + l_err = waitForOccsActive(); + if (NULL == l_err) + { + // Set active sensors for all OCCs so BMC can start comm + l_err = setOccActiveSensors(); + } + } + else + { + TMGT_ERR("Unable to find any functional OCCs"); + /*@ + * @errortype + * @reasoncode HTMGT_RC_OCC_UNAVAILABLE + * @moduleid HTMGT_MOD_LOAD_START_STATUS + * @userdata1[0:7] load/start completed + * @devdesc No functional OCCs were found + */ + bldErrLog(l_err, HTMGT_MOD_LOAD_START_STATUS, + HTMGT_RC_OCC_UNAVAILABLE, + i_startCompleted, 0, 0, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else + { + TMGT_ERR("All OCCs were not loaded/started successfully"); + /*@ + * @errortype + * @reasoncode HTMGT_RC_OCC_START_FAIL + * @moduleid HTMGT_MOD_LOAD_START_STATUS + * @userdata1 Failing OCC HUID + * @devdesc OCCs were not loaded/started successfully + */ + bldErrLog(l_err, HTMGT_MOD_LOAD_START_STATUS, + HTMGT_RC_OCC_START_FAIL, + l_huid, 0, 0, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + + if (NULL != l_err) + { + TMGT_ERR("OCCs not all active. System will stay in safe mode"); + // TODO: RTC 109066 + //stopAllOccs(); + + // Update error log to unrecoverable and set SRC + // to indicate the system will remain in safe mode + /*@ + * @errortype + * @reasoncode HTMGT_RC_OCC_CRIT_FAILURE + * @moduleid HTMGT_MOD_LOAD_START_STATUS + * @userdata1[0:7] load/start completed + * @devdesc OCCs did not all reach active state, + * system will be in Safe Mode + */ + bldErrLog(l_err, HTMGT_MOD_LOAD_START_STATUS, + HTMGT_RC_OCC_CRIT_FAILURE, + i_startCompleted, 0, 0, 1, + ERRORLOG::ERRL_SEV_UNRECOVERABLE); + + // Add level 2 support callout + l_err->addProcedureCallout(HWAS::EPUB_PRC_LVL_SUPP, + HWAS::SRCI_PRIORITY_MED); + // Add HB firmware callout + l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_MED); + + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + + } + + } // end processOccStartStatus() + + + + // Notify HTMGT that an OCC has an error to report + void processOccError(TARGETING::Target * i_occTarget) + { + const uint32_t l_huid = i_occTarget->getAttr<TARGETING::ATTR_HUID>(); + TMGT_INF("processOccError(HUID=0x%08X) called", l_huid); + // TODO RTC 109224 + + } // end processOccError() + + + + + // Notify HTMGT that an OCC has failed and needs to be reset + void processOccReset(TARGETING::Target * i_failedOccTarget) + { + const uint32_t l_huid = + i_failedOccTarget->getAttr<TARGETING::ATTR_HUID>(); + TMGT_INF("processOccReset(HUID=0x%08X) called", l_huid); + // TODO RTC 115296 + + } // end processOccReset() + +} + diff --git a/src/usr/htmgt/htmgt_activate.C b/src/usr/htmgt/htmgt_activate.C new file mode 100644 index 000000000..e094b491f --- /dev/null +++ b/src/usr/htmgt/htmgt_activate.C @@ -0,0 +1,148 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_activate.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <htmgt/htmgt.H> +#include <htmgt/htmgt_reasoncodes.H> +#include "htmgt_utility.H" +#include "htmgt_activate.H" +#include "htmgt_occcmd.H" +#include "htmgt_config.H" +#include "htmgt_poll.H" + +// Targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> + + +namespace HTMGT +{ + +// TODO RTC 118875 +#ifdef SIMICS_TESTING + uint8_t * G_simicsHomerBuffer = NULL; +#endif + + + // Send all config data to the OCCs + // (see ToifNode::toif_manager_config() in src/tmgt/fsp/tmgt_toifnode.C) + void sendOccConfigData() + { + TMGT_INF("sendOccConfigData: STUB"); + // TODO RTC 109066 + } + + + + // Wait for all OCCs to reach active ready state + // (see ToifNode::wait_for_occ_ready() in tmgt_toifnode.C) + errlHndl_t waitForOccReady() + { + errlHndl_t l_err = NULL; + + l_err = sendOccPoll(); + + // TODO RTC 109066 + if (NULL == l_err) + { + TMGT_ERR("waitForOccReady: Stub forcing failure"); + /*@ + * @errortype + * @reasoncode HTMGT_RC_OCC_UNAVAILABLE + * @moduleid HTMGT_MOD_WAIT_FOR_OCC_READY + * @devdesc OCCs did not reach active ready state + */ + bldErrLog(l_err, HTMGT_MOD_WAIT_FOR_OCC_READY, + HTMGT_RC_OCC_UNAVAILABLE, + 0, 0, 0, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + + return l_err; + } + + + + errlHndl_t setOccState(const occStateId i_state) + { + errlHndl_t l_err = NULL; + + TMGT_INF("setOccState: STUB"); + // TODO RTC 109066 + + return l_err; + } + + + + // Wait for all OCCs to reach active state + errlHndl_t waitForOccsActive() + { + errlHndl_t l_err = NULL; + + TMGT_INF("wait_for_occs_active called"); + + // Wait for attns - not needed? + + // Wait for all OCCs to be ready for active state + l_err = waitForOccReady(); + if (NULL == l_err) + { + // Send Set State (ACTIVE) to master + l_err = setOccState(OCC_STATE_ACTIVE); + if (NULL == l_err) + { + TMGT_INF("waitForOccsActive: OCCs are all active"); + } + } + else + { + TMGT_ERR("waitForOccsActive: OCC(s) are not in active ready"); + } + + return l_err; + + } // end waitForOccsActive() + + + + // Set active sensors for all OCCs so BMC can start communication + errlHndl_t setOccActiveSensors() + { + errlHndl_t l_err = NULL; + + TMGT_INF("setOccActiveSensors: STUB"); + // TODO RTC 109066 + + return l_err; + } + + + +} // end namespace + + + diff --git a/src/usr/htmgt/htmgt_activate.H b/src/usr/htmgt/htmgt_activate.H new file mode 100644 index 000000000..83cc79cec --- /dev/null +++ b/src/usr/htmgt/htmgt_activate.H @@ -0,0 +1,79 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_activate.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 HTMGT_ACTIVATE_H +#define HTMGT_ACTIVATE_H + +#include <stdint.h> +#include "htmgt_occ.H" +#include <errl/errlmanager.H> + + +// TODO RTC 118875 +//#define SIMICS_TESTING + + +namespace HTMGT +{ + + /** + * @brief Build the pstate tables + */ + void buildPstateTables(); + + + /** + * @brief Calculate memory throttles + */ + void calculateMemoryThrottles(); + + + /** + * @brief Set the OCC state + * + * @param[in] i_state Desired OCC state + * + * @return NULL if success, else error handle + */ + errlHndl_t setOccState(const occStateId i_state); + + + /** + * @brief Wait for all OCCs to go to active state + * + * @return NULL if all OCCs reached active state, else error handle + */ + errlHndl_t waitForOccsActive(); + + + /** + * @brief Set active sensors for all OCCs so BMC can start communication + * + * @return NULL if all sensors were updated, else error handle + */ + errlHndl_t setOccActiveSensors(); + +} // end namespace +#endif diff --git a/src/usr/htmgt/htmgt_common.mk b/src/usr/htmgt/htmgt_common.mk index d2cc0d3bb..589cedd1b 100644 --- a/src/usr/htmgt/htmgt_common.mk +++ b/src/usr/htmgt/htmgt_common.mk @@ -23,4 +23,14 @@ # # IBM_PROLOG_END_TAG # common objects between hostboot and hbrt +OBJS += htmgt.o +OBJS += htmgt_occ.o +OBJS += htmgt_activate.o +OBJS += htmgt_occcmd.o +OBJS += htmgt_poll.o OBJS += htmgt_utility.o + +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp diff --git a/src/usr/htmgt/htmgt_config.H b/src/usr/htmgt/htmgt_config.H new file mode 100644 index 000000000..e87c5f381 --- /dev/null +++ b/src/usr/htmgt/htmgt_config.H @@ -0,0 +1,70 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/tmgtutility.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 HTMGT_CONFIG_H +#define HTMGT_CONFIG_H + +#include <stdint.h> + +namespace HTMGT +{ + + extern const uint8_t NUM_CFG_FORMATS; + + enum occCfgDataFormat + { + OCC_CFGDATA_NO_REQUEST = 0x00, // no request for config data + OCC_CFGDATA_PSTATE_SSTRUCT = 0x01, // Psate Super Structure + OCC_CFGDATA_FREQ_POINT = 0x02, // Frequency Operating Points + OCC_CFGDATA_OCC_ROLE = 0x03, // OCC Role + OCC_CFGDATA_APSS_CONFIG = 0x04, // APSS Config + OCC_CFGDATA_MEM_CONFIG = 0x05, // Memory Configuration + OCC_CFGDATA_FIR_SCOMS = 0x06, // FIR Scoms Table + OCC_CFGDATA_PCAP_CONFIG = 0x07, // PCAP Config + OCC_CFGDATA_SYS_CONFIG = 0x0F, // System Configuration + OCC_CFGDATA_MEM_THROTTLE = 0x12, // Memory Throttle Settings + OCC_CFGDATA_TCT_CONFIG = 0x13, // Thermal Contorl Treshold + + OCC_CFGDATA_FORMAT_END, // Marker to indicate last entry + OCC_CFGDATA_CLEAR_ALL = 0xFF, // Clear All Active Config Data + }; + + + enum occDataState + { + OCC_DATA_NOT_AVAILABLE = 0x00, + OCC_DATA_AVAILABLE = 0x01, + OCC_DATA_NEEDS_TO_BE_SENT = 0x02, + }; + + + + // Send all config data to the OCCs + void sendOccConfigData(); + + + +} // end namespace + +#endif diff --git a/src/usr/htmgt/htmgt_occ.C b/src/usr/htmgt/htmgt_occ.C new file mode 100644 index 000000000..2d0aaca11 --- /dev/null +++ b/src/usr/htmgt/htmgt_occ.C @@ -0,0 +1,286 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_occ.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <htmgt/htmgt.H> +#include <htmgt/htmgt_reasoncodes.H> +#include "htmgt_utility.H" +#include "htmgt_occcmd.H" +#include "htmgt_config.H" +#include "htmgt_occ.H" + +// Targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> + + +using namespace HTMGT; + + +namespace HTMGT +{ + + Occ::Occ(const uint8_t i_instance, + const bool i_masterCapable, + uint8_t * i_homer, + TARGETING::TargetHandle_t i_target, + const occRole i_role) + :instance(i_instance), + masterCapable(i_masterCapable), + role(i_role), + state(OCC_STATE_UNKNOWN), + commEstablished(false), + needsReset(false), + failed(false), + seqNumber(0), + homer(i_homer), + target(i_target), + lastPollValid(false), + version(0x01) + { + // Probably not needed... + huid = i_target->getAttr<TARGETING::ATTR_HUID>(); + } + + Occ::~Occ() + { + } + + + OccManager::OccManager() + :iv_occMaster(NULL), + iv_state(OCC_STATE_UNKNOWN) + { + } + + + OccManager::~OccManager() + { + } + + + // Remove all OCC objects + void OccManager::_removeAllOccs() + { + iv_occMaster = NULL; + if (iv_occArray.size() > 0) + { + for (std::vector<Occ*>::iterator pOcc = iv_occArray.begin(); + pOcc < iv_occArray.end(); + pOcc++) + { + TMGT_INF("removeAllOccs: Removing OCC%d", + (*pOcc)->getInstance()); + delete (*pOcc); + } + iv_occArray.clear(); + } + } + + + // Query the functional OCCs and build OCC objects + uint32_t OccManager::_buildOccs() + { + TMGT_INF("buildOccs called"); + + // Remove existing OCC objects + _removeAllOccs(); + + // Get all functional processors + TARGETING::TargetHandleList pProcs; + TARGETING::getChipResources(pProcs, + TARGETING::TYPE_PROC, + TARGETING::UTIL_FILTER_FUNCTIONAL); + if (pProcs.size() > 0) + { + // for each functional processor + for(TARGETING::TargetHandleList::iterator proc = pProcs.begin(); + proc != pProcs.end(); + ++proc) + { + // Instance number for this Processor/OCC + const uint8_t instance = + (*proc)->getAttr<TARGETING::ATTR_POSITION>(); + TMGT_INF("buildOccs: PROC%d is functional", instance); + // Get HOMER virtual address + uint8_t * homer = (uint8_t*) + ((*proc)->getAttr<TARGETING::ATTR_HOMER_VIRT_ADDR>()); + TMGT_INF("buildOccs: homer = 0x%08X (from proc 0)", homer); +#ifdef SIMICS_TESTING + // Starting of OCCs is not supported in SIMICS, so fake out + // HOMER memory area for testing + if (NULL == homer) + { + extern uint8_t * G_simicsHomerBuffer; + + if (NULL == G_simicsHomerBuffer) + { + // Allocate a fake HOMER area + G_simicsHomerBuffer = + new uint8_t [HTMGT_OCC_CMD_ADDR+0x2000]; + } + homer = G_simicsHomerBuffer; + TMGT_ERR("buildOccs: Using hardcoded HOMER of 0x%08lX", + homer); + } +#endif + + // Get functional OCC (one per proc) + TARGETING::TargetHandleList pOccs; + getChildChiplets(pOccs, *proc, TARGETING::TYPE_OCC); + if (pOccs.size() > 0) + { + const unsigned long huid = + pOccs[0]->getAttr<TARGETING::ATTR_HUID>(); + const bool masterCapable = + pOccs[0]->getAttr<TARGETING::ATTR_OCC_MASTER_CAPABLE>(); + + TMGT_INF("Found OCC %d - HUID: 0x%0lX, masterCapable: %c," + " homer: 0x%0lX", + instance, huid, masterCapable?'Y':'N', homer); + _addOcc(instance, masterCapable, homer, pOccs[0]); + } + else + { + // OCC must not be functional + TMGT_ERR("OCC%d not functional", instance); + } + } + } + else + { + TMGT_ERR("No functional processors found"); + } + + TMGT_INF("buildOccs: OCC Targets found = %d", _getNumOccs()); + + return _getNumOccs(); + + } // end OccManager::_buildOccs() + + + + /* Add a functional OCC to be monitored */ + void OccManager::_addOcc(const uint8_t i_instance, + const bool i_masterCapable, + uint8_t * i_homer, + TARGETING::TargetHandle_t i_target) + { + TMGT_INF("addOcc(%d, masterCapable=%c)", + i_instance, i_masterCapable?'y':'n'); + + occRole role = OCC_ROLE_SLAVE; + if (true == i_masterCapable) + { + if (NULL == iv_occMaster) + { + // No master assigned yet, use this OCC + TMGT_INF("addOcc: OCC%d will be the master", i_instance); + role = OCC_ROLE_MASTER; + } + else + { + role = OCC_ROLE_BACKUP_MASTER; + } + } + + Occ * l_occ = new Occ(i_instance, + i_masterCapable, + i_homer, + i_target, + role); + + // Add OCC to the array + iv_occArray.push_back(l_occ); + + if (OCC_ROLE_MASTER == role) + { + iv_occMaster = l_occ; + } + + } // end OccManager::_addOcc() + + + + uint8_t OccManager::getNumOccs() + { + return Singleton<OccManager>::instance()._getNumOccs(); + } + + + std::vector<Occ*> OccManager::getOccArray() + { + return Singleton<OccManager>::instance()._getOccArray(); + } + + + uint32_t OccManager::buildOccs() + { + return Singleton<OccManager>::instance()._buildOccs(); + } + + + Occ * OccManager::getMasterOcc() + { + return Singleton<OccManager>::instance()._getMasterOcc(); + } + + + +#if 0 + // TODO: RTC 109066 + void update_occ_data() + { + if (occMgr::instance().getNumOccs() > 0) + { + // TBD: define as one block of data or in each OCC target? + + uint32_t dataSize = occMgr::instance().getNumOccs() * + sizeof(occInstance); + if (dataSize > 256) + { + TMGT_ERR("update_occ_data: data exceeds attr size, truncating"); + dataSize = 256; + } + // Update OCC_CONTROL_DATA Attribute + bool success = ->trySetAttr<ATTR_OCC_CONTROL_DATA>(dataSize, G_occ); + if (false == success) + { + TMGT_ERR("update_occ_data: failed to update OCC_CONTROL_DATA"); + } + } + else + { + TMGT_INF("update_occ_data: No OCC data to update"); + } + } // end update_occ_data() +#endif + + +} // end namespace + + + diff --git a/src/usr/htmgt/htmgt_occ.H b/src/usr/htmgt/htmgt_occ.H new file mode 100644 index 000000000..64daf73c9 --- /dev/null +++ b/src/usr/htmgt/htmgt_occ.H @@ -0,0 +1,268 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_occ.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 HTMGT_OCC_H +#define HTMGT_OCC_H + +#include <stdint.h> +#include <vector> + + +namespace HTMGT +{ + + const uint8_t MASTER_OCC = 0xFF; + + const uint32_t OCC_POLL_DATA_MIN_SIZE = 40; + + + enum occStateId + { + OCC_STATE_NO_CHANGE = 0x00, + OCC_STATE_STANDBY = 0x01, + OCC_STATE_OBSERVATION = 0x02, + OCC_STATE_ACTIVE = 0x03, + OCC_STATE_SAFE = 0x04, + OCC_STATE_RESET = 0x05, + OCC_STATE_IN_TRANSITION = 0x07, + OCC_STATE_LOADING = 0x08, + OCC_STATE_UNKNOWN = 0x09, + }; + + enum occRole + { + OCC_ROLE_SLAVE = 0, + OCC_ROLE_MASTER = 1, + OCC_ROLE_BACKUP_MASTER = 2, + OCC_ROLE_FIR_MASTER = 3 + }; + + + + /** + * @class Occ + * + * @brief OCC data class + * + * @par Detailed Description: + * Provides configuration data for a specific OCC. + * Data will be saved during IPL so it can be used + * at runtime. + */ + class Occ + { + friend class OccManager; + friend class OccCmd; + + public: + /** + * @brief Constructor + * + * @param[in] i_instance OCC instance number + * @param[in] i_masterCapable Is OCC capable of being master + * @param[in] i_homer Virtual address of HOMER + * @param[in] i_target OCC target pointer + */ + Occ(const uint8_t i_instance, + const bool i_masterCapable, + uint8_t * i_homer, + TARGETING::TargetHandle_t i_target, + const occRole i_role); + + + /** + * @brief Destructor + */ + ~Occ(); + + + /** + * @brief Return the instance nubmer + * + * @return instance number for this OCC + */ + const uint8_t getInstance() { return instance; }; + + + /** + * @brief Return pointer to the last poll response + * + * @return pointer to last poll response + */ + const uint8_t *getLastPollRsp() { return lastPollResponse; }; + + + /** + * @brief Return pointer OCC target + * + * @return pointer to last poll response + */ + TARGETING::TargetHandle_t getTarget() { return target; }; + + + protected: + // Instance number of this OCC: 0 = first physical OCC + uint8_t instance; + // true if this OCC is capable of Master role (wired to APSS) + bool masterCapable; + // Role of this OCC + occRole role; + // State of this OCC + occStateId state; + // true if communication to this OCC has been established + bool commEstablished; + // true if OCC needs to be reset + bool needsReset; + // true if OCC failed + bool failed; + // Sequence number of last/current OCC command + uint8_t seqNumber; + // HOMER base address + uint8_t * homer; + // OCC target + TARGETING::TargetHandle_t target; + // Last poll response (excluding sensor data) + uint8_t lastPollResponse[OCC_POLL_DATA_MIN_SIZE]; + // true if lastPollResponse contains valid data + bool lastPollValid; + + // HOM Unit Id of this OCC + TARGETING::ATTR_HUID_type huid; + + + private: + // Version of data stored (0 = not written) + uint8_t version; + + }; + + + + /** + * @class OccManager + * + * @brief System / Node class + * + * @par Detailed Description: + * Manages all Occ classes and contains data specific to + * this system / node. + */ + class OccManager + { + friend class Occ; + + public: + /** + * @brief Constructor + */ + OccManager(); + + + /** + * @brief Destructor + */ + ~OccManager(); + + + /** + * @brief Query the functional OCCs and build OCC objects + * + * @return Return the number of OCC objects that were created + */ + static uint32_t buildOccs(); + + + /** + * @brief Get number of functional OCCs + * + * @return number of OCCs + */ + static uint8_t getNumOccs(); + + + /** + * @brief Return array of current OCCs + * + * @return vector of OCC objects + */ + static std::vector<Occ*> getOccArray(); + + + /** + * @brief Return pointer to master OCC + * + * @return pointer to master OCC + */ + static Occ * getMasterOcc(); + + + private: + Occ * iv_occMaster; + std::vector<Occ*> iv_occArray; + occStateId iv_state; + + /* See buildOccs() above */ + uint32_t _buildOccs(); + + + /* See getNumOccs() above */ + uint8_t _getNumOccs() { return iv_occArray.size(); }; + + + /* See getOccArray() above */ + std::vector<Occ*> _getOccArray() { return iv_occArray; }; + + + /** + * @brief Remove all OCC objects + */ + void _removeAllOccs(); + + + /** + * @brief Add a functional OCC to be monitored + * + * @param[in] i_instance OCC instance number + * @param[in] i_masterCapable Is OCC capable of being master + * @param[in] i_homer Virtual address of HOMER + * @param[in] i_target OCC target pointer + * @param[in] i_role OCC role + */ + void _addOcc(const uint8_t i_instance, + const bool i_masterCapable, + uint8_t * i_homer, + TARGETING::TargetHandle_t i_target); + + + /* See getMasterOcc() above */ + Occ * _getMasterOcc() { return iv_occMaster; }; + + + }; + + typedef Singleton<OccManager> occMgr; + +} // end namespace +#endif diff --git a/src/usr/htmgt/htmgt_occcmd.C b/src/usr/htmgt/htmgt_occcmd.C new file mode 100644 index 000000000..7a238b5d5 --- /dev/null +++ b/src/usr/htmgt/htmgt_occcmd.C @@ -0,0 +1,1210 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_occcmd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <htmgt/htmgt.H> +#include <htmgt/htmgt_reasoncodes.H> +#include "htmgt_occcmd.H" +#include "htmgt_config.H" +#include "htmgt_poll.H" + +// Targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> + +#include <ecmdDataBufferBase.H> + +#include <sys/time.h> +#include <trace/interface.H> +#include <errl/errlmanager.H> +#include <stdio.h> + +// TODO RTC 115922 +#ifdef __HOSTBOOT_RUNTIME +#include <runtime/interface.h> +#endif + + + +// TODO: RTC 115922 +#if 0 +#include <hwpf/hwp/occ/occAccess.H> +#else +namespace HBOCC +{ + + /** + * @brief Write OCC Circular Buffer + * + * @param[in] i_pTarget PROC or OCC target pointer + * @param[in] i_dataBuf Reference to data buffer + * @return errlHndl_t Error log if operation failed + */ + errlHndl_t writeCircularBuffer(const TARGETING::Target*i_pTarget, + ecmdDataBufferBase & i_dataBuf) + { + errlHndl_t l_err = NULL; + TRACFCOMP( HTMGT::g_trac_htmgt, "writeCircularBuffer(STUB): " + "setting status to 0xFF"); + return l_err; + } // end writeCircularBuffer() + +} //end OCC namespace +#endif + + + +namespace HTMGT +{ + uint8_t g_cmd = 0; + uint8_t g_seq = 0; + + struct occCircBufferCmd_t + { + uint8_t senderId; + uint8_t commandType; + uint8_t reserved[6]; + }__attribute__((packed)); + + + // Note: Read length must be 8 byte aligned (for SRAM reads) + const uint16_t RD_MAX = (OCC_MAX_DATA_LENGTH - 8); + const uint16_t TO_20SEC = 20 * 1000; + const occCommandTable_t OccCmd::cv_occCommandTable[] = + { + // Command Support RspCheck + // RspLen Timeout ReadMax Tracing + {OCC_CMD_POLL, 0xE0, OCC_CHECK_RSP_LENGTH_GREATER, + 0x0028, TO_20SEC, 0x0017, OCC_TRACE_EXTENDED}, + {OCC_CMD_CLEAR_ERROR_LOG, 0xC0, OCC_CHECK_RSP_LENGTH_EQUALS, + 0x0000, TO_20SEC, 0x0008, OCC_TRACE_EXTENDED}, + {OCC_CMD_SET_STATE, 0xE0, OCC_CHECK_RSP_LENGTH_EQUALS, + 0x0000, TO_20SEC, 0x0008, OCC_TRACE_ALWAYS}, + {OCC_CMD_SETUP_CFG_DATA, 0x80, OCC_CHECK_RSP_LENGTH_EQUALS, + 0x0000, TO_20SEC, 0x0008, OCC_TRACE_CONDITIONAL}, + {OCC_CMD_SET_POWER_CAP, 0x80, OCC_CHECK_RSP_LENGTH_NONE, + 0x0000, TO_20SEC, 0x0090, OCC_TRACE_EXTENDED}, + {OCC_CMD_RESET_PREP, 0x80, OCC_CHECK_RSP_LENGTH_GREATER, + 0x0006, TO_20SEC, 0x0190, OCC_TRACE_ALWAYS}, + {OCC_CMD_GET_FIELD_DEBUG_DATA, 0x80, OCC_CHECK_RSP_LENGTH_GREATER, + 0x0001, TO_20SEC, RD_MAX, OCC_TRACE_NEVER}, + + {OCC_CMD_END_OF_TABLE, 0x00, OCC_CHECK_RSP_LENGTH_EQUALS, + 0x0000, 0x0000, 0x0000, OCC_TRACE_NEVER} + }; + + + /** + * @brief Get the index of the specified command in the command table + * + * @param[in] i_cmd OCC command type + * + * @note If command not found/invalid, index to END_OF_TABLE will + * be returned and checked by caller + * + * @return index into command table + */ + uint8_t OccCmd::getCmdIndex(const occCommandType i_cmd) + { + uint8_t l_index = 0; + + // TODO RTC 109066 - convert to use lower_bound + //= find(&cv_occCommandTable[0], + // &cv_occCommandTable[OCC_CMDTABLE_SIZE-1], + // i_cmd); + + while ((cv_occCommandTable[l_index].cmdType != OCC_CMD_END_OF_TABLE) && + (cv_occCommandTable[l_index].cmdType != i_cmd)) + { + l_index++; + } + + if (cv_occCommandTable[l_index].cmdType == OCC_CMD_END_OF_TABLE) + { + TMGT_ERR("getCmdIndex: Invalid cmd (0x%02X) specified", i_cmd); + } + + return l_index; + } + + + + /** + * @brief Convert OCC response status to a string + * + * @param[in] i_status OCC response status + * + * @return text string describing status + */ + const char *rsp_status_string(const occReturnCodes i_status) + { + const uint8_t STATUS_STRING_COUNT = 11; + struct string_data_t + { + uint8_t str_num; + const char *str_data; + }; + const static struct string_data_t L_status_string[STATUS_STRING_COUNT]= + { + {OCC_RC_SUCCESS, "SUCCESS"}, + {OCC_RC_INVALID_COMMAND, "INVALID_COMMAND"}, + {OCC_RC_INVALID_COMMAND_LENGTH, "INVALID_COMMAND_LENGTH"}, + {OCC_RC_INVALID_DATA_FIELD, "INVALID_DATA_FIELD"}, + {OCC_RC_CHECKSUM_FAILURE, "CHECKSUM_FAILURE"}, + {OCC_RC_INTERNAL_ERROR, "INTERNAL_ERROR"}, + {OCC_RC_PRESENT_STATE_PROHIBITS, "PRESENT_STATE_PROHIBITS"}, + {OCC_RC_OCC_EXCEPTION, "OCC_EXCEPTION"}, + {OCC_RC_OCC_INIT_CHECKPOINT, "OCC_INIT_FAILURE"}, + {OCC_COMMAND_IN_PROGRESS, "IN_PROGRESS"}, + {OCC_COMMAND_IN_PROGRESS, "UNKNOWN"} + }; + + uint8_t l_idx = 0; + // TODO RTC 109066 + for (l_idx=0; l_idx < STATUS_STRING_COUNT; l_idx++) + { + if (i_status == L_status_string[l_idx].str_num) + { + // Return Code found + break; + } + } + + if (STATUS_STRING_COUNT == l_idx) + { + // Set index to last entry record + l_idx = STATUS_STRING_COUNT - 1; + } + + return L_status_string[l_idx].str_data; + } + + + + // Constructor for OccCmd + OccCmd::OccCmd(Occ * i_occ, + const occCommandType i_cmd, + const uint16_t i_cmdDataLength, + const uint8_t *i_data) + :iv_RetryCmd(false), + iv_OccCmd(), + iv_OccRsp(), + iv_Occ(i_occ) + { + iv_OccCmd.cmdType = i_cmd; + iv_OccCmd.dataLength = i_cmdDataLength; + if (0 != i_cmdDataLength) + { + if (i_cmdDataLength > OCC_MAX_DATA_LENGTH) + { + TMGT_ERR("OccCmd: truncating data length (0x%04X)", + i_cmdDataLength); + iv_OccCmd.dataLength = OCC_MAX_DATA_LENGTH; + } + memcpy(iv_OccCmd.cmdData, i_data, iv_OccCmd.dataLength); + } + + } // end OccCmd() + + + + // Destructor for OccCmd + OccCmd::~OccCmd() + { + } + + + // Determine if command needs to be traced and if so, trace it. + bool OccCmd::traceCommand() + { + bool o_cmdWasTraced = true; + const uint8_t l_instance = iv_Occ->instance; + + const uint8_t l_cmd_index = getCmdIndex(iv_OccCmd.cmdType); + if (OCC_CMD_END_OF_TABLE != cv_occCommandTable[l_cmd_index].cmdType) + { + switch(cv_occCommandTable[l_cmd_index].traceCmd) + { + case OCC_TRACE_ALWAYS: + // Always trace command + break; + + case OCC_TRACE_EXTENDED: + // Trace command when tracing enabled + o_cmdWasTraced = (G_debug_trace & DEBUG_TRACE_OCCCMD); + break; + + case OCC_TRACE_NEVER: + // Never trace these cmds (unless full tracing enabled) + o_cmdWasTraced = (G_debug_trace&DEBUG_TRACE_OCCCMD_FULL); + break; + + default: + if ((OCC_CMD_SETUP_CFG_DATA==iv_OccCmd.cmdType) && + (iv_OccCmd.dataLength > 0) && + ((iv_OccCmd.cmdData[0] == + OCC_CFGDATA_PSTATE_SSTRUCT))) + { + // Dont trace Pstate data (unless full tracing) + o_cmdWasTraced = (G_debug_trace & + DEBUG_TRACE_OCCCMD_FULL); + } + break; + } + } + + if (o_cmdWasTraced) + { + // Trace command (and up to 16 bytes of data) + if ((OCC_CMD_SETUP_CFG_DATA == iv_OccCmd.cmdType) && + (iv_OccCmd.dataLength > 0)) + { + // Trace config format and first parms since TRACFBIN does + // not always work + TMGT_INF("Send OCC%d cmd=0x%02X (%s), length=0x%04X," + " data=0x%08X...", + l_instance, iv_OccCmd.cmdType, + command_string(iv_OccCmd.cmdType), + iv_OccCmd.dataLength, + UINT32_GET(iv_OccCmd.cmdData)); + } + else + { + TMGT_INF("Send OCC%d cmd=0x%02X (%s), length=0x%04X", + l_instance, iv_OccCmd.cmdType, + command_string(iv_OccCmd.cmdType), + iv_OccCmd.dataLength); + } + if (iv_OccCmd.dataLength > 0) + { + TMGT_BIN("cmd data", iv_OccCmd.cmdData, + std::min(iv_OccCmd.dataLength,(uint16_t)16)); + } + } + + return o_cmdWasTraced; + + } // end OccCmd::traceCommand() + + + void OccCmd::traceResponse() + { + char l_rsp_status_string[64] = ""; + const uint8_t l_instance = iv_Occ->instance; + + if (iv_OccRsp.returnStatus != OCC_RC_SUCCESS) + { + sprintf(l_rsp_status_string, " (%s)", + rsp_status_string(iv_OccRsp.returnStatus)); + } + + // TODO RTC 109224 - refactor/optimize trace strings + TMGT_INF("OCC%d rsp status=0x%02X%s, length=0x%04X", + l_instance, iv_OccRsp.returnStatus, + l_rsp_status_string, iv_OccRsp.dataLength); + if (iv_OccRsp.dataLength > 0) + { + TMGT_BIN("rsp data:", iv_OccRsp.rspData, + std::min(iv_OccRsp.dataLength,(uint16_t)16)); + } + } + + + // Process the OCC response and determine if retry is required + void OccCmd::processOccResponse(errlHndl_t & io_errlHndl, + const bool i_traceRsp) + { + const uint8_t l_instance = iv_Occ->instance; + const bool alreadyRetriedOnce = iv_RetryCmd; + iv_RetryCmd = false; + + if (i_traceRsp) + { + traceResponse(); + } + + if (io_errlHndl == NULL) + { + // A response was received + io_errlHndl = checkOccResponse(); + if (io_errlHndl != NULL) + { + // Error checking on response failed... + if ((alreadyRetriedOnce == false) && + (OCC_RC_PRESENT_STATE_PROHIBITS != iv_OccRsp.returnStatus)) + { + // A retry has not been sent yet, commit/delete the error + // and retry. Add OCC command data to user details + // TODO RTC 115922 + //io_errlHndl->addUsrDtls(iv_OccCmd.cmdData, + // iv_OccCmd.dataLength, HTMGT_COMP_ID, + // 0/*version*/, TMGT_OCC_CMD_DATA); + ERRORLOG::errlCommit(io_errlHndl, HTMGT_COMP_ID); + iv_RetryCmd = true; + // Clear/init the response data structure + memset(&iv_OccRsp, 0x00, sizeof(occResponseStruct_t)); + iv_OccRsp.returnStatus = OCC_COMMAND_IN_PROGRESS; + } + else + { + // A retry has already been sent... + TMGT_ERR("OCC%d cmd 0x%02X failed retry, status=0x%02X," + " returned length=0x%04X", + l_instance, iv_OccCmd.cmdType, + iv_OccRsp.returnStatus, iv_OccRsp.dataLength); + if (iv_OccRsp.dataLength) + { + TMGT_BIN("OCC rsp data:", iv_OccRsp.rspData, + iv_OccRsp.dataLength); + } + + if ( /*(TMGT_RC_CHECKSUM_FAIL == io_errlHndl->getRC()) ||*/ + (OCC_RC_CHECKSUM_FAILURE == iv_OccRsp.returnStatus) || + (OCC_RC_INTERNAL_ERROR == iv_OccRsp.returnStatus) ) + { + // failed due to rsp data checksum failure... reset OCC + TMGT_ERR("processOccResponse: OCC%d response had" + " checksum or internal error," + " need to RESET OCC", l_instance); + iv_Occ->needsReset = true; + // Mark OCC as failed + iv_Occ->failed = true; + } + } + } + // else response was good + } + else + { + // Send of OCC command failed + if ( /*(TMGT_RC_SEND_FAIL == io_errlHndl->getRC()) &&*/ + (alreadyRetriedOnce == true) ) + { + // failed due to send/receive problem and retry has been + // sent... reset OCC + TMGT_ERR("Sending OCC%d command failed twice, need to RESET" + " OCC", l_instance); + iv_Occ->needsReset = true; + // Unable to communicate with OCC, mark as failed + iv_Occ->failed = true; + } + else + { + if ((alreadyRetriedOnce == false) && + (OCC_RC_PRESENT_STATE_PROHIBITS != iv_OccRsp.returnStatus)) + { + // A retry has not been sent yet, commit the error + // and retry. + // Add OCC command data to user details + // TODO RTC 115922 + //io_errlHndl->addUsrDtls(iv_OccCmd.cmdData, + //iv_OccCmd.dataLength, HTMGT_COMP_ID, + //0/*version*/, TMGT_OCC_CMD_DATA); + ERRORLOG::errlCommit(io_errlHndl, HTMGT_COMP_ID); + iv_RetryCmd = true; + + // Clear/init the response data structure + memset(&iv_OccRsp, 0x00, sizeof(occResponseStruct_t)); + iv_OccRsp.returnStatus = OCC_COMMAND_IN_PROGRESS; + } + else + { + // A retry has already been sent... + TMGT_ERR("OCC%d cmd 0x%02X failed. status=0x%02X," + " returned length=0x%04X", + l_instance, iv_OccCmd.cmdType, + iv_OccRsp.returnStatus, iv_OccRsp.dataLength); + if (iv_OccRsp.dataLength) + { + TMGT_BIN("response data:", iv_OccRsp.rspData, + iv_OccRsp.dataLength); + } + + if ( /*(TMGT_RC_CHECKSUM_FAIL == io_errlHndl->getRC()) ||*/ + (OCC_RC_CHECKSUM_FAILURE == iv_OccRsp.returnStatus) || + (OCC_RC_INTERNAL_ERROR == iv_OccRsp.returnStatus) ) + { + // failed due to rsp data checksum failure... reset OCC + TMGT_ERR("processOccResponse: OCC%d response had" + " checksum or internal error," + " need to RESET OCC", l_instance); + iv_Occ->needsReset = true; + // Unable to communicate with OCC, mark as failed + iv_Occ->failed = true; + } + } + } + } + } // end OccCmd::processOccResponse() + + + // Send command to OCC + errlHndl_t OccCmd::sendOccCmd() + { + errlHndl_t l_errlHndl = NULL; + uint8_t l_cmd_index = 0; + iv_OccRsp.returnStatus = OCC_COMMAND_IN_PROGRESS; + + if (iv_Occ != NULL) + { + const occStateId l_occState = iv_Occ->state; + l_cmd_index = getCmdIndex(iv_OccCmd.cmdType); + if (OCC_CMD_END_OF_TABLE!=cv_occCommandTable[l_cmd_index].cmdType) + { + const bool cmdTraced = traceCommand(); + + const bool l_commEstablished = iv_Occ->commEstablished; + if ( (true == l_commEstablished) || + ((false == l_commEstablished) && + (OCC_CMD_POLL == iv_OccCmd.cmdType)) ) + { + iv_RetryCmd = false; + do + { + // Send the command and receive the response + l_errlHndl = writeOccCmd(); + + processOccResponse(l_errlHndl, cmdTraced); + + } while (iv_RetryCmd); + } + else + { + // Ignore failure on GET_FIELD_DEBUG_DATA + if (OCC_CMD_GET_FIELD_DEBUG_DATA != iv_OccCmd.cmdType) + { + // Comm not established or command not supported + /*@ + * @errortype + * @reasoncode HTMGT_RC_OCC_UNAVAILABLE + * @moduleid HTMGT_MOD_SEND_OCC_CMD + * @userdata1 OCC command + * @userdata2 comm established + * @userdata3 OCC state + * @userdata4 1 + * @devdesc OCC comm not established or command is not + * supported + */ + bldErrLog(l_errlHndl, HTMGT_MOD_SEND_OCC_CMD, + HTMGT_RC_OCC_UNAVAILABLE, + iv_OccCmd.cmdType, l_commEstablished, + l_occState, 1, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + } + else + { + TMGT_ERR("sendOccCmd: ignoring invalid command 0x%02X", + iv_OccCmd.cmdType); + /*@ + * @errortype + * @reasoncode HTMGT_RC_INVALID_DATA + * @moduleid HTMGT_MOD_SEND_OCC_CMD + * @userdata1 OCC command type + * @devdesc Ignoring invalid command + */ + bldErrLog(l_errlHndl, HTMGT_MOD_SEND_OCC_CMD, + HTMGT_RC_INVALID_DATA, + iv_OccCmd.cmdType, 0, 0, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else + { + TMGT_ERR("sendOccCmd: ignoring command 0x%02X due to NULL OCC", + iv_OccCmd.cmdType); + /*@ + * @errortype + * @reasoncode HTMGT_RC_INTERNAL_ERROR + * @moduleid HTMGT_MOD_SEND_OCC_CMD + * @userdata1 OCC command type + * @devdesc OCC is not valid + */ + bldErrLog(l_errlHndl, HTMGT_MOD_SEND_OCC_CMD, + HTMGT_RC_INTERNAL_ERROR, + iv_OccCmd.cmdType, 0, 0, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + + if (l_errlHndl) + { + // Add OCC command data to user details + // TODO RTC 115922 + //l_errlHndl->addUsrDtls(iv_OccCmd.cmdData, + // iv_OccCmd.dataLength, HTMGT_COMP_ID, + // 0/*version*/, TMGT_OCC_CMD_DATA); + } + + return l_errlHndl; + + } // end OccCmd::sendOccCmd() + + + +#ifdef SIMICS_TESTING + // Auto-responder for testing in simics + void OccCmd::fakeOccResponse() + { + static uint8_t L_state = 0; + static uint8_t L_prior_status = 0x00; + static uint8_t L_prior_sequence = 0x00; + uint8_t * const rspBuffer = iv_Occ->homer + HTMGT_OCC_RSP_ADDR; + + if (0 == L_state) + { + if (G_debug_data != 0x02) + { + TMGT_INF("fakeOccResponse: status=0xFF"); + rspBuffer[0] = g_seq; + rspBuffer[1] = g_cmd; + rspBuffer[2] = 0xFF; // status + ++L_state; + + if (G_debug_data == 0x01) + { + L_state = 0; // force command timeout + } + } + } + else + { + if (G_debug_data != 0xE0) + { + TMGT_INF("fakeOccResponse: status=0x00"); + rspBuffer[2] = 0x00; // status + + // Add full reseponse data + const uint16_t dataLength = OCC_POLL_DATA_MIN_SIZE; + const occPollRspStruct_t poll_rsp_data = { + // Status 0x8B = Master, AttnEnabled, ObsReady, ActReady + 0x8B, + 0, // extStatus; + 0x01, // occsPresent; + 0, // requestedCfg; + 0, // state; + 0x0000, // reserved; + 0, // errorId; + 0x00000000, // errorAddress; + 0x0000, // errorLength; + 0x0000, // reserved2; + { "occ825_simicsFF" }, // codeLevel[16]; + { 'S', 'E', 'N', 'S', 'O', 'R' }, // sensor[6]; + 0, // numBlocks; + 0x01 // version; + //uint8_t sensorData[4049]; + }; + UINT16_PUT(&rspBuffer[3], dataLength); + TMGT_INF("fakeOccResponse: data length=%d", dataLength); + if (dataLength) + { + memcpy(&rspBuffer[5], &poll_rsp_data, dataLength); + } + uint16_t checksum = 0; + const uint16_t checksumOffset = OCC_RSP_HDR_LENGTH + + dataLength - 2; + for (uint16_t l_index = 0; l_index < checksumOffset; l_index++) + { + checksum += rspBuffer[l_index]; + } + if (G_debug_data == 0x03) + { + TMGT_INF("fakeOccResponse: corrupting checksum" + " (good=0x%04X)", checksum); + checksum++; + } + TMGT_INF("fakeOccResponse: Writing checksum 0x%04X to offset" + " 0x%04X", checksum, checksumOffset); + UINT16_PUT(&rspBuffer[checksumOffset], checksum); + } + else + { + TMGT_INF("fakeOccResponse: status=0xE1"); + rspBuffer[2] = 0xE0; // status + const uint16_t dataLength = 32; + UINT16_PUT(&rspBuffer[3], dataLength); + const uint8_t excpData[dataLength] = { 0x11, 0x22, 0x33, 0x44 }; + TMGT_INF("fakeOccResponse: data length=%d", dataLength); + if (dataLength) + { + memcpy(&rspBuffer[5], &excpData, dataLength); + } + } + + L_state = 0; + } + + // Check response buffer + if (L_prior_status != rspBuffer[2]) + { + TMGT_INF("fakeOccResponse: status updated to 0x%02X", + rspBuffer[2]); + L_prior_status = rspBuffer[2]; + } + if (L_prior_sequence != rspBuffer[0]) + { + TMGT_INF("fakeOccResponse: sequence updated to 0x%02X" + " (expecting=0x%02X)", + rspBuffer[0], iv_Occ->seqNumber); + L_prior_sequence = rspBuffer[0]; + } + + } // end fakeOccResponse() +#endif + + + + // Returns true if timeout waiting for response + bool OccCmd::waitForOccRsp(uint32_t i_timeout) + { + const uint8_t * const rspBuffer = iv_Occ->homer + HTMGT_OCC_RSP_ADDR; + uint16_t rspLength = 0; + if (G_debug_trace & DEBUG_TRACE_VERBOSE) + { + TMGT_INF("waitForOccRsp(%d) address=0x%08X", i_timeout, rspBuffer); + } + + bool l_time_expired = true; + const uint32_t OCC_RSP_SAMPLE_TIME = 100; // in milliseconds + uint32_t l_msec_remaining = std::max(i_timeout, OCC_RSP_SAMPLE_TIME); + while (l_msec_remaining > 0) + { +#ifdef SIMICS_TESTING + fakeOccResponse(); +#endif + // 1. When OCC receives the command, they will set the status to + // COMMAND_IN_PROGRESS. + // 2. When the response is ready they will update the full + // response buffer (except the status) + // 3. The status field is updated last to indicate response ready + // + // Note: Need to check the sequence number to be sure we are + // processing the expected response + if ((OCC_COMMAND_IN_PROGRESS != rspBuffer[2]) && + (iv_Occ->seqNumber == rspBuffer[0])) + { + // Need an 'isync' here to ensure that previous instructions + // have completed before the code continues on. This is a type + // of read-barrier. Without this the processor can do + // speculative reads of the HOMER data and you can actually + // get stale data as part of the instructions that happen + // afterwards. Another 'weak consistency' issue. + isync(); + + // OCC must have processed the command + const uint16_t rspDataLen = UINT16_GET(&rspBuffer[3]); + rspLength = OCC_RSP_HDR_LENGTH + rspDataLen; + if (G_debug_trace & DEBUG_TRACE_OCCCMD) + { + TMGT_INF("waitForOccRsp: OCC%d rsp (huid=0x%08X," + " rsp length=%d)", + iv_Occ->instance, iv_Occ->huid, rspLength); + TMGT_BIN("waitForOccRsp: OCC rsp data (up to 256 bytes)", + rspBuffer, std::min(rspLength, (uint16_t)256)); + } + l_time_expired = false; + break; + } + + // delay before next check + const uint32_t l_sleep_msec = std::min(l_msec_remaining, + OCC_RSP_SAMPLE_TIME); + + // TODO RTC 115922 +#ifndef __HOSTBOOT_RUNTIME + nanosleep( 0, NS_PER_MSEC * l_sleep_msec ); +#else + if(g_hostInterfaces && g_hostInterfaces->nanosleep) + { + g_hostInterfaces->nanosleep(0, NS_PER_MSEC * l_sleep_msec); + } +#endif + l_msec_remaining -= l_sleep_msec; + + } // while + + if (l_time_expired) + { + // timeout waiting for response + TMGT_ERR("waitForOccRsp: OCC%d timeout waiting for response" + " (%d sec)", + iv_Occ->instance, i_timeout/1000); + } + + return l_time_expired; + + } // end OccCmd::waitForOccRsp() + + + + // Create/commit an error log with the OCC exception data + void OccCmd::handleOccException(void) + { + // Exception length includes response header (w/o checksum) and + // the data length + uint32_t l_exceptionDataLength = OCC_RSP_HDR_LENGTH - 2 + + iv_OccRsp.dataLength; + + TMGT_ERR("handleOccException: OCC%d returned abnormal rsp status of" + " 0x%02X, rsp len=%d", + iv_Occ->instance, iv_OccRsp.returnStatus, + l_exceptionDataLength); + if (l_exceptionDataLength > 4*KILOBYTE) + { + TMGT_INF("handleOccException: truncating data length to 4K"); + l_exceptionDataLength = 4*KILOBYTE; + // TODO RTC 109224 - HB elogs are only 4K + } + + /*@ + * @errortype + * @reasoncode HTMGT_RC_INTERNAL_ERROR + * @moduleid HTMGT_MOD_HANLDE_OCC_EXCEPTION + * @userdata1[0-15] rsp status + * @userdata1[16-31] exception data length + * @userdata2[0-15] huid + * @userdata2[16-31] + * @devdesc OCC reported exception + */ + errlHndl_t l_excErr = NULL; + bldErrLog(l_excErr, HTMGT_MOD_HANLDE_OCC_EXCEPTION, + (htmgtReasonCode)(OCCC_COMP_ID | iv_OccRsp.returnStatus), + iv_OccRsp.returnStatus, iv_OccRsp.dataLength, + iv_Occ->huid, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL //, + //false, // dont skip traces + // OCCC_COMP_ID); + // TODO RTC 115922 + //l_excErr->addUsrDtls(l_excp_buffer, l_excp_length, + // OCCC_COMP_ID, 1 /*version*/, + // iv_OccRsp.returnStatus/*type*/ + ); + ERRORLOG::errlCommit(l_excErr, HTMGT_COMP_ID); + + } // end OccCmd::handleOccException() + + + + // Build OCC command buffer in HOMER, notify OCC and wait for + // the response or timeout + errlHndl_t OccCmd::writeOccCmd() + { + errlHndl_t l_err = NULL; + if (G_debug_trace & DEBUG_TRACE_VERBOSE) + { + TMGT_INF("writeOccCmd() called"); + } + + // Write the command to HOMER + buildOccCmdBuffer(); + + // Notify OCC that command is available (via circular buffer) + const uint32_t l_bitsToSend = sizeof(occCircBufferCmd_t) * 8; + ecmdDataBufferBase l_circ_buffer(l_bitsToSend); + const occCircBufferCmd_t tmgtDataWriteAttention = + { + 0x10, // sender: HTMGT + 0x01, // command: Command Write Attention + {0, 0, 0, 0, 0, 0} // reserved + }; + l_circ_buffer.insert((uint8_t*)&tmgtDataWriteAttention, 0, + l_bitsToSend); + if (G_debug_trace & DEBUG_TRACE_VERBOSE) + { + TMGT_INF("writeOccCmd: Calling writeCircularBuffer()"); + } + l_err = HBOCC::writeCircularBuffer(iv_Occ->target, l_circ_buffer); + if (NULL != l_err) + { + TMGT_ERR("writeOccCmd: Error writing to OCC Circular Buffer"); + } + else + { + // Wait for response from the OCC + const uint8_t l_instance = iv_Occ->instance; + const uint8_t l_index = getCmdIndex(iv_OccCmd.cmdType); + // l_index should be valid since validation was done in sendOccCmd() + const uint16_t l_read_timeout = cv_occCommandTable[l_index].timeout; + + // Wait for OCC to process command and send response + waitForOccRsp(l_read_timeout); + + // Parse the OCC response (called even on timeout to collect + // rsp buffer) + l_err = parseOccResponse(); + + bool l_timeout = false; + if (OCC_COMMAND_IN_PROGRESS != iv_OccRsp.returnStatus) + { + // Status of 0xE0-EF are reserved for OCC exceptions, + // must collect data for these + if (0xE0 == (iv_OccRsp.returnStatus & 0xF0)) + { + handleOccException(); + } + else + { + if (iv_OccRsp.sequenceNumber != + iv_OccCmd.sequenceNumber) + { + // Sequence number mismatch + TMGT_ERR("writeOccCmd: OCC%d sequence number mismatch" + " (from cmd: 0x%02X, rsp: 0x%02X)", + l_instance, iv_OccCmd.sequenceNumber, + iv_OccRsp.sequenceNumber); + l_timeout = true; + } + } + } + else + { + // OCC must not have completed processing the command before + // timeout + l_timeout = true; + } + + if (l_timeout) + { + /*@ + * @errortype + * @reasoncode HTMGT_RC_TIMEOUT + * @moduleid HTMGT_MOD_WRITE_OCC_CMD + * @userdata1[0-15] command + * @userdata1[16-31] read timeout + * @userdata2[0-15] response sequence number + * @userdata2[16-31] response status + * @devdesc Timeout waiting for OCC response + */ + bldErrLog(l_err, HTMGT_MOD_WRITE_OCC_CMD, HTMGT_RC_TIMEOUT, + iv_OccCmd.cmdType, l_read_timeout, + iv_OccRsp.sequenceNumber, + iv_OccRsp.returnStatus, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + + // The response buffer did not contain correct sequence number, + // or staus is still in progress save 1K rsp data + // TODO RTC 115922 + //l_err->addUsrDtls(l_err, l_excp_length, + // OCCC_COMP_ID, 1 /*version*/, 0xF0 /*type*/); + + // timeout waiting for response (no data to return) + iv_OccRsp.dataLength = 0; + } // end timeout + } + + return l_err; + + } /* end of OccCmd::writeOccCmd() */ + + + + // Copy OCC command into command buffer in HOMER + uint16_t OccCmd::buildOccCmdBuffer() + { + uint8_t * const cmdBuffer = iv_Occ->homer + HTMGT_OCC_CMD_ADDR; + uint16_t l_send_length = 0; + + if (0 == ++iv_Occ->seqNumber) + { + // Do not use 0 for sequence number + ++iv_Occ->seqNumber; + } + iv_OccCmd.sequenceNumber = iv_Occ->seqNumber; + cmdBuffer[l_send_length++] = iv_OccCmd.sequenceNumber; + cmdBuffer[l_send_length++] = iv_OccCmd.cmdType; + cmdBuffer[l_send_length++] = (iv_OccCmd.dataLength >> 8) & 0xFF; + cmdBuffer[l_send_length++] = iv_OccCmd.dataLength & 0xFF; + memcpy(&cmdBuffer[l_send_length], iv_OccCmd.cmdData, + iv_OccCmd.dataLength); + l_send_length += iv_OccCmd.dataLength; + + // Calculate checksum + iv_OccCmd.checksum = 0; + for (uint16_t l_index = 0; l_index < l_send_length; l_index++) + { + iv_OccCmd.checksum += cmdBuffer[l_index]; + } + cmdBuffer[l_send_length++] = (iv_OccCmd.checksum >> 8) & 0xFF; + cmdBuffer[l_send_length++] = iv_OccCmd.checksum & 0xFF; + + if (G_debug_trace & DEBUG_TRACE_OCCCMD) + { + // Trace the command + TMGT_BIN("buildOccCmdBuffer: OCC command", + cmdBuffer, l_send_length); + } + +#ifdef SIMICS_TESTING + g_seq = iv_OccCmd.sequenceNumber; + g_cmd = iv_OccCmd.cmdType; +#endif + + // When the P8 processor writes to memory (such as the HOMER) there is + // no certainty that the writes happen in order or that they have + // actually completed by the time the instructions complete. 'sync' + // is a memory barrier to ensure the HOMER data has actually been made + // consistent with respect to memory, so that if the OCC were to read + // it they would see all of the data. Otherwise, there is potential + // for them to get stale or incomplete data. + sync(); + + return l_send_length; + + } // end OccCmd::buildOccCmdBuffer() + + + + // Copy response into object + errlHndl_t OccCmd::parseOccResponse() + { + errlHndl_t l_errlHndl = NULL; + uint16_t l_index = 0; + const uint8_t * const rspBuffer = iv_Occ->homer + HTMGT_OCC_RSP_ADDR; + const uint16_t rspLen = OCC_RSP_HDR_LENGTH + UINT16_GET(&rspBuffer[3]); + + if ((NULL != rspBuffer) && (rspLen >= OCC_RSP_HDR_LENGTH)) + { + iv_OccRsp.sequenceNumber = rspBuffer[l_index++]; + iv_OccRsp.cmdType = (enum occCommandType)rspBuffer[l_index++]; + iv_OccRsp.returnStatus = (occReturnCodes)rspBuffer[l_index++]; + + iv_OccRsp.dataLength = UINT16_GET(&rspBuffer[l_index]); + l_index += 2; + if (rspLen >= (iv_OccRsp.dataLength + OCC_RSP_HDR_LENGTH)) + { + if (iv_OccRsp.dataLength > 0) + { + if (iv_OccRsp.dataLength > OCC_MAX_DATA_LENGTH) + { + TMGT_ERR("parseOccResponse: truncating data (0x%04X)", + iv_OccRsp.dataLength); + iv_OccRsp.dataLength = OCC_MAX_DATA_LENGTH; + } + memcpy(iv_OccRsp.rspData, &rspBuffer[l_index], + iv_OccRsp.dataLength); + l_index += iv_OccRsp.dataLength; + } + iv_OccRsp.checksum = UINT16_GET(&rspBuffer[l_index]); + l_index += 2; + } + else + { + // Log invalid read length (not enough data received) + /*@ + * @errortype + * @reasoncode HTMGT_RC_SEND_FAIL + * @moduleid HTMGT_MOD_PARSE_OCC_RSP + * @userdata1[0-15] response length + * @userdata1[16-31] response buffer[0-3] + * @userdata2[0-15] response buffer[4-7] + * @userdata2[16-31] + * @devdesc Invalid response length received + */ + bldErrLog(l_errlHndl, HTMGT_MOD_PARSE_OCC_RSP, + HTMGT_RC_SEND_FAIL, + rspLen, UINT32_GET(rspBuffer), + UINT32_GET(&rspBuffer[4]), 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else + { + uint32_t l_data[2] = {0}; + if (NULL != rspBuffer) + { + memcpy(l_data, rspBuffer, sizeof(l_data)); + } + // Log invalid read length (rsp too short) + bldErrLog(l_errlHndl, HTMGT_MOD_PARSE_OCC_RSP, HTMGT_RC_SEND_FAIL, + rspLen, l_data[0], l_data[1], 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + + if (l_errlHndl) + { + // Add full OCC response to user details + // TODO RTC 115922 + //l_errlHndl->addUsrDtls(rspBuffer, rspLen, HTMGT_COMP_ID, + // 0/*version*/, TMGT_OCC_RSP_DATA); + } + + return l_errlHndl; + + } // end OccCmd::parseOccResponse() + + + + // Verify status, checksum and length of OCC response + errlHndl_t OccCmd::checkOccResponse() + { + errlHndl_t l_errlHndl = NULL; + uint16_t l_calc_checksum = 0, l_index = 0; + + // Calculate checksum on response + l_calc_checksum += iv_OccRsp.sequenceNumber; + l_calc_checksum += iv_OccRsp.cmdType; + l_calc_checksum += iv_OccRsp.returnStatus; + l_calc_checksum += (iv_OccRsp.dataLength >> 8) & 0xFF; + l_calc_checksum += iv_OccRsp.dataLength & 0xFF; + for (l_index = 0; l_index < iv_OccRsp.dataLength; l_index++) + { + l_calc_checksum += iv_OccRsp.rspData[l_index]; + } + + if (l_calc_checksum == iv_OccRsp.checksum) + { + if (OCC_RC_SUCCESS == iv_OccRsp.returnStatus) + { + occCheckRspLengthType l_check_rsp_length; + uint16_t l_rsp_length = 0; + + // Verify response length and log errors if bad + l_index = getCmdIndex(iv_OccRsp.cmdType); + // l_index should be valid since validation was done + // in sendOccCmd() + l_check_rsp_length = cv_occCommandTable[l_index].checkRspLength; + l_rsp_length = cv_occCommandTable[l_index].rspLength; + + if (OCC_CHECK_RSP_LENGTH_EQUALS == l_check_rsp_length) + { + if ( iv_OccRsp.dataLength != l_rsp_length ) + { + TMGT_ERR("Invalid length in OCC response for" + " cmd=0x%02X, length=0x%04X", + iv_OccRsp.cmdType, + iv_OccRsp.dataLength); + /*@ + * @errortype + * @reasoncode HTMGT_RC_OCC_CMD_FAIL + * @moduleid HTMGT_MOD_CHECK_OCC_RSP + * @userdata1[0-15] OCC command type + * @userdata1[16-31] response data length + * @devdesc Invalid length in OCC response + */ + bldErrLog(l_errlHndl, HTMGT_MOD_CHECK_OCC_RSP, + HTMGT_RC_OCC_CMD_FAIL, + iv_OccRsp.cmdType, + iv_OccRsp.dataLength, 0, 1, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else if (OCC_CHECK_RSP_LENGTH_GREATER == l_check_rsp_length) + { + if ( iv_OccRsp.dataLength < l_rsp_length ) + { + TMGT_ERR("Invalid length in OCC response for" + " cmd=0x%02X, length=0x%04X", + iv_OccRsp.cmdType, + iv_OccRsp.dataLength); + bldErrLog(l_errlHndl, HTMGT_MOD_CHECK_OCC_RSP, + HTMGT_RC_OCC_CMD_FAIL, + iv_OccRsp.cmdType, + iv_OccRsp.dataLength, 0, 2, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else if (OCC_CHECK_RSP_LENGTH_NONE != l_check_rsp_length) + { + TMGT_ERR("Invalid check response length=0x%02X in OCC" + " command table for cmd = 0x%02X", + l_check_rsp_length, iv_OccRsp.cmdType); + bldErrLog(l_errlHndl, HTMGT_MOD_CHECK_OCC_RSP, + HTMGT_RC_OCC_CMD_FAIL, + iv_OccRsp.cmdType, iv_OccRsp.dataLength, + 0, 0, ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else + { + // Command was not successfully processed + uint8_t l_error_log_id = 0; + + if (1 == iv_OccRsp.dataLength) + { + // Data should be error log id created for this failure + l_error_log_id = iv_OccRsp.rspData[0]; + + TMGT_ERR("checkOccResponse: Bad status (0x%02X=%s) from OCC" + " (returned elog=0x%02X)", + iv_OccRsp.returnStatus, + rsp_status_string(iv_OccRsp.returnStatus), + l_error_log_id); + } + else + { + TMGT_ERR("checkOccResponse: Bad status (0x%02X=%s) from OCC" + " (data len=%d)", + iv_OccRsp.returnStatus, + rsp_status_string(iv_OccRsp.returnStatus), + iv_OccRsp.dataLength); + + TMGT_ERR("OCC response packet length invalid (0x%04X)", + iv_OccRsp.dataLength); + l_error_log_id = 0; + } + /* */ + bldErrLog(l_errlHndl, HTMGT_MOD_CHECK_OCC_RSP, + HTMGT_RC_OCC_CMD_FAIL, + iv_OccRsp.returnStatus, l_error_log_id, + iv_OccRsp.cmdType, 3, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + else + { + /*@ + * @errortype + * @reasoncode HTMGT_RC_CHECKSUM_FAIL + * @moduleid HTMGT_MOD_CHECK_OCC_RSP + * @userdata1 OCC command type + * @userdata2 sequence number + * @userdata3 checksum + * @userdata4 calculated checksum + * @devdesc OCC response had checksum failure + */ + bldErrLog(l_errlHndl, HTMGT_MOD_CHECK_OCC_RSP, + HTMGT_RC_CHECKSUM_FAIL, + iv_OccRsp.cmdType, iv_OccRsp.sequenceNumber, + iv_OccRsp.checksum, l_calc_checksum, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + + if (l_errlHndl) + { + // Add OCC response data to user details + // TODO RTC 115922 + // l_errlHndl->addUsrDtls(iv_OccRsp.rspData, + // iv_OccRsp.dataLength, HTMGT_COMP_ID, + // 0/*version*/, TMGT_OCC_RSP_DATA); + } + + return(l_errlHndl); + + } /* end of OccCmd::checkOccResponse() */ + + +} + diff --git a/src/usr/htmgt/htmgt_occcmd.H b/src/usr/htmgt/htmgt_occcmd.H new file mode 100644 index 000000000..6bc5d75fc --- /dev/null +++ b/src/usr/htmgt/htmgt_occcmd.H @@ -0,0 +1,304 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_occcmd.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 HTMGT_OCCCMD_H +#define HTMGT_OCCCMD_H + +#include "htmgt_utility.H" +#include "htmgt_activate.H" +#include "htmgt_occ.H" + +#include <stdint.h> +#include <errl/errlmanager.H> + +namespace HTMGT +{ + + const uint32_t HTMGT_OCC_CMD_ADDR = 0x001EE000; + const uint32_t HTMGT_OCC_RSP_ADDR = 0x001EF000; + const uint32_t OCC_MAX_DATA_LENGTH = 0x00001000; + + // The following header lengths include the 2 byte checksum + const uint16_t OCC_CMD_HDR_LENGTH = 6; + const uint16_t OCC_RSP_HDR_LENGTH = 7; + + enum occReturnCodes + { + OCC_RC_SUCCESS = 0x00, + OCC_RC_INVALID_COMMAND = 0x11, + OCC_RC_INVALID_COMMAND_LENGTH = 0x12, + OCC_RC_INVALID_DATA_FIELD = 0x13, + OCC_RC_CHECKSUM_FAILURE = 0x14, + OCC_RC_INTERNAL_ERROR = 0x15, + OCC_RC_PRESENT_STATE_PROHIBITS = 0x16, + + // 0xE0-EF are reserved for OCC exceptions on command timeouts + // TMGT should collect all the data in the response as FFDC + OCC_RC_OCC_EXCEPTION = 0xE0, + OCC_RC_OCC_INIT_CHECKPOINT = 0xE1, + OCC_RC_OCC_WATCHDOG_TIMEOUT = 0xE2, + OCC_RC_OCC_TIMEOUT = 0xE3, + OCC_RC_OCC_HW_ERROR = 0xE4, + OCC_RC_OCC_EXCEPTION_RESERVED = 0xEF, + + OCC_COMMAND_IN_PROGRESS = 0xFF + }; + + enum occCommandType + { + OCC_CMD_POLL = 0x00, + OCC_CMD_CLEAR_ERROR_LOG = 0x12, + OCC_CMD_SET_STATE = 0x20, + OCC_CMD_SETUP_CFG_DATA = 0x21, + OCC_CMD_SET_POWER_CAP = 0x22, + OCC_CMD_RESET_PREP = 0x25, + OCC_CMD_GET_FIELD_DEBUG_DATA = 0x42, + + OCC_CMD_END_OF_TABLE = 0xFF + }; + + enum occCheckRspLengthType + { + OCC_CHECK_RSP_LENGTH_NONE = 0x00, + OCC_CHECK_RSP_LENGTH_EQUALS = 0x01, + OCC_CHECK_RSP_LENGTH_GREATER = 0x02, + }; + + enum occCmdTraceEnum + { + OCC_TRACE_NEVER = 0x00, + OCC_TRACE_EXTENDED = 0x01, + OCC_TRACE_CONDITIONAL = 0x02, + OCC_TRACE_ALWAYS = 0x03, + }; + + struct occCommandTable_t + { + occCommandType cmdType; + uint8_t supported; + occCheckRspLengthType checkRspLength; + uint16_t rspLength; + uint32_t timeout; + uint16_t maxBytesRead; + occCmdTraceEnum traceCmd; + + bool operator== (const occCommandType i_cmd) + { + return (cmdType == i_cmd); + } + }; + + struct occCommandStruct_t + { + uint8_t sequenceNumber; + occCommandType cmdType; + uint16_t dataLength; + uint8_t cmdData[OCC_MAX_DATA_LENGTH]; + uint16_t checksum; + }; + + struct occResponseStruct_t + { + uint8_t sequenceNumber; + occCommandType cmdType; + occReturnCodes returnStatus; + uint16_t dataLength; + uint8_t rspData[OCC_MAX_DATA_LENGTH]; + uint16_t checksum; + }; + + + + /** + * @class OccCmd + * + * @brief OCC Command handling class. + * + * @par Detailed Description: + * Provides ability to build and send commands to the OCC and + * process the responses returned by the OCC. + */ + class OccCmd + { + private: + bool iv_RetryCmd; + occCommandStruct_t iv_OccCmd; + occResponseStruct_t iv_OccRsp; + Occ * iv_Occ; + + static const occCommandTable_t cv_occCommandTable[]; + + /** + * @brief Get the index of the specified command in the command + * table + * + * @param[in] i_cmd OCC command type + * + * @note If command not found/invalid, index to END_OF_TABLE will + * be returned and checked by caller + * + * @return index into command table + */ + uint8_t getCmdIndex(const occCommandType i_cmd); + + /** + * @brief Write the full OCC command into HOMER (memory) including + * checksum. + */ + uint16_t buildOccCmdBuffer(); + + /** + * @brief Verify the status, checksum and length of the OCC + * response. + * + * @return NULL on success, or errlHndl_t for any failure + */ + errlHndl_t checkOccResponse(); + + /** + * @brief Parse the OCC response into the object and verify + * lengths are valid. + * + * @return NULL on success, or errlHndl_t for any failure + */ + errlHndl_t parseOccResponse(); + + /** + * @brief Create and commit error log from the exception data + * in the response buffer. It is assumed that the OCC + * response status is 0xE0-0xEF when called. + */ + void handleOccException(void); + + /** + * @brief Send the command to the OCC + * + * @return NULL on success, or errlHndl_t for any failure + */ + errlHndl_t writeOccCmd(); + + /** + * @brief Waits for the OCC response to be received + * + * @param[in] i_timeout max time to wait for response (in seconds) + * + * @return true if timeout was reached before good response, or + * false if response was received within the timeout + */ + bool waitForOccRsp(uint32_t i_timeout); + + + public: + /** + * @brief Constructor + * + * @param[in] i_occ target OCC for the command + * @param[in] i_cmd OCC command to send + * @param[in] i_dataLength Size of Data buffer (i_data) + * @param[in] i_data Data buffer to send with command + */ + OccCmd(Occ * i_occ, + const occCommandType i_cmd, + const uint16_t i_dataLength, + const uint8_t *i_data); + + /** + * @brief Destructor + */ + ~OccCmd(); + + /** + * @brief Send this command to the OCC + * + * @return NULL on success, or errlHndl_t for any failure + */ + errlHndl_t sendOccCmd(); + + /** + * @brief Determine if the command needs to be traced and trace it + * + * @return true if the command was traced + */ + bool traceCommand(); + + /** + * @brief Trace the response + */ + void traceResponse(); + + /** + * @brief Process the OCC response and determine if a retry + * is necessary (iv_retryCmd will be true if required) + * + * @param[in,out] io_errlHndl Error handle from sending command + * and response error handle if failed + * @param[in] i_traceRsp true if the response should be traced + */ + void processOccResponse(errlHndl_t & io_errlHndl, + const bool i_traceRsp); + /** + * @brief Return the OCC response status from the response buffer + * + * @return OCC response status + */ + occReturnCodes getRspStatus() { return iv_OccRsp.returnStatus; } + + /** + * @brief Return the data length from the OCC response + * + * @return OCC response data length + */ + uint16_t getRspLength() { return iv_OccRsp.dataLength; } + + /** + * @brief Return a pointer to the response data and length + * + * @param[in,out] rsp_data pointer to the response data + * + * @return OCC response data length + */ + uint16_t getResponseData(uint8_t* & rsp_data) + { + rsp_data = iv_OccRsp.rspData; + return iv_OccRsp.dataLength; + } + + +#ifdef SIMICS_TESTING + /** + * @brief Auto-responder for testing in simics + * + * @param[in] iOcc OCC target + */ + void fakeOccResponse(); +#endif + + }; + + + +} // end namespace + +#endif diff --git a/src/usr/htmgt/htmgt_poll.C b/src/usr/htmgt/htmgt_poll.C new file mode 100644 index 000000000..402c7ce74 --- /dev/null +++ b/src/usr/htmgt/htmgt_poll.C @@ -0,0 +1,141 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_poll.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <htmgt/htmgt.H> +#include <htmgt/htmgt_reasoncodes.H> +#include "htmgt_utility.H" +#include "htmgt_activate.H" +#include "htmgt_poll.H" +#include "htmgt_occcmd.H" +#include "htmgt_config.H" + +// Targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> + + +using namespace HTMGT; + + +namespace HTMGT +{ + + // Send a single poll command to OCC + errlHndl_t sendOccPoll() + { + errlHndl_t l_err = NULL; + uint8_t * l_poll_rsp = NULL; + + // Loop through all functional OCCs + std::vector<Occ*> occList = occMgr::instance().getOccArray(); + for (std::vector<Occ*>::iterator itr = occList.begin(); + (itr < occList.end()) && (NULL == l_err); + ++itr) + { + Occ * occ = (*itr); + const uint8_t occInstance = occ->getInstance(); + TMGT_INF("sendOccPoll: to OCC%d", occInstance); + + // create 1 byte buffer for poll command data + const uint8_t l_cmdData[1] = { 0x10 /*version*/ }; + + OccCmd cmd(occ, OCC_CMD_POLL, sizeof(l_cmdData), l_cmdData); + l_err = cmd.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + TMGT_ERR("sendOccPoll: OCC%d poll failed with rc=0x%04X", + occInstance, l_err->reasonCode()); + } + else + { + // Poll succeeded, check response + uint32_t l_poll_rsp_size = cmd.getResponseData(l_poll_rsp); + if (l_poll_rsp_size >= OCC_POLL_DATA_MIN_SIZE) + { + poll_rsp_handler(occ, l_poll_rsp, l_poll_rsp_size); + } + else + { + TMGT_ERR("sendOccPoll: OCC%d poll command response " + "failed with invalid data length %d", + occInstance, l_poll_rsp_size); + /*@ + * @errortype + * @reasoncode HTMGT_RC_INVALID_LENGTH + * @moduleid HTMGT_MOD_OCC_POLL + * @userdata1 OCC instance + * @devdesc Invalid POLL response length + */ + bldErrLog(l_err, HTMGT_MOD_OCC_POLL, + HTMGT_RC_INVALID_LENGTH, + occInstance, 0, 0, 0, + ERRORLOG::ERRL_SEV_INFORMATIONAL); + } + } + } + + return l_err; + + } // end sendOccPoll() + + + + // Handle OCC poll response + void poll_rsp_handler(Occ * i_occ, + const uint8_t * i_pollResponse, + const uint16_t i_pollResponseSize) + { + TMGT_DBG("OCC Poll Response", i_pollResponse, i_pollResponseSize); + + const occPollRspStruct_t *pollRspData = + (occPollRspStruct_t *) i_pollResponse; + + // Trace if any data changed + if (memcmp(pollRspData, + i_occ->getLastPollRsp(), + OCC_POLL_DATA_MIN_SIZE) != 0) + { + TMGT_INF("OCC%d Poll change: Status:%04X Occs:%02X Cfg:%02X " + "State:%02X Error:%06X/%08X", + i_occ->getInstance(), + (pollRspData->status << 8) | pollRspData->extStatus, + pollRspData->occsPresent, + pollRspData->requestedCfg, pollRspData->state, + (pollRspData->errorId<<16) | pollRspData->errorLength, + pollRspData->errorAddress); + TMGT_INF(" Code: \"%s\", NumSensors: 0x%02X", + pollRspData->codeLevel, pollRspData->numBlocks); + } + } + + + +} // end namespace + + + diff --git a/src/usr/htmgt/htmgt_poll.H b/src/usr/htmgt/htmgt_poll.H new file mode 100644 index 000000000..62eabf885 --- /dev/null +++ b/src/usr/htmgt/htmgt_poll.H @@ -0,0 +1,78 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_poll.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 HTMGT_POLL_H +#define HTMGT_POLL_H + +#include <stdint.h> +#include <htmgt/htmgt.H> +#include "htmgt_activate.H" +#include "htmgt_occ.H" + +namespace HTMGT +{ + struct occPollRspStruct_t + { + uint8_t status; + uint8_t extStatus; + uint8_t occsPresent; + uint8_t requestedCfg; + uint8_t state; + uint16_t reserved; + uint8_t errorId; + uint32_t errorAddress; + uint16_t errorLength; + uint16_t reserved2; + uint8_t codeLevel[16]; + uint8_t sensor[6]; + uint8_t numBlocks; + uint8_t version; + uint8_t sensorData[4049]; + } __attribute__((packed)); + + const uint32_t HTMGT_OCC_POLL_DATA_SIZE = sizeof(occPollRspStruct_t); + + + /** + * @brief Send a poll command to each OCC + * + * @return NULL on success, else error handle + */ + errlHndl_t sendOccPoll(); + + + /** + * @brief Handle OCC poll response + * + * @param[in] i_occ pointer to the OCC + * @param[in] i_pollResponse pointer to the response + * @param[in] i_pollResponseSize length of the poll response + */ + void poll_rsp_handler(Occ * i_occ, + const uint8_t * i_pollResponse, + const uint16_t i_pollResponseSize); + +} // end namespace +#endif diff --git a/src/usr/htmgt/htmgt_utility.C b/src/usr/htmgt/htmgt_utility.C index 078c7eebd..733887de3 100644 --- a/src/usr/htmgt/htmgt_utility.C +++ b/src/usr/htmgt/htmgt_utility.C @@ -29,7 +29,12 @@ namespace HTMGT { // Trace definition trace_desc_t* g_trac_htmgt = NULL; - TRAC_INIT(&g_trac_htmgt, HTMGT_COMP_NAME, 2*KILOBYTE); + TRAC_INIT(&g_trac_htmgt, HTMGT_COMP_NAME, 4*KILOBYTE); + + // Debug flags + uint32_t G_debug_data = 0; + uint32_t G_debug_trace = DEBUG_TRACE_FULL_NONVERBOSE; // TODO RTC 115922 + // Create/Build an Error log and add HTMGT component trace void bldErrLog(errlHndl_t & io_err, @@ -39,21 +44,25 @@ namespace HTMGT const uint32_t i_data2, const uint32_t i_data3, const uint32_t i_data4, - const ERRORLOG::errlSeverity_t i_sev) + const ERRORLOG::errlSeverity_t i_sev, + const bool i_addFwCallout) { - TMGT_INF("bldErrLog(mod: 0x%02X, rc: 0x%02X, data: 0x%08X %08X %08X %08X, sev: 0x%02X", - i_modid, i_rc, i_data1, i_data2, i_data3, i_data4, i_sev); + TMGT_INF("bldErrLog(mod: 0x%02X, rc: 0x%02X, data: 0x%08X %08X %08X" + " %08X, sev: 0x%02X, fw:%c", + i_modid, i_rc, i_data1, i_data2, i_data3, i_data4, + i_sev, i_addFwCallout?'y':'n'); + // TODO RTC 109224 - RAS review what logs need fw callout if (NULL == io_err) { - io_err = new ERRORLOG::ErrlEntry - (i_sev, - i_modid, - i_rc, - ((uint64_t)i_data1 << 32) | i_data2, - ((uint64_t)i_data3 << 32) | i_data4, - true /*Add HB Software Callout TODO RTC 115422 RAS review*/); - + io_err = new ERRORLOG::ErrlEntry(i_sev, + i_modid, + i_rc, + ((uint64_t)i_data1 << 32) | + i_data2, + ((uint64_t)i_data3 << 32) | + i_data4, + i_addFwCallout); io_err->collectTrace("HTMGT"); } else @@ -62,4 +71,50 @@ namespace HTMGT } } + + + // Internal utility to convert OCC command type to a string + const char *command_string(const uint8_t i_cmd) + { + struct string_data_t + { + uint8_t str_num; + const char *str_data; + }; + + const static struct string_data_t L_cmd_string[] = { + {OCC_CMD_POLL, "POLL"}, + {OCC_CMD_CLEAR_ERROR_LOG, "CLEAR_ELOG"}, + {OCC_CMD_SET_STATE, "SET_STATE"}, + {OCC_CMD_SETUP_CFG_DATA, "SET_CFG_DATA"}, + {OCC_CMD_RESET_PREP, "RESET_PREP"}, + {OCC_CMD_GET_FIELD_DEBUG_DATA, "GET_FIELD_DEBUG_DATA"}, + // OCC_CMD_END_OF_TABLE should be the last entry + {OCC_CMD_END_OF_TABLE, "Unknown Command"} + }; + const uint8_t l_total = + sizeof(L_cmd_string) / sizeof(struct string_data_t); + + // TODO RTC 109066 + uint8_t l_idx = 0; + for (l_idx=0; l_idx<l_total; l_idx++) + { + if (i_cmd == L_cmd_string[l_idx].str_num) + { + // Return Code found + break; + } + } + + if (l_total == l_idx) + { + // Set index to last entry record + l_idx = l_total - 1; + } + + return L_cmd_string[l_idx].str_data; + } // end command_string() + + + } // end namespace diff --git a/src/usr/htmgt/htmgt_utility.H b/src/usr/htmgt/htmgt_utility.H index 5ff06d0b0..cbc5b1fb9 100644 --- a/src/usr/htmgt/htmgt_utility.H +++ b/src/usr/htmgt/htmgt_utility.H @@ -28,6 +28,7 @@ #include <stdint.h> #include <trace/interface.H> #include <errl/errlmanager.H> +#include "htmgt_occcmd.H" #define TMGT_DBG( _fmt_, _args_...) \ @@ -78,7 +79,54 @@ namespace HTMGT // Trace definition extern trace_desc_t* g_trac_htmgt; - // Create/Build an Error log and add HTMGT component trace + // Debug flags + extern uint32_t G_debug_data; + enum debugTraceTypes + { + // Types are bit flags so can enable multiple at once + DEBUG_TRACE_OFF = 0x00, + DEBUG_TRACE_OCCCMD = 0x01, // OCC command tracing + DEBUG_TRACE_OCCCMD_FULL = 0x02, // full OCC command tracing + DEBUG_TRACE_FULL_NONVERBOSE = 0x7FFFFFFF, + DEBUG_TRACE_VERBOSE = 0x80000000, // verbose tracing + DEBUG_TRACE_FULL = 0xFFFFFFFF + }; + extern uint32_t G_debug_trace; + + + enum tmgtElogSubsecTypes + { + // Values selected to be common with FSP from tmgt_elog_parser.H + //SUBSEC_MSG_DATA_TYPE = 0x01, + //SUBSEC_ERROR_DATA_TYPE = 0x06, + //SUBSEC_ENERGYSCALE_DATA_TYPE = 0x08, + //SUBSEC_OCC_ELOG_DATA_TYPE = 0x0A, + //SUBSEC_OCC_FFDC_DATA_TYPE = 0x0B, + //SUBSEC_MSG_DATA_TRUNCATED = 0x0C, + SUBSEC_OCC_CMD_DATA = 0x0D, + SUBSEC_OCC_RSP_DATA = 0x0E, + //SUBSEC_ELOG_TYPE_TOIF_RESET = 0x10, + //SUBSEC_ELOG_TYPE_OCC_RESET = 0x11, + //SUBSEC_ELOG_TYPE_PCAP_DATA = 0x12, + //SUBSEC_ELOG_TYPE_THERMAL_DATA = 0x13, + //SUBSEC_PROC_SCOM_REGISTERS = 0x14, + // 0xE0-0xEF are reserved for OCC Exceptions + }; + + + /** + * @brief Create/Build an Error log and add HTMGT component trace + * + * @param[in,out] io_err Error handle to use or NULL to create new handle + * @param[in] i_modid Module ID + * @param[in] i_rc Return Code + * @param[in] i_data1 User data word 1 + * @param[in] i_data2 User data word 2 + * @param[in] i_data3 User data word 3 + * @param[in] i_data4 User data word 4 + * @param[in] i_sev Error severity + * @param[in] i_addFwCallout true if a FW Callout should be added + */ void bldErrLog(errlHndl_t & io_err, const uint8_t i_modid, const uint16_t i_rc, @@ -86,8 +134,19 @@ namespace HTMGT const uint32_t i_data2 = 0, const uint32_t i_data3 = 0, const uint32_t i_data4 = 0, - const ERRORLOG::errlSeverity_t i_sev = ERRORLOG::ERRL_SEV_INFORMATIONAL); - + const ERRORLOG::errlSeverity_t i_sev = + ERRORLOG::ERRL_SEV_INFORMATIONAL, + const bool i_addFwCallout = false); + + + /** + * @brief Internal utility to convert OCC command type to a string + * + * @param[in] i_cmd OCC command type + * + * @return text string description of command + */ + const char *command_string(const uint8_t i_cmd); } // end namespace diff --git a/src/usr/htmgt/test/htmgt_occcmd_test.H b/src/usr/htmgt/test/htmgt_occcmd_test.H new file mode 100644 index 000000000..eb92fac32 --- /dev/null +++ b/src/usr/htmgt/test/htmgt_occcmd_test.H @@ -0,0 +1,335 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/test/htmgt_occcmd_test.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 __HTMGT_OCCCMD_TEST_H +#define __HTMGT_OCCCMD_TEST_H + +#include <cxxtest/TestSuite.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <vfs/vfs.H> + +#include <htmgt/htmgt.H> + +#include <targeting/common/targetservice.H> +#include <targeting/common/attributes.H> +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/util.H> + +#include <htmgt_activate.H> +#include <htmgt_occcmd.H> + + +using namespace TARGETING; + + +class htmgtOccCmdTest: public CxxTest::TestSuite +{ + public: + + // TODO RTC 118875 + void test_occcmd_poll(void) + { + errlHndl_t l_err = NULL; + bool locallyLoaded = false; + TS_TRACE("entered test_occcmd_poll"); + + if(!VFS::module_is_loaded("libhtmgt.so")) + { + l_err = VFS::module_load("libhtmgt.so"); + if( l_err ) + { + TS_FAIL("Could not load libhtmgt.so module"); + errlCommit(l_err,HTMGT_COMP_ID); + } + else + { + locallyLoaded = true; + } + } + + HTMGT::occMgr::instance().buildOccs(); + if (HTMGT::occMgr::instance().getNumOccs() > 0) + { + HTMGT::Occ *l_occ = + HTMGT::occMgr::instance().getMasterOcc(); + + // create 1 byte buffer for poll command data + const uint8_t l_cmdData[1] = { 0x10 /*version*/ }; + + // Normal Poll with default response + HTMGT::OccCmd l_cmd(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_cmd.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + TS_FAIL("occcmd_poll: Poll command failed" ); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_cmd.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_cmd.getRspStatus()); + } + + + // Timeout waiting for OCC to respond to Poll cmd + HTMGT::G_debug_data = 0x01; + HTMGT::OccCmd l_pollTimeout(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_pollTimeout.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + if (0x2635 == l_err->reasonCode()) + { + TS_TRACE("occcmd_poll: Poll timeout as expected"); + } + else + { + TS_FAIL("occcmd_poll: Did not fail with 0x2635"); + } + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_pollTimeout.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, + l_pollTimeout.getRspStatus()); + TS_FAIL("occcmd_poll: Poll should have failed due to" + " timeout waiting for response"); + } + HTMGT::G_debug_data = 0x00; + + + // Normal Poll with default response + HTMGT::OccCmd l_cmd2(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_cmd2.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + TS_FAIL("occcmd_poll: Poll 2 command failed" ); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_cmd2.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_cmd2.getRspStatus()); + } + + + // Timeout waiting for OCC to receive next command + HTMGT::G_debug_data = 0x02; + HTMGT::OccCmd l_pollTimeout2(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_pollTimeout2.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + if (0x2635 == l_err->reasonCode()) + { + TS_TRACE("occcmd_poll: Poll timeout as expected"); + } + else + { + TS_FAIL("occcmd_poll: Did not fail with 0x2635"); + } + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_pollTimeout2.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, + l_pollTimeout2.getRspStatus()); + TS_FAIL("occcmd_poll: Poll should have failed due to" + " timeout waiting" + " to receive cmd"); + } + HTMGT::G_debug_data = 0x00; + + + // Normal Poll with default response + HTMGT::OccCmd l_cmd3(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_cmd3.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + TS_FAIL("occcmd_poll: Poll 3 command failed" ); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_cmd3.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_cmd3.getRspStatus()); + } + + + // Bad checkum in OCC response + HTMGT::G_debug_data = 0x03; + HTMGT::OccCmd l_pollChecsum(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_pollChecsum.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + if (0x2619 == l_err->reasonCode()) + { + TS_TRACE("occcmd_poll: Checksum fail as expected"); + } + else + { + TS_FAIL("occcmd_poll: Did not fail with 0x2619"); + } + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_pollChecsum.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_pollChecsum.getRspStatus()); + TS_FAIL("occcmd_poll: Poll should have failed with a" + " checksum failure" ); + } + HTMGT::G_debug_data = 0x00; + + + // Normal Poll with default response + HTMGT::OccCmd l_cmd4(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_cmd4.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + TS_FAIL("occcmd_poll: Poll 4 command failed" ); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_cmd4.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_cmd4.getRspStatus()); + } + + + // OCC exception + HTMGT::G_debug_data = 0xE0; + HTMGT::OccCmd l_exception(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_exception.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + if (0x2619 == l_err->reasonCode()) + { + TS_TRACE("occcmd_poll: Checksum fail as expected"); + } + else + { + TS_FAIL("occcmd_poll: Did not fail with 0x2619"); + } + TS_TRACE("occcmd_poll: Check for 2AE0 exception logs"); + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_exception.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_exception.getRspStatus()); + TS_FAIL("occcmd_poll: Poll should have failed with an" + " OCC exception" ); + } + HTMGT::G_debug_data = 0x00; + + + // Normal Poll with default response + HTMGT::OccCmd l_cmd5(l_occ, HTMGT::OCC_CMD_POLL, + sizeof(l_cmdData), l_cmdData); + l_err = l_cmd5.sendOccCmd(); + if (l_err != NULL) + { + // Poll failed + ERRORLOG::errlCommit(l_err, HTMGT_COMP_ID); + TS_FAIL("occcmd_poll: Poll 5 command failed" ); + } + else + { + // Poll succeeded + uint8_t * l_poll_rsp = NULL; + uint32_t l_poll_rsp_size = + l_cmd5.getResponseData(l_poll_rsp); + TS_TRACE("test_occcmd_poll: length=%d, status=0x%02X", + l_poll_rsp_size, l_cmd5.getRspStatus()); + } + + } + else + { + TS_FAIL("occcmd_poll: Could not find any OCCs" ); + } + + if (locallyLoaded) + { + VFS::module_unload("libhtmgt.so"); + } + + TS_TRACE("exiting test_occcmd_poll"); + } + +}; + +#endif diff --git a/src/usr/htmgt/test/htmgt_test.H b/src/usr/htmgt/test/htmgt_test.H new file mode 100644 index 000000000..4cf7264c2 --- /dev/null +++ b/src/usr/htmgt/test/htmgt_test.H @@ -0,0 +1,225 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/test/htmgt_test.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] 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 __HTMGTTEST_H +#define __HTMGTTEST_H + +#include <cxxtest/TestSuite.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <vfs/vfs.H> + +#include <htmgt/htmgt.H> +#include <htmgt_activate.H> + +#include <targeting/common/targetservice.H> +#include <targeting/common/attributes.H> +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/util.H> + + +using namespace TARGETING; + + +class htmgtTest: public CxxTest::TestSuite +{ + public: + + // Check for HTMGT library + bool verifyModuleLoaded(const char *i_modname) + { + bool loadedLocally = false; + + if(!VFS::module_is_loaded(i_modname)) + { + errlHndl_t l_err = VFS::module_load(i_modname); + if( l_err ) + { + TS_FAIL("Could not load %s module", i_modname); + errlCommit(l_err,HTMGT_COMP_ID); + } + else + { + loadedLocally = true; + } + } + + return loadedLocally; + } + + + // Get a target for the first OCC + TARGETING::TargetHandle_t getFirstOccTarget() + { + TARGETING::TargetHandle_t o_occTarget = NULL; + + // Get all functional processors + TARGETING::TargetHandleList pProcs; + TARGETING::getChipResources(pProcs, + TARGETING::TYPE_PROC, + TARGETING::UTIL_FILTER_FUNCTIONAL); + if (pProcs.size() > 0) + { + const uint8_t instance = + pProcs[0]->getAttr<TARGETING::ATTR_POSITION>(); + TS_TRACE("buildOccs: PROC%d is functional", instance); + + // Get functional OCC (one per proc) + TARGETING::TargetHandleList pOccs; + getChildChiplets(pOccs, pProcs[0], TARGETING::TYPE_OCC); + if (pOccs.size() > 0) + { + // Use first OCC target + TS_TRACE("getFirstOccTarget: Found OCC%d", instance); + o_occTarget = pOccs[0]; + } + } + if (NULL == o_occTarget) + { + TS_FAIL("getFirstOccTarget: did not find functional OCC"); + } + + return o_occTarget; + } + + + void test_occdataattr(void) + { + TS_TRACE("entered test_occdataattr"); + + uint8_t occControlData[256]; + TargetHandleList procChips; + getAllChips(procChips, TYPE_PROC, true); + uint32_t index = 0; + for (TargetHandleList::iterator itr = procChips.begin(); + itr != procChips.end(); + ++itr) + { + const uint32_t *wordPtr = (uint32_t*)occControlData; + itr[index]->tryGetAttr<ATTR_OCC_CONTROL_DATA>(occControlData); + TS_TRACE("test_occdataattr[%d]: 0x%08X ...", + index++, *wordPtr); + // TODO RTC 109066 + } + + TS_TRACE("exiting test_occdataattr"); + } + + + void test_occloadstartfail(void) + { + TS_TRACE("entered test_occloadstartfail"); + const bool locallyLoaded = verifyModuleLoaded("libhtmgt.so"); + + TARGETING::TargetHandle_t failedOcc = getFirstOccTarget(); + HTMGT::processOccStartStatus(false, failedOcc); + if (HTMGT::occMgr::instance().getNumOccs() != 0) + { + TS_FAIL("occloadstartfail: No OCCs should be available"); + } + + if (locallyLoaded) + { + VFS::module_unload("libhtmgt.so"); + } + + TS_TRACE("exiting test_occloadstartfail"); + } + + + void test_occloadstartsuccess(void) + { + TS_TRACE("entered test_occloadstartsuccess"); + const bool locallyLoaded = verifyModuleLoaded("libhtmgt.so"); + + HTMGT::processOccStartStatus(true); + if (HTMGT::occMgr::instance().getNumOccs() == 0) + { + TS_FAIL("occloadstartsuccess: No OCCs are available"); + } + + if (locallyLoaded) + { + VFS::module_unload("libhtmgt.so"); + } + + TS_TRACE("exiting test_occloadstartsuccess"); + } + + + void test_processoccerror(void) + { + TS_TRACE("entered test_processoccerror"); + const bool locallyLoaded = verifyModuleLoaded("libhtmgt.so"); + + TARGETING::TargetHandle_t occTarget = getFirstOccTarget(); + HTMGT::occMgr::instance().buildOccs(); + if (HTMGT::occMgr::instance().getNumOccs() > 0) + { + HTMGT::processOccError(occTarget); + // TODO RTC 109224 + } + else + { + TS_FAIL("processoccerror: Couldnt find a functional OCC"); + } + + if (locallyLoaded) + { + VFS::module_unload("libhtmgt.so"); + } + + TS_TRACE("exiting test_processoccerror"); + } + + void test_processoccreset(void) + { + TS_TRACE("entered test_processoccreset"); + const bool locallyLoaded = verifyModuleLoaded("libhtmgt.so"); + + TARGETING::TargetHandle_t occTarget = getFirstOccTarget(); + HTMGT::occMgr::instance().buildOccs(); + if (HTMGT::occMgr::instance().getNumOccs() > 0) + { + HTMGT::processOccReset(occTarget); + // TODO RTC 115296 + } + else + { + TS_FAIL("processoccreset: Couldnt find a functional OCC"); + } + + if (locallyLoaded) + { + VFS::module_unload("libhtmgt.so"); + } + + TS_TRACE("exiting test_processoccreset"); + } + +}; + +#endif diff --git a/src/usr/htmgt/test/makefile b/src/usr/htmgt/test/makefile index a80ff55e2..cd03f5636 100644 --- a/src/usr/htmgt/test/makefile +++ b/src/usr/htmgt/test/makefile @@ -31,6 +31,7 @@ EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/include EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/mc_config/mss_eff_config +EXTRAINCDIR += ${ROOTPATH}/src/usr/htmgt MODULE = testhtmgt TESTS = *.H |