summaryrefslogtreecommitdiffstats
path: root/src/usr/occ
diff options
context:
space:
mode:
authorDan Crowell <dcrowell@us.ibm.com>2016-04-08 21:03:51 -0500
committerStephen Cprek <smcprek@us.ibm.com>2016-04-21 13:51:32 -0500
commit76f1c48130a060fbe83c851fce2474c17b2df9b2 (patch)
treee258515dcbdab5817603c9d290befe2324df7d59 /src/usr/occ
parent3967f43b9478d7e6b58180dd0b331e61412997cd (diff)
downloadtalos-hostboot-76f1c48130a060fbe83c851fce2474c17b2df9b2.tar.gz
talos-hostboot-76f1c48130a060fbe83c851fce2474c17b2df9b2.zip
Removing some more old fapi1 and hwp code
Deleted all of the old fapi1 code Moved potentially reuseable occ code to a new dir Deleted a variety of p8 hwp files Change-Id: I8b6ab72fef3f1413d919bdd21bc88f2c4f59c5c3 RTC: 146345 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/23075 Tested-by: Jenkins Server Tested-by: FSP CI Jenkins Reviewed-by: Matt Derksen <v2cibmd@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Reviewed-by: William G. Hoffa <wghoffa@us.ibm.com>
Diffstat (limited to 'src/usr/occ')
-rw-r--r--src/usr/occ/makefile37
-rw-r--r--src/usr/occ/occ.C572
-rw-r--r--src/usr/occ/occ.mk84
-rw-r--r--src/usr/occ/occAccess.C292
-rw-r--r--src/usr/occ/occ_common.C936
-rw-r--r--src/usr/occ/p8_pmc_force_vsafe.C517
-rwxr-xr-xsrc/usr/occ/p8_pmc_force_vsafe.H81
-rw-r--r--src/usr/occ/runtime/makefile39
-rw-r--r--src/usr/occ/runtime/rt_occ.C486
9 files changed, 3044 insertions, 0 deletions
diff --git a/src/usr/occ/makefile b/src/usr/occ/makefile
new file mode 100644
index 000000000..0d5144e99
--- /dev/null
+++ b/src/usr/occ/makefile
@@ -0,0 +1,37 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/occ/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2013,2016
+# [+] 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
+ROOTPATH = ../../../../..
+
+MODULE = occ
+
+SUBDIRS += runtime.d
+
+## Objects unique to HB IPL
+OBJS +=
+
+## Objects common to HB IPL and HBRT
+include occ.mk
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/occ/occ.C b/src/usr/occ/occ.C
new file mode 100644
index 000000000..c13f09e70
--- /dev/null
+++ b/src/usr/occ/occ.C
@@ -0,0 +1,572 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/occ/occ.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2016 */
+/* [+] 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 <stdint.h>
+#include <config.h>
+
+#include <hwpf/hwp/occ/occ.H>
+#include <hwpf/hwp/occ/occ_common.H>
+
+#include <initservice/taskargs.H>
+#include <errl/errlentry.H>
+
+#include <devicefw/userif.H>
+#include <sys/misc.h>
+#include <sys/mm.h>
+#include <sys/mmio.h>
+#include <vmmconst.h>
+#include <kernel/vmmmgr.H> // INITIAL_MEM_SIZE
+
+// targeting support
+#include <targeting/common/commontargeting.H>
+#include <targeting/common/utilFilter.H>
+#include <targeting/common/targetservice.H>
+#include <targeting/common/util.H>
+
+// fapi support
+#include <fapi.H>
+#include <fapiPlatHwpInvoker.H>
+#include <hwpf/plat/fapiPlatTrace.H>
+#include <isteps/hwpf_reasoncodes.H>
+
+#include <vfs/vfs.H>
+#include <util/utillidmgr.H>
+
+#include <htmgt/htmgt.H>
+
+// Procedures
+#include <p8_pba_init.H>
+#include <p8_occ_control.H>
+#include <p8_pba_bar_config.H>
+#include <p8_pm_init.H>
+#include <p8_pm_firinit.H>
+
+#include <config.h>
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+extern trace_desc_t* g_fapiTd;
+
+using namespace TARGETING;
+
+namespace HBOCC
+{
+ /**
+ * @brief Determine homer addresses and load OCC image for a processor.
+ *
+ * @param[in] i_target0 Target proc to load
+ * @param[in] i_homerVirtAddrBase
+ * IPL: Base Virtual address of all HOMER images
+ * Runtime: Ignored - Determined using Attributes
+ *
+ * @param[in] i_homerPhysAddrBase
+ * IPL: Base Physical address of all HOMER images
+ * Runtime: Ignored - Determined using Attributes
+ * @param[in] i_useSRAM: bool - use SRAM for OCC image, ie during IPL
+ * true if during IPL, false if at end of IPL (default)
+ *
+ * @return errlHndl_t Error log
+ */
+
+ errlHndl_t primeAndLoadOcc (Target* i_target,
+ void* i_homerVirtAddrBase,
+ uint64_t i_homerPhysAddrBase,
+ bool i_useSRAM)
+ {
+ errlHndl_t l_errl = NULL;
+
+ TRACUCOMP( g_fapiTd,
+ ENTER_MRK"primeAndLoadOcc(%d)", i_useSRAM);
+
+ do {
+ //==============================
+ //Setup Addresses
+ //==============================
+ uint64_t occImgPaddr, occImgVaddr;
+ uint64_t commonPhysAddr, homerHostVirtAddr;
+
+#ifndef __HOSTBOOT_RUNTIME
+ const uint8_t procPos = i_target->getAttr<ATTR_POSITION>();
+ const uint64_t procOffset = (procPos * VMM_HOMER_INSTANCE_SIZE);
+
+ if (i_useSRAM)
+ {
+ occImgVaddr = reinterpret_cast<uint64_t>(i_homerVirtAddrBase);
+ }
+ else
+ {
+ occImgVaddr = reinterpret_cast<uint64_t>(i_homerVirtAddrBase) +
+ procOffset + HOMER_OFFSET_TO_OCC_IMG;
+ }
+
+ occImgPaddr =
+ i_homerPhysAddrBase + procOffset + HOMER_OFFSET_TO_OCC_IMG;
+
+ commonPhysAddr =
+ i_homerPhysAddrBase + VMM_HOMER_REGION_SIZE;
+
+ homerHostVirtAddr = reinterpret_cast<uint64_t>
+ (i_homerVirtAddrBase) + procOffset +
+ HOMER_OFFSET_TO_OCC_HOST_DATA;
+#else
+ uint64_t homerPaddr = i_target->getAttr<ATTR_HOMER_PHYS_ADDR>();
+ uint64_t homerVaddr = i_target->getAttr<ATTR_HOMER_VIRT_ADDR>();
+
+ occImgPaddr = homerPaddr + HOMER_OFFSET_TO_OCC_IMG;
+ occImgVaddr = homerVaddr + HOMER_OFFSET_TO_OCC_IMG;
+
+ TARGETING::Target* sys = NULL;
+ TARGETING::targetService().getTopLevelTarget(sys);
+ commonPhysAddr =
+ sys->getAttr<ATTR_OCC_COMMON_AREA_PHYS_ADDR>();
+
+ homerHostVirtAddr =
+ homerVaddr + HOMER_OFFSET_TO_OCC_HOST_DATA;
+#endif
+
+ //==============================
+ // Load OCC
+ //==============================
+ l_errl = HBOCC::loadOCC(i_target,
+ occImgPaddr,
+ occImgVaddr,
+ commonPhysAddr,
+ i_useSRAM);
+ if(l_errl != NULL)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"primeAndLoadOcc: loadOCC failed" );
+ break;
+ }
+
+#ifdef CONFIG_IPLTIME_CHECKSTOP_ANALYSIS
+#ifndef __HOSTBOOT_RUNTIME
+ if (i_useSRAM)
+ {
+ //==============================
+ //Setup host data area in SRAM
+ //==============================
+ l_errl = HBOCC::loadHostDataToSRAM(i_target,
+ PRDF::MASTER_PROC_CORE);
+ if( l_errl != NULL )
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"loading Host Data Area failed!" );
+ break;
+ }
+ }
+ else
+#endif
+#endif
+ {
+ //==============================
+ //Setup host data area of HOMER;
+ //==============================
+ void* occHostVirt = reinterpret_cast<void*>(homerHostVirtAddr);
+ l_errl = HBOCC::loadHostDataToHomer(i_target,occHostVirt);
+ if( l_errl != NULL )
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"loading Host Data Area failed!" );
+ break;
+ }
+ }
+ } while (0);
+
+ TRACUCOMP( g_fapiTd,
+ EXIT_MRK"primeAndLoadOcc" );
+ return l_errl;
+ }
+
+ /**
+ * @brief Starts OCCs on all Processors in the node
+ * This is intended to be used for AVP testing.
+ *
+ * @param[out] o_failedOccTarget: Pointer to the target failing
+ * loadnStartAllOccs
+ * @param[in] i_useSRAM: bool - use SRAM for OCC image, ie during IPL
+ * true if during IPL, false if at end of IPL (default)
+ * @return errlHndl_t Error log if OCC load failed
+ */
+ errlHndl_t loadnStartAllOccs(TARGETING::Target *& o_failedOccTarget,
+ bool i_useSRAM)
+ {
+ errlHndl_t l_errl = NULL;
+ void* homerVirtAddrBase = NULL;
+ uint64_t homerPhysAddrBase = VMM_HOMER_REGION_START_ADDR;
+ bool winkle_loaded = false;
+
+ TRACUCOMP( g_fapiTd,
+ ENTER_MRK"loadnStartAllOccs(%d)", i_useSRAM);
+
+ do {
+#ifndef __HOSTBOOT_RUNTIME
+ //OCC requires the build_winkle_images library
+ if ( !VFS::module_is_loaded( "libbuild_winkle_images.so" ) )
+ {
+ l_errl = VFS::module_load( "libbuild_winkle_images.so" );
+
+ if ( l_errl )
+ {
+ // load module returned with errl set
+ TRACFCOMP( g_fapiTd,ERR_MRK"loadnStartAllOccs: Could not load build_winkle module" );
+ // break from do loop if error occured
+ break;
+ }
+ winkle_loaded = true;
+ }
+
+ assert(VMM_HOMER_REGION_SIZE <= THIRTYTWO_GB,
+ "loadnStartAllOccs: Unsupported HOMER Region size");
+
+ if (!i_useSRAM)
+ {
+ //If running Sapphire need to place this at the top of memory
+ if(TARGETING::is_sapphire_load())
+ {
+ homerPhysAddrBase = TARGETING::get_top_mem_addr();
+ assert (homerPhysAddrBase != 0,
+ "loadnStartAllOccs: Top of memory was 0!");
+ homerPhysAddrBase -= VMM_ALL_HOMER_OCC_MEMORY_SIZE;
+ }
+ TRACFCOMP( g_fapiTd, "HOMER is at %.16X", homerPhysAddrBase );
+
+ //Map entire homer region into virtual memory
+ homerVirtAddrBase =
+ mm_block_map(reinterpret_cast<void*>(homerPhysAddrBase),
+ VMM_HOMER_REGION_SIZE);
+ TRACFCOMP( g_fapiTd, "HOMER virtaddrbase %.16X", homerVirtAddrBase );
+ }
+ else
+ {
+ // Use page of memory previously set aside for OCC Bootloader
+ // see src/kernel/misc.C::expand_full_cache()
+ homerVirtAddrBase = reinterpret_cast<void*>
+ (VmmManager::INITIAL_MEM_SIZE);
+ homerPhysAddrBase = mm_virt_to_phys(homerVirtAddrBase);
+
+ TRACUCOMP(g_fapiTd, "Virtual Address = 0x%16lx",
+ homerVirtAddrBase);
+ TRACUCOMP(g_fapiTd, "Physical Address= 0x%16lx",
+ homerPhysAddrBase);
+ }
+#endif
+
+ if (i_useSRAM)
+ {
+ // OCC is going into L3 and SRAM so only need 1 prime and load
+ // into the Master Proc
+ TargetService & tS = targetService();
+ Target * sysTarget = NULL;
+ tS.getTopLevelTarget( sysTarget );
+ assert( sysTarget != NULL );
+ Target* masterproc = NULL;
+ tS.masterProcChipTargetHandle( masterproc );
+
+ /******* SETUP AND LOAD **************/
+ l_errl = primeAndLoadOcc (masterproc,
+ homerVirtAddrBase,
+ homerPhysAddrBase,
+ i_useSRAM);
+ if(l_errl)
+ {
+ o_failedOccTarget = masterproc;
+ TRACFCOMP( g_fapiImpTd, ERR_MRK
+ "loadnStartAllOccs:primeAndLoadOcc failed");
+ break;
+ }
+
+ /********* START OCC *************/
+ l_errl = HBOCC::startOCC (masterproc, NULL, o_failedOccTarget);
+
+
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"loadnStartAllOccs: startOCC failed");
+ break;
+ }
+ }
+ else
+ {
+
+ TargetHandleList procChips;
+ getAllChips(procChips, TYPE_PROC, true);
+
+ if(procChips.size() == 0)
+ {
+ TRACFCOMP( g_fapiTd,INFO_MRK"loadnStartAllOccs: No processors found" );
+ //We'll never get this far in the IPL without any processors,
+ // so just exit.
+ break;
+ }
+
+ TRACUCOMP( g_fapiTd,
+ INFO_MRK"loadnStartAllOccs: %d procs found",
+ procChips.size());
+
+ TargetHandleList::iterator itr1 = procChips.begin();
+ //The OCC Procedures require processors within a DCM be
+ //setup together. So, first checking if any proc has
+ //DCM installed attribute set. If not, we can iterate
+ //over the list in any order.
+
+ //If DCM installed is set, we work under the assumption
+ //that each nodeID is a DCM. So sort the list by NodeID
+ //then call OCC Procedures on NodeID pairs.
+ if(0 ==
+ (*itr1)->getAttr<ATTR_PROC_DCM_INSTALLED>())
+ {
+ TRACUCOMP( g_fapiTd,
+ INFO_MRK"loadnStartAllOccs: non-dcm path entered");
+
+ for (TargetHandleList::iterator itr = procChips.begin();
+ itr != procChips.end();
+ ++itr)
+ {
+ /******* SETUP AND LOAD **************/
+ l_errl = primeAndLoadOcc (*itr,
+ homerVirtAddrBase,
+ homerPhysAddrBase,
+ i_useSRAM);
+ if(l_errl)
+ {
+ o_failedOccTarget = *itr;
+ TRACFCOMP( g_fapiImpTd, ERR_MRK
+ "loadnStartAllOccs:primeAndLoadOcc failed");
+ break;
+ }
+
+ /********* START OCC *************/
+ l_errl = HBOCC::startOCC (*itr, NULL, o_failedOccTarget);
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"loadnStartAllOccs: startOCC failed");
+ break;
+ }
+ }
+ if (l_errl)
+ {
+ break;
+ }
+
+ }
+ else
+ {
+ TRACUCOMP( g_fapiTd,
+ INFO_MRK"loadnStartAllOccs: Following DCM Path");
+
+ std::sort(procChips.begin(),
+ procChips.end(),
+ orderByNodeAndPosition);
+
+ TRACUCOMP( g_fapiTd,
+ INFO_MRK"loadnStartAllOccs: procChips list sorted");
+
+ for (TargetHandleList::iterator itr = procChips.begin();
+ itr != procChips.end();
+ ++itr)
+ {
+ TRACUCOMP( g_fapiImpTd, INFO_MRK"loadnStartAllOccs: Insepcting first target" );
+ Target* targ0 = *itr;
+ Target* targ1 = NULL;
+
+ TRACUCOMP( g_fapiImpTd, INFO_MRK
+ "loadnStartAllOccs: Cur target nodeID=%d",
+ targ0->getAttr<ATTR_FABRIC_GROUP_ID>());
+
+
+ //if the next target in the list is in the same node
+ // they are on the same DCM, so bump itr forward
+ // and update targ1 pointer
+ if((itr+1) != procChips.end())
+ {
+ TRACUCOMP( g_fapiImpTd, INFO_MRK
+ "loadnStartAllOccs: n+1 target nodeID=%d",
+ ((*(itr+1))->getAttr<ATTR_FABRIC_GROUP_ID>())
+ );
+
+ if((targ0->getAttr<ATTR_FABRIC_GROUP_ID>()) ==
+ ((*(itr+1))->getAttr<ATTR_FABRIC_GROUP_ID>()))
+ {
+ itr++;
+ targ1 = *itr;
+ }
+ }
+
+ /********** Setup and load targ0 ***********/
+ l_errl = primeAndLoadOcc (targ0,
+ homerVirtAddrBase,
+ homerPhysAddrBase,
+ i_useSRAM);
+ if(l_errl)
+ {
+ o_failedOccTarget = targ0;
+ TRACFCOMP( g_fapiImpTd, ERR_MRK
+ "loadnStartAllOccs: "
+ "primeAndLoadOcc failed on targ0");
+ break;
+ }
+
+ /*********** Setup and load targ1 **********/
+ l_errl = primeAndLoadOcc (targ1,
+ homerVirtAddrBase,
+ homerPhysAddrBase,
+ i_useSRAM);
+ if(l_errl)
+ {
+ o_failedOccTarget = targ1;
+ TRACFCOMP( g_fapiImpTd, ERR_MRK
+ "loadnStartAllOccs: "
+ "primeAndLoadOcc failed on targ1");
+ break;
+ }
+
+ /*********** Start OCC *******************/
+ l_errl = HBOCC::startOCC (targ0, targ1, o_failedOccTarget);
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK
+ "loadnStartAllOccs: start failed");
+ break;
+ }
+ }
+ if (l_errl)
+ {
+ break;
+ }
+ }
+ }
+ } while(0);
+
+ errlHndl_t l_tmpErrl = NULL;
+//Unless HTMGT is in use, there are no further accesses to HOMER memory
+//required during the IPL
+#ifndef CONFIG_HTMGT
+ if(homerVirtAddrBase)
+ {
+ int rc = 0;
+ rc = mm_block_unmap(homerVirtAddrBase);
+ if (rc != 0)
+ {
+ /*@
+ * @errortype
+ * @moduleid fapi::MOD_OCC_LOAD_START_ALL_OCCS
+ * @reasoncode fapi::RC_MM_UNMAP_ERR
+ * @userdata1 Return Code
+ * @userdata2 Unmap address
+ * @devdesc mm_block_unmap() returns error
+ * @custdesc A problem occurred during the IPL
+ * of the system.
+ */
+ l_tmpErrl =
+ new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ fapi::MOD_OCC_LOAD_START_ALL_OCCS,
+ fapi::RC_MM_UNMAP_ERR,
+ rc,
+ reinterpret_cast<uint64_t>
+ (homerVirtAddrBase));
+ if(l_tmpErrl)
+ {
+ if(l_errl)
+ {
+ errlCommit( l_tmpErrl, HWPF_COMP_ID );
+ }
+ else
+ {
+ l_errl = l_tmpErrl;
+ }
+ }
+ }
+ }
+#endif
+ //make sure we always unload the module
+ if (winkle_loaded)
+ {
+ l_tmpErrl = VFS::module_unload( "libbuild_winkle_images.so" );
+ if ( l_tmpErrl )
+ {
+ TRACFCOMP
+ ( g_fapiTd,ERR_MRK
+ "loadnStartAllOccs: Error unloading build_winkle module"
+ );
+ if(l_errl)
+ {
+ errlCommit( l_tmpErrl, HWPF_COMP_ID );
+ }
+ else
+ {
+ l_errl = l_tmpErrl;
+ }
+ }
+ }
+
+ TRACUCOMP( g_fapiTd,
+ EXIT_MRK"loadnStartAllOccs" );
+
+ return l_errl;
+ }
+
+ /**
+ * @brief Starts OCCs on all Processors in the node
+ * This is intended to be used for Open Power.
+ *
+ * @return errlHndl_t Error log if OCC load failed
+ */
+ errlHndl_t activateOCCs(bool i_useSRAM)
+ {
+ TRACUCOMP( g_fapiTd,ENTER_MRK"activateOCCs(%d)", i_useSRAM );
+ errlHndl_t l_errl = NULL;
+ TARGETING::Target* l_failedOccTarget = NULL;
+#ifdef CONFIG_HTMGT
+ bool occStartSuccess = true;
+#endif
+
+ l_errl = loadnStartAllOccs (l_failedOccTarget, i_useSRAM);
+ if (l_errl)
+ {
+ errlCommit (l_errl, HWPF_COMP_ID);
+#ifdef CONFIG_HTMGT
+ occStartSuccess = false;
+#endif
+ }
+
+ //TODO RTC:116027
+ //HB configures/enables the occ buffers
+
+ //TODO RTC:115636
+ //HB enables the scon-via-i2c logic on the OCCs
+
+#ifdef CONFIG_HTMGT
+ // Report OCC status to HTMGT
+ if (!i_useSRAM)
+ {
+ HTMGT::processOccStartStatus(occStartSuccess,l_failedOccTarget);
+ }
+#endif
+ TRACUCOMP( g_fapiTd,EXIT_MRK"activateOCC" );
+ return l_errl;
+ }
+
+
+} //end OCC namespace
diff --git a/src/usr/occ/occ.mk b/src/usr/occ/occ.mk
new file mode 100644
index 000000000..a64a2f2e3
--- /dev/null
+++ b/src/usr/occ/occ.mk
@@ -0,0 +1,84 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/occ/occ.mk $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2014,2016
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+## support for Targeting and fapi
+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
+
+## pointer to common HWP files
+EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/include
+
+## pointer to already consumed procedures.
+EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images/p8_set_pore_bar
+
+## NOTE: add the base istep dir here.
+EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/occ
+
+## Include sub dirs
+## NOTE: add a new EXTRAINCDIR when you add a new HWP
+## EXAMPLE:
+## EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/occ/<HWP_dir>
+EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/occ/occ_procedures
+EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp/utility_procedures
+
+## NOTE: add new object files when you add a new HWP
+OBJS += p8_pba_init.o
+OBJS += p8_pm_init.o
+OBJS += p8_pcbs_init.o
+OBJS += p8_pmc_init.o
+OBJS += p8_poregpe_init.o
+OBJS += p8_oha_init.o
+OBJS += p8_ocb_init.o
+OBJS += p8_pss_init.o
+OBJS += p8_occ_control.o
+OBJS += p8_occ_sram_init.o
+OBJS += p8_pm_firinit.o
+OBJS += p8_pm_oha_firinit.o
+OBJS += p8_pm_pcbs_firinit.o
+OBJS += p8_pm_occ_firinit.o
+OBJS += p8_pm_pba_firinit.o
+OBJS += p8_pm_pmc_firinit.o
+OBJS += p8_pm_utils.o
+
+
+#These procedures are included per Stradale's request so
+#they can implement OCC Reset.
+OBJS += p8_pm_prep_for_reset.o
+OBJS += p8_pmc_force_vsafe.o
+OBJS += p8_ocb_indir_access.o
+OBJS += p8_ocb_indir_setup_linear.o
+
+#common occ functions between ipl and runtime
+OBJS += occ_common.o
+OBJS += occ.o
+OBJS += $(if $(CONFIG_HTMGT),occAccess.o)
+
+## NOTE: add a new directory onto the vpaths when you add a new HWP
+## EXAMPLE:
+# VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/occ/<HWP_dir>
+VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/occ/occ_procedures
+
+
diff --git a/src/usr/occ/occAccess.C b/src/usr/occ/occAccess.C
new file mode 100644
index 000000000..d06a47680
--- /dev/null
+++ b/src/usr/occ/occAccess.C
@@ -0,0 +1,292 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/occ/occAccess.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014,2016 */
+/* [+] 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 <stdint.h>
+
+#include <errl/errlentry.H>
+#include <occ/occAccess.H>
+#include <targeting/common/utilFilter.H>
+
+// Fapi
+#include <fapi.H>
+#include <fapiPlatHwpInvoker.H>
+#include <isteps/hwpf_reasoncodes.H>
+
+// Procedures
+#include <p8_ocb_init.H>
+#include <p8_ocb_indir_setup_linear.H>
+#include <p8_ocb_indir_access.H>
+
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+namespace HBOCC
+{
+
+// Passed target should be either a PROC or an OCC target
+// If passed an OCC, then use it's parent PROC
+// If passed a PROC, then use it
+errlHndl_t getChipTarget(const TARGETING::Target* i_target,
+ TARGETING::Target* & o_pChipTarget)
+{
+ errlHndl_t l_errl = NULL;
+ TARGETING::TYPE l_type = TARGETING::TYPE_NA;
+ bool l_found = false; //error if no chip target found
+ uint32_t l_huid = 0xFFFFFFFF; //read for error FFDC
+
+ do
+ {
+ if(NULL == i_target) //unexpected error
+ {
+ TRACFCOMP( g_fapiTd, ERR_MRK"getChipTarget: null target passed");
+ break; // log and return error
+ }
+
+ l_type = i_target->getAttr<TARGETING::ATTR_TYPE> ();
+ if (TARGETING::TYPE_OCC == l_type) // if OCC, use parent PROC
+ {
+ const TARGETING::Target * l_pChipTarget = getParentChip(
+ const_cast<TARGETING::Target *>(i_target));
+ o_pChipTarget = const_cast<TARGETING::Target *>(l_pChipTarget);
+ if (NULL == o_pChipTarget)
+ {
+ l_huid = i_target->getAttr<TARGETING::ATTR_HUID>();
+ TRACFCOMP( g_fapiTd, ERR_MRK"getChipTarget:"
+ " Error OCC target has no parent"
+ " Target type: 0x%X huid:0x%X",
+ l_type, l_huid);
+ break; // log and return error
+ }
+ l_found = true;
+ }
+ else if (TARGETING::TYPE_PROC == l_type) //use passed PROC target
+ {
+ o_pChipTarget = const_cast<TARGETING::Target *>(i_target);
+ l_found = true;
+ }
+ else // unexpected target type
+ {
+ l_huid = i_target->getAttr<TARGETING::ATTR_HUID>();
+ TRACFCOMP( g_fapiTd, ERR_MRK"getChipTarget:"
+ " Error Unexpected target type. Not PROC or"
+ " OCC. Target is of type: 0x%X huid:0x%X",
+ l_type, l_huid);
+ break; // log and return error
+ }
+
+ }
+ while (0);
+
+ if (!l_found)
+ {
+ /*@
+ * @errortype
+ * @moduleid fapi::MOD_GET_OCC_CHIP_TARGET
+ * @reasoncode fapi::RC_TARGET_UNSUPPORTED
+ * @userdata1 Target Type
+ * @userdata2 Target HUID
+ * @devdesc PROC or OCC expected
+ * @custdesc A problem occurred during the IPL
+ * of the system.
+ */
+ const bool hbSwError = true;
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ fapi::MOD_GET_OCC_CHIP_TARGET,
+ fapi::RC_TARGET_UNSUPPORTED,
+ l_type,
+ l_huid,
+ hbSwError);
+ }
+
+ return l_errl;
+}
+
+// common wrapper to p8_ocb_indir_access to access an OCB indirect channel
+enum accessOCBIndirectCmd
+{
+ ACCESS_OCB_READ_LINEAR,
+ ACCESS_OCB_WRITE_LINEAR,
+ ACCESS_OCB_WRITE_CIRCULAR,
+};
+
+errlHndl_t accessOCBIndirectChannel(accessOCBIndirectCmd i_cmd,
+ const TARGETING::Target * i_pTarget,
+ const uint32_t i_addr,
+ ecmdDataBufferBase & io_dataBuf)
+{
+ errlHndl_t l_errl = NULL;
+ uint32_t l_len = 0;
+ TARGETING::Target* l_pChipTarget = NULL;
+
+ uint32_t l_channel = OCB_CHAN0; // OCB channel (0,1,2,3)
+ uint32_t l_operation = OCB_GET; // Operation(Get, Put)
+ bool l_ociAddrValid = true; // use oci_address
+ bool l_setup=true; // set up linear
+
+ TRACUCOMP( g_fapiTd, ENTER_MRK"accessOCBIndirectChannel cmd=%d",i_cmd);
+
+ switch (i_cmd)
+ {
+ case (ACCESS_OCB_READ_LINEAR):
+ break; // use defaults
+ case (ACCESS_OCB_WRITE_LINEAR):
+ l_operation = OCB_PUT;
+ break;
+ case (ACCESS_OCB_WRITE_CIRCULAR):
+ l_channel = OCB_CHAN1;
+ l_operation = OCB_PUT;
+ l_ociAddrValid = false;
+ l_setup = false;
+ break;
+ }
+
+ TRACUCOMP( g_fapiTd, INFO_MRK"accessOCBIndirectChannel"
+ " channel=%d operation=%d addrValid=%d",
+ l_channel,l_operation,l_ociAddrValid);
+ do
+ {
+ l_errl = getChipTarget(i_pTarget,l_pChipTarget);
+ if (l_errl)
+ {
+ break; //exit with error
+ }
+ TRACUCOMP( g_fapiTd, INFO_MRK"accessOCBIndirectChannel:"
+ " target=%.8x type=%d",
+ get_huid(l_pChipTarget),
+ l_pChipTarget->getAttr<TARGETING::ATTR_TYPE>());
+
+ fapi::Target l_fapiTarget(fapi::TARGET_TYPE_PROC_CHIP,
+ reinterpret_cast<void *> (l_pChipTarget) );
+
+ // buffer must be multiple of bytes
+ if(io_dataBuf.getByteLength()%8 != 0)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"accessOCBIndirectChannel:"
+ " Error Improper data size:%d(in bytes),size of data"
+ " requested to be read is not aligned in size of 8 Bytes",
+ io_dataBuf.getByteLength());
+ /*@
+ * @errortype
+ * @moduleid fapi::MOD_ACCESS_OCB_INDIRECT_CHANNEL
+ * @reasoncode fapi::RC_INVALID_DATA_BUFFER_LENGTH
+ * @userdata1 Length of requested buffer size(in Bytes) to
+ * perform read operation.
+ * @userdata2 OCI address
+ * @devdesc Improper data size, data is not 8 byte aligned.
+ * @custdesc A problem occurred during the IPL
+ * of the system.
+ */
+ const bool hbSwError = true;
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ fapi::MOD_ACCESS_OCB_INDIRECT_CHANNEL,
+ fapi::RC_INVALID_DATA_BUFFER_LENGTH,
+ io_dataBuf.getByteLength(),
+ i_addr,
+ hbSwError);
+ break; // return with error
+ }
+
+ // TODO RTC: 116027 To be consistent with FSP code hwcoOCC.C,
+ // p8_ocb_indir_setup_linear is always called for read and write
+ // linear and not called for write circular.
+ // a) linear read and write set up may only be needed once
+ // b) circular write may need to be set up once
+ if (l_setup)
+ {
+ FAPI_INVOKE_HWP(l_errl, p8_ocb_indir_setup_linear, l_fapiTarget,
+ OCB_CHAN0, OCB_TYPE_LINSTR, i_addr);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"accessOCBIndirectChannel:"
+ " Error [0x%X] in call to "
+ " FAPI_INVOKE_HWP(p8_ocb_indir_setup_linear)",
+ l_errl->reasonCode());
+ break; // return with error
+ }
+ }
+
+ // perform operation
+ FAPI_INVOKE_HWP(l_errl, p8_ocb_indir_access, l_fapiTarget,
+ l_channel,l_operation,io_dataBuf.getByteLength()/8,
+ io_dataBuf,l_len,l_ociAddrValid,i_addr);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"accessOCBIndirectChannel:"
+ " Error [0x%X] in call to"
+ " FAPI_INVOKE_HWP(p8_ocb_indir_access)",
+ l_errl->reasonCode());
+ break; // return with error
+ }
+
+ }
+ while (0);
+
+ TRACUCOMP( g_fapiTd, EXIT_MRK"accessOCBIndirectChannel");
+
+ return l_errl;
+}
+
+// Read OCC SRAM
+errlHndl_t readSRAM(const TARGETING::Target * i_pTarget,
+ const uint32_t i_addr,
+ ecmdDataBufferBase & io_dataBuf)
+{
+ errlHndl_t l_errl = NULL;
+ l_errl = accessOCBIndirectChannel(ACCESS_OCB_READ_LINEAR,
+ i_pTarget,
+ i_addr,
+ io_dataBuf);
+ return l_errl;
+}
+
+// Write OCC SRAM
+errlHndl_t writeSRAM(const TARGETING::Target * i_pTarget,
+ const uint32_t i_addr,
+ ecmdDataBufferBase & i_dataBuf)
+{
+ errlHndl_t l_errl = NULL;
+ l_errl = accessOCBIndirectChannel(ACCESS_OCB_WRITE_LINEAR,
+ i_pTarget,
+ i_addr,
+ i_dataBuf);
+ return l_errl;
+}
+
+// Write OCC Circular Buffer
+errlHndl_t writeCircularBuffer(const TARGETING::Target * i_pTarget,
+ ecmdDataBufferBase & i_dataBuf)
+{
+ errlHndl_t l_errl = NULL;
+ l_errl = accessOCBIndirectChannel(ACCESS_OCB_WRITE_CIRCULAR,
+ i_pTarget,
+ 0,
+ i_dataBuf);
+ return l_errl;
+}
+
+} //end OCC namespace
diff --git a/src/usr/occ/occ_common.C b/src/usr/occ/occ_common.C
new file mode 100644
index 000000000..98a01a9da
--- /dev/null
+++ b/src/usr/occ/occ_common.C
@@ -0,0 +1,936 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/occ/occ_common.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2016 */
+/* [+] 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 <stdint.h>
+
+#include <occ/occ_common.H>
+#include <occ/occAccess.H>
+
+#include <initservice/taskargs.H>
+#include <errl/errlentry.H>
+
+#include <devicefw/userif.H>
+#include <sys/misc.h>
+#include <sys/mm.h>
+#include <sys/mmio.h>
+#include <limits.h>
+#include <vmmconst.h>
+
+// targeting support
+#include <targeting/common/commontargeting.H>
+#include <targeting/common/utilFilter.H>
+#include <targeting/common/targetservice.H>
+#include <targeting/common/util.H>
+
+// fapi support
+#include <fapi.H>
+#include <fapiPlatHwpInvoker.H>
+#include <hwpf/plat/fapiPlatTrace.H>
+#include <isteps/hwpf_reasoncodes.H>
+
+#include <vfs/vfs.H>
+#include <util/utillidmgr.H>
+#include <initservice/initserviceif.H>
+
+// Procedures
+#include <p8_pba_init.H>
+#include <p8_occ_control.H>
+#include <p8_pba_bar_config.H>
+#include <p8_pm_init.H>
+#include <p8_pm_firinit.H>
+#include <p8_pm_prep_for_reset.H>
+#include <arch/ppc.H>
+
+#ifdef CONFIG_ENABLE_CHECKSTOP_ANALYSIS
+ #include <diag/prdf/prdfWriteHomerFirData.H>
+#endif
+
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+extern trace_desc_t* g_fapiTd;
+
+using namespace TARGETING;
+
+namespace HBOCC
+{
+ /**
+ * @brief Fetches OCC image from FSP and writes to
+ * specified offset.
+ *
+ * @param[in] i_occVirtAddr Virtual
+ * address where OCC image
+ * should be loaded.
+ *
+ * @return errlHndl_t Error log image load failed
+ */
+ errlHndl_t loadOCCImageToHomer(void* i_occVirtAddr)
+ {
+ TRACUCOMP( g_fapiTd,
+ ENTER_MRK"loadOCCImageToHomer(%p)",
+ i_occVirtAddr);
+
+ errlHndl_t l_errl = NULL;
+ size_t lidSize = 0;
+ do {
+ UtilLidMgr lidMgr(HBOCC::OCC_LIDID);
+
+ l_errl = lidMgr.getLidSize(lidSize);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCCImageToHomer: Error getting lid size. lidId=0x%.8x",
+ OCC_LIDID);
+ break;
+ }
+
+ l_errl = lidMgr.getLid(i_occVirtAddr, lidSize);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCCImageToHomer: Error getting lid.. lidId=0x%.8x",
+ OCC_LIDID);
+ break;
+ }
+
+ }while(0);
+
+ TRACUCOMP( g_fapiTd,
+ EXIT_MRK"loadOCCImageToHomer");
+
+ return l_errl;
+ }
+
+#ifdef CONFIG_IPLTIME_CHECKSTOP_ANALYSIS
+ errlHndl_t loadOCCImageDuringIpl( TARGETING::Target* i_target,
+ void* i_occVirtAddr)
+ {
+ TRACUCOMP( g_fapiTd,
+ ENTER_MRK"loadOCCImageDuringIpl(%p)",
+ i_occVirtAddr);
+
+ errlHndl_t l_errl = NULL;
+ size_t lidSize = 0;
+ void* l_occImage = NULL;
+ do {
+ // allocate memory big enough for all OCC
+ l_occImage = (void*)malloc(1*MEGABYTE);
+
+ UtilLidMgr lidMgr(HBOCC::OCC_LIDID);
+
+ // Get the size of the OCC lid
+ l_errl = lidMgr.getLidSize(lidSize);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCCImageDuringIpl: Error getting lid size. lidId=0x%.8x",
+ OCC_LIDID);
+ break;
+ }
+
+ // Ensure occ lid size is less than memory allocated for it
+ assert(lidSize <= 1*MEGABYTE);
+
+ // Get the entire OCC lid and write it into temporary memory
+ l_errl = lidMgr.getLid(l_occImage, lidSize);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCCImageDuringIpl: Error getting lid. lidId=0x%.8x",
+ OCC_LIDID);
+ break;
+ }
+ // Pointer to OCC LID
+ char *l_occLid = reinterpret_cast<char*>(l_occImage);
+
+
+ // Get system target in order to access ATTR_NEST_FREQ_MHZ
+ TARGETING::TargetService & tS = TARGETING::targetService();
+ TARGETING::Target * sysTarget = NULL;
+ tS.getTopLevelTarget( sysTarget );
+ assert( sysTarget != NULL );
+
+ // Save Nest Frequency;
+ ATTR_NEST_FREQ_MHZ_type l_nestFreq =
+ sysTarget->getAttr<ATTR_FREQ_PB>();
+
+
+ size_t l_length = 0; // length of this section
+ size_t l_startOffset = 0; // offset to start of the section
+
+ // offset to length of the section
+ size_t l_offsetToLength = OCC_OFFSET_LENGTH;
+
+ // Get length of OCC bootloader
+ uint32_t *ptrToLength = (uint32_t *)(l_occLid + l_offsetToLength);
+ l_length = *ptrToLength;
+
+ // We only have PAGESIZE to work with so make sure we do not exceed
+ // limit.
+ assert(l_length <= PAGESIZE);
+ // Write the OCC Bootloader into memory
+ memcpy(i_occVirtAddr, l_occImage, l_length);
+
+
+ // OCC Main Application
+ l_startOffset = l_length; // after the Boot image
+ char * l_occMainAppPtr = reinterpret_cast<char *>(l_occLid) +
+ l_startOffset;
+
+ // Get the length of the OCC Main application
+ ptrToLength = (uint32_t *)(l_occMainAppPtr + l_offsetToLength);
+ l_length = *ptrToLength;
+
+
+ // write the IPL flag and the nest freq into OCC main app.
+ // IPL_FLAG is a two byte field. OR a 1 into these two bytes.
+ // FREQ is the 4 byte nest frequency value that goes into
+ // the same field in the HOMER.
+
+ uint16_t *ptrToIplFlag =
+ (uint16_t *)((char *)l_occMainAppPtr + OCC_OFFSET_IPL_FLAG);
+
+ uint32_t *ptrToFreq =
+ (uint32_t *)((char *)l_occMainAppPtr + OCC_OFFSET_FREQ);
+
+ *ptrToIplFlag |= 0x0001;
+ *ptrToFreq = l_nestFreq;
+
+ // Store the OCC Main applicatoin into ecmdDataBuffer
+ // so we may write it to SRAM
+ ecmdDataBufferBase l_occAppData(l_length * 8 /* bits */);
+ uint32_t rc = l_occAppData.insert((uint32_t *)l_occMainAppPtr, 0,
+ l_length * 8 /* bits */);
+ if (rc)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCCImageDuringIpl: Error %d doing insert",
+ rc);
+ // create l_errl
+ break;
+ }
+ // Write the OCC Main app into SRAM
+ const uint32_t l_SramAddrApp = OCC_SRAM_ADDRESS;
+ l_errl = HBOCC::writeSRAM(i_target, l_SramAddrApp, l_occAppData);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCCImageDuringIpl: Error in writeSRAM of app");
+ break;
+ }
+
+
+ }while(0);
+
+ //free memory used for OCC lid
+ free(l_occImage);
+
+ TRACUCOMP( g_fapiTd,
+ EXIT_MRK"loadOCCImageDuringIpl");
+ return l_errl;
+ }
+#endif
+
+ /**
+ * @brief Sets up OCC Host data in Homer
+ */
+ errlHndl_t loadHostDataToHomer( TARGETING::Target* i_proc,
+ void* i_occHostDataVirtAddr)
+ {
+ TRACUCOMP( g_fapiTd,
+ ENTER_MRK"loadHostDataToHomer(%p)",
+ i_occHostDataVirtAddr);
+
+ errlHndl_t l_errl = NULL;
+
+ //Treat virtual address as starting pointer
+ //for config struct
+ HBOCC::occHostConfigDataArea_t * config_data =
+ reinterpret_cast<HBOCC::occHostConfigDataArea_t *>
+ (i_occHostDataVirtAddr);
+
+ // Get top level system target
+ TARGETING::TargetService & tS = TARGETING::targetService();
+ TARGETING::Target * sysTarget = NULL;
+ tS.getTopLevelTarget( sysTarget );
+ assert( sysTarget != NULL );
+
+ uint32_t nestFreq = sysTarget->getAttr<ATTR_FREQ_PB>();
+
+ config_data->version = HBOCC::OccHostDataVersion;
+ config_data->nestFrequency = nestFreq;
+
+ // Figure out the interrupt type
+ if( INITSERVICE::spBaseServicesEnabled() )
+ {
+ config_data->interruptType = USE_FSI2HOST_MAILBOX;
+ }
+ else
+ {
+ config_data->interruptType = USE_PSIHB_COMPLEX;
+ }
+
+#ifdef CONFIG_ENABLE_CHECKSTOP_ANALYSIS
+ // Figure out the FIR master
+ TARGETING::Target* masterproc = NULL;
+ tS.masterProcChipTargetHandle( masterproc );
+ if( masterproc == i_proc )
+ {
+ config_data->firMaster = IS_FIR_MASTER;
+
+ // TODO: RTC 124683 The ability to write the HOMER data
+ // is currently not available at runtime.
+#ifndef __HOSTBOOT_RUNTIME
+ l_errl = PRDF::writeHomerFirData( config_data->firdataConfig,
+ sizeof(config_data->firdataConfig) );
+#endif
+
+ }
+ else
+ {
+ config_data->firMaster = NOT_FIR_MASTER;
+ }
+
+#else
+ config_data->firMaster = 0;
+ //force to an older version so we can support
+ // older levels of OCC
+ config_data->version = PRE_FIR_MASTER_VERSION;
+#endif
+
+ TRACUCOMP( g_fapiTd,
+ EXIT_MRK"loadHostDataToHomer");
+
+ return l_errl;
+ } // loadHostDataToHomer
+
+#ifdef CONFIG_IPLTIME_CHECKSTOP_ANALYSIS
+#ifndef __HOSTBOOT_RUNTIME
+ /**
+ * @brief Sets up OCC Host data in SRAM
+ */
+ errlHndl_t loadHostDataToSRAM( TARGETING::Target* i_proc,
+ const PRDF::HwInitialized_t i_curHw)
+ {
+ TRACUCOMP( g_fapiTd,
+ ENTER_MRK"loadHostDataToSRAM i_curHw=%d",i_curHw);
+
+ errlHndl_t l_errl = NULL;
+
+ //Treat virtual address as starting pointer
+ //for config struct
+ HBOCC::occHostConfigDataArea_t * config_data =
+ new HBOCC::occHostConfigDataArea_t();
+
+ // Get top level system target
+ TARGETING::TargetService & tS = TARGETING::targetService();
+ TARGETING::Target * sysTarget = NULL;
+ tS.getTopLevelTarget( sysTarget );
+ assert( sysTarget != NULL );
+
+ uint32_t nestFreq = sysTarget->getAttr<ATTR_FREQ_PB>();
+
+
+
+ config_data->version = HBOCC::OccHostDataVersion;
+ config_data->nestFrequency = nestFreq;
+
+ // Figure out the interrupt type
+ if( INITSERVICE::spBaseServicesEnabled() )
+ {
+ config_data->interruptType = USE_FSI2HOST_MAILBOX;
+ }
+ else
+ {
+ config_data->interruptType = USE_PSIHB_COMPLEX;
+ }
+
+ config_data->firMaster = IS_FIR_MASTER;
+ l_errl = PRDF::writeHomerFirData( config_data->firdataConfig,
+ sizeof(config_data->firdataConfig),
+ i_curHw);
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadHostDataToSRAM: Error in writeHomerFirData");
+ }
+ else
+ {
+ const uint32_t l_SramAddrFir = OCC_SRAM_FIR_DATA;
+ ecmdDataBufferBase l_occFirData(OCC_SRAM_FIR_LENGTH * 8 /* bits */);
+ /// copy config_data in here
+ uint32_t rc = l_occFirData.insert(
+ (uint32_t *)config_data->firdataConfig,
+ 0,
+ sizeof(config_data->firdataConfig) * 8 /* bits */);
+ if (rc)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadHostDataToSRAM: Error %d doing insert",
+ rc);
+ /*@
+ * @errortype
+ * @moduleid fapi::MOD_OCC_LOAD_HOST_DATA_TO_SRAM
+ * @reasoncode fapi::RC_ECMD_INSERT_FAILED
+ * @userdata1 Return Code
+ * @userdata2 0
+ * @devdesc ecmd insert failed for l_occFirData
+ * @custdesc A problem occurred during the IPL
+ * of the system.
+ */
+ l_errl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ fapi::MOD_OCC_LOAD_HOST_DATA_TO_SRAM,
+ fapi::RC_ECMD_INSERT_FAILED,
+ rc, 0);
+ }
+ else
+ {
+ l_errl = HBOCC::writeSRAM(i_proc, l_SramAddrFir, l_occFirData);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadHostDataToSRAM: Error in writeSRAM");
+ }
+ }
+ }
+
+ TRACUCOMP( g_fapiTd,
+ EXIT_MRK"loadHostDataToSRAM");
+
+ return l_errl;
+ } // loadHostDataToSRAM
+#endif
+#endif
+
+ errlHndl_t loadOCC(TARGETING::Target* i_target,
+ uint64_t i_occImgPaddr,
+ uint64_t i_occImgVaddr, // dest
+ uint64_t i_commonPhysAddr,
+ bool i_useSRAM)
+ {
+ errlHndl_t l_errl = NULL;
+
+ TRACFCOMP( g_fapiTd,
+ ENTER_MRK"loadOCC(0x%08X, 0x%08X, 0x%08X, %d)",
+ i_occImgPaddr, i_occImgVaddr, i_commonPhysAddr,
+ i_useSRAM);
+ do{
+ // Remember where we put things
+ // Subtract HOMER_OFFSET_TO_OCC_IMG to be technically
+ // correct though HOMER_OFFSET_TO_OCC_IMG happens to be zero
+ i_target->setAttr<ATTR_HOMER_PHYS_ADDR>
+ (i_occImgPaddr - HOMER_OFFSET_TO_OCC_IMG);
+ i_target->setAttr<ATTR_HOMER_VIRT_ADDR>
+ (i_occImgVaddr - HOMER_OFFSET_TO_OCC_IMG);
+
+ // cast OUR type of target to a FAPI type of target.
+ const fapi::Target l_fapiTarg(fapi::TARGET_TYPE_PROC_CHIP,
+ (const_cast<Target*>(i_target)));
+ TRACFCOMP( g_fapiTd, "FapiTarget: %s",l_fapiTarg.toEcmdString());
+
+ //==============================
+ //Setup for OCC Load
+ //==============================
+
+ // BAR0 is the Entire HOMER (start of HOMER contains OCC base Image)
+ // Bar size is in MB, obtained value of 4MB from Greg Still
+ TRACUCOMP( g_fapiImpTd,
+ INFO_MRK"loadOCC: OCC Address: 0x%.8X, size=0x%.8X",
+ i_occImgPaddr, VMM_HOMER_INSTANCE_SIZE_IN_MB);
+
+ FAPI_INVOKE_HWP( l_errl,
+ p8_pba_bar_config,
+ l_fapiTarg,
+ 0,
+ i_occImgPaddr,
+ VMM_HOMER_INSTANCE_SIZE_IN_MB,
+ PBA_CMD_SCOPE_NODAL );
+
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCC: Bar0 config failed!" );
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+ break;
+ }
+
+ // BAR1 is what OCC uses to talk to the Centaur
+ // Bar size is in MB
+ uint64_t centaur_addr =
+ i_target->getAttr<ATTR_IBSCOM_PROC_BASE_ADDR>();
+ FAPI_INVOKE_HWP( l_errl,
+ p8_pba_bar_config,
+ l_fapiTarg,
+ 1, //i_index
+ centaur_addr, //i_pba_bar_addr
+ (uint64_t)OCC_IBSCOM_RANGE_IN_MB, //i_pba_bar_size
+ PBA_CMD_SCOPE_NODAL ); //i_pba_cmd_scope
+
+ if ( l_errl )
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCC: Bar1 config failed!" );
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+ break;
+ }
+
+ // BAR3 is the OCC Common Area
+ // Bar size is in MB, obtained value of 8MB from Tim Hallett
+ TARGETING::Target* sys = NULL;
+ TARGETING::targetService().getTopLevelTarget(sys);
+ sys->setAttr<ATTR_OCC_COMMON_AREA_PHYS_ADDR>(i_commonPhysAddr);
+
+ TRACUCOMP( g_fapiImpTd,
+ INFO_MRK"loadOCC: OCC Common Addr: 0x%.8X,size=0x%.8X",
+ i_commonPhysAddr,VMM_OCC_COMMON_SIZE_IN_MB);
+
+ FAPI_INVOKE_HWP( l_errl,
+ p8_pba_bar_config,
+ l_fapiTarg,
+ 3,
+ i_commonPhysAddr,
+ VMM_OCC_COMMON_SIZE_IN_MB,
+ PBA_CMD_SCOPE_NODAL );
+
+ if ( l_errl )
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCC: Bar3 config failed!" );
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+ break;
+ }
+
+#ifdef CONFIG_IPLTIME_CHECKSTOP_ANALYSIS
+ if (i_useSRAM)
+ {
+ void* occVirt = reinterpret_cast<void *>(i_occImgVaddr);
+ l_errl = loadOCCImageDuringIpl( i_target, occVirt );
+ if( l_errl )
+ {
+ TRACFCOMP(g_fapiImpTd,
+ ERR_MRK"loadOCC: loadOCCImageDuringIpl failed!");
+ break;
+ }
+ }
+ else
+#endif
+ {
+ //==============================
+ //Load the OCC HOMER image
+ //==============================
+
+#ifdef CONFIG_IPLTIME_CHECKSTOP_ANALYSIS
+ // clear (up to and including) the IPL Flag
+ const uint32_t l_SramAddrApp = OCC_SRAM_ADDRESS;
+ ecmdDataBufferBase l_occAppData((OCC_OFFSET_IPL_FLAG + 6) * 8 /* bits */);
+ l_errl = HBOCC::writeSRAM(i_target, l_SramAddrApp, l_occAppData);
+ if(l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"loadOCC: Error in writeSRAM of 0");
+ break;
+ }
+#endif
+ void* occVirt = reinterpret_cast<void *>(i_occImgVaddr);
+ l_errl = loadOCCImageToHomer( occVirt );
+ if( l_errl )
+ {
+ TRACFCOMP(g_fapiImpTd,
+ ERR_MRK"loadOCC: loadOCCImageToHomer failed!");
+ break;
+ }
+ }
+ }while(0);
+
+ TRACFCOMP( g_fapiTd,
+ EXIT_MRK"loadOCC");
+ return l_errl;
+ }
+
+ /**
+ * @brief Start OCC for specified DCM pair of processors.
+ * If 2nd input is NULL, OCC will be setup on just
+ * one target.
+ */
+ errlHndl_t startOCC (Target* i_target0,
+ Target* i_target1,
+ Target *& o_failedTarget)
+ {
+ TRACFCOMP( g_fapiTd,
+ ENTER_MRK"startOCC");
+ errlHndl_t l_errl = NULL;
+
+ // cast OUR type of target to a FAPI type of target.
+ // figure out homer offsets
+ const fapi::Target
+ l_fapiTarg0(fapi::TARGET_TYPE_PROC_CHIP,
+ (const_cast<Target*>(i_target0)));
+ fapi::Target l_fapiTarg1;
+ if(i_target1)
+ {
+ l_fapiTarg1.setType(fapi::TARGET_TYPE_PROC_CHIP);
+ l_fapiTarg1.set(const_cast<Target*>(i_target1));
+ }
+ else
+ {
+ l_fapiTarg1.setType(fapi::TARGET_TYPE_NONE);
+ }
+ do {
+ //==============================
+ // Initialize the logic
+ //==============================
+
+ // Config path
+ // p8_pm_init.C enum: PM_CONFIG
+ FAPI_INVOKE_HWP( l_errl,
+ p8_pm_init,
+ l_fapiTarg0,
+ l_fapiTarg1,
+ PM_CONFIG );
+
+ if ( l_errl != NULL )
+ {
+ o_failedTarget = i_target0;
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"startOCC: p8_pm_init, config failed!");
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+ break;
+ }
+
+ // Init path
+ // p8_pm_init.C enum: PM_INIT
+ FAPI_INVOKE_HWP( l_errl,
+ p8_pm_init,
+ l_fapiTarg0,
+ l_fapiTarg1,
+ PM_INIT );
+
+ if ( l_errl != NULL )
+ {
+ o_failedTarget = i_target0;
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"startOCC: p8_pm_init, init failed!" );
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+
+ break;
+ }
+
+ //==============================
+ //Start the OCC on primary chip of DCM
+ //==============================
+ FAPI_INVOKE_HWP( l_errl,
+ p8_occ_control,
+ l_fapiTarg0,
+ PPC405_RESET_OFF,
+ PPC405_BOOT_MEM );
+
+ if ( l_errl != NULL )
+ {
+ o_failedTarget = i_target0;
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"startOCC: occ_control failed!");
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+
+ break;
+ }
+
+ //==============================
+ // Start the OCC on slave chip of DCM
+ //==============================
+ if ( l_fapiTarg1.getType() != fapi::TARGET_TYPE_NONE )
+ {
+ FAPI_INVOKE_HWP( l_errl,
+ p8_occ_control,
+ l_fapiTarg1,
+ PPC405_RESET_OFF,
+ PPC405_BOOT_MEM );
+
+ if ( l_errl != NULL )
+ {
+ o_failedTarget = i_target1;
+ TRACFCOMP( g_fapiImpTd,
+ ERR_MRK"startOCCocc_control failed on slave chip!");
+ l_errl->collectTrace(FAPI_TRACE_NAME,256);
+ l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256);
+
+ break;
+ }
+ }
+ } while (0);
+
+ TRACFCOMP( g_fapiTd,
+ EXIT_MRK"startOCC");
+ return l_errl;
+ }
+
+ /**
+ * @brief Stop OCC for specified DCM pair of processors.
+ * If 2nd input is NULL, OCC will be setup on just
+ * one target.
+ */
+ errlHndl_t stopOCC(TARGETING::Target * i_target0,
+ TARGETING::Target * i_target1)
+ {
+ TRACFCOMP( g_fapiTd,
+ ENTER_MRK"stopOCC");
+ errlHndl_t err = NULL;
+ do
+ {
+ const fapi::Target
+ l_fapiTarg0(fapi::TARGET_TYPE_PROC_CHIP,
+ (const_cast<TARGETING::Target*>(i_target0)));
+
+ fapi::Target l_fapiTarg1;
+ if(i_target1)
+ {
+ l_fapiTarg1.setType(fapi::TARGET_TYPE_PROC_CHIP);
+ l_fapiTarg1.set(const_cast<TARGETING::Target*>(i_target1));
+
+ }
+ else
+ {
+ l_fapiTarg1.setType(fapi::TARGET_TYPE_NONE);
+ }
+
+ FAPI_INVOKE_HWP( err,
+ p8_pm_prep_for_reset,
+ l_fapiTarg0,
+ l_fapiTarg1,
+ PM_RESET );
+
+ if ( err != NULL )
+ {
+ TRACFCOMP( g_fapiTd,
+ ERR_MRK"stopOCC:p8_pm_prep_for_reset failed!" );
+ err->collectTrace(FAPI_TRACE_NAME,256);
+ err->collectTrace(FAPI_IMP_TRACE_NAME,256);
+
+ break;
+ }
+
+ } while(0);
+
+ TRACFCOMP( g_fapiTd,
+ EXIT_MRK"stopOCC");
+ return err;
+ }
+
+ /**
+ * @brief Stops OCCs on all Processors in the node
+ */
+ errlHndl_t stopAllOCCs()
+ {
+ TRACFCOMP( g_fapiTd,ENTER_MRK"stopAllOCCs" );
+ errlHndl_t l_errl = NULL;
+ bool winkle_loaded = false;
+ do {
+
+#ifndef __HOSTBOOT_RUNTIME
+ //OCC requires the build_winkle_images library
+ if ( !VFS::module_is_loaded( "libbuild_winkle_images.so" ) )
+ {
+ l_errl = VFS::module_load( "libbuild_winkle_images.so" );
+
+ if ( l_errl )
+ {
+ // load module returned with errl set
+ TRACFCOMP( g_fapiTd,ERR_MRK"loadnStartAllOccs: Could not load build_winkle module" );
+ // break from do loop if error occured
+ break;
+ }
+ winkle_loaded = true;
+ }
+#endif
+
+
+ TargetHandleList procChips;
+ getAllChips(procChips, TYPE_PROC, true);
+
+ if(procChips.size() == 0)
+ {
+ TRACFCOMP( g_fapiTd,INFO_MRK"loadnStartAllOccs: No processors found" );
+ //We'll never get this far in the IPL without any processors,
+ // so just exit.
+ break;
+ }
+
+ TRACFCOMP( g_fapiTd,
+ INFO_MRK"loadnStartAllOccs: %d procs found",
+ procChips.size());
+
+ //The OCC Procedures require processors within a DCM be
+ //setup together. If DCM installed is set, we work under
+ //the assumption that each nodeID is a DCM. So sort the
+ //list by NodeID then call OCC Procedures on NodeID pairs.
+ std::sort(procChips.begin(),
+ procChips.end(),
+ orderByNodeAndPosition);
+
+ //The OCC master for the node must be reset last. For all
+ //OP systems there is only a single OCC that can be the
+ //master so it is safe to look at the MASTER_CAPABLE flag.
+ Target* masterProc0 = NULL;
+ Target* masterProc1 = NULL;
+
+ TargetHandleList::iterator itr1 = procChips.begin();
+
+ if(0 == (*itr1)->getAttr<ATTR_PROC_DCM_INSTALLED>())
+ {
+ TRACUCOMP( g_fapiTd,
+ INFO_MRK"stopAllOCCs: non-dcm path entered");
+
+ for (TargetHandleList::iterator itr = procChips.begin();
+ itr != procChips.end();
+ ++itr)
+ {
+ TargetHandleList pOccs;
+ getChildChiplets(pOccs, *itr, TYPE_OCC);
+ if (pOccs.size() > 0)
+ {
+ if( pOccs[0]->getAttr<ATTR_OCC_MASTER_CAPABLE>() )
+ {
+ masterProc0 = *itr;
+ continue;
+ }
+ }
+
+ l_errl = HBOCC::stopOCC( *itr, NULL );
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"stopAllOCCs: stop failed");
+ errlCommit (l_errl, HWPF_COMP_ID);
+ // just commit and try the next chip
+ }
+ }
+ if (l_errl)
+ {
+ break;
+ }
+ }
+ else
+ {
+ TRACFCOMP( g_fapiTd,
+ INFO_MRK"stopAllOCCs: Following DCM Path");
+
+ for (TargetHandleList::iterator itr = procChips.begin();
+ itr != procChips.end();
+ ++itr)
+ {
+ Target* targ0 = *itr;
+ Target* targ1 = NULL;
+
+ TRACFCOMP( g_fapiImpTd, INFO_MRK"stopAllOCCs: Cur target nodeID=%d",
+ targ0->getAttr<ATTR_FABRIC_GROUP_ID>());
+
+ //if the next target in the list is in the same node
+ // they are on the same DCM, so bump itr forward
+ // and update targ0 pointer
+ if((itr+1) != procChips.end())
+ {
+ TRACFCOMP( g_fapiImpTd, INFO_MRK"stopAllOCCs: n+1 target nodeID=%d", ((*(itr+1))->getAttr<ATTR_FABRIC_GROUP_ID>()));
+
+ if((targ0->getAttr<ATTR_FABRIC_GROUP_ID>()) ==
+ ((*(itr+1))->getAttr<ATTR_FABRIC_GROUP_ID>()))
+ {
+ //need to flip the numbers because we were reversed
+ targ1 = targ0;
+ itr++;
+ targ0 = *itr;
+ }
+ }
+
+ TargetHandleList pOccs;
+ getChildChiplets(pOccs, targ0, TYPE_OCC);
+ if (pOccs.size() > 0)
+ {
+ if( pOccs[0]->getAttr<ATTR_OCC_MASTER_CAPABLE>() )
+ {
+ masterProc0 = targ0;
+ masterProc1 = targ1;
+ continue;
+ }
+ }
+
+ l_errl = HBOCC::stopOCC( targ0, targ1 );
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"stopAllOCCs: stop failed");
+ errlCommit (l_errl, HWPF_COMP_ID);
+ // just commit and try the next module
+ }
+ }
+ if (l_errl)
+ {
+ break;
+ }
+ }
+
+ //now do the master OCC
+ if( masterProc0 )
+ {
+ l_errl = HBOCC::stopOCC( masterProc0, masterProc1 );
+ if (l_errl)
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"stopAllOCCs: stop failed on master");
+ break;
+ }
+ }
+ } while(0);
+
+ //make sure we always unload the module if we loaded it
+ if (winkle_loaded)
+ {
+#ifndef __HOSTBOOT_RUNTIME
+ errlHndl_t l_tmpErrl =
+ VFS::module_unload( "libbuild_winkle_images.so" );
+ if ( l_tmpErrl )
+ {
+ TRACFCOMP( g_fapiTd,ERR_MRK"stopAllOCCs: Error unloading build_winkle module" );
+ if(l_errl)
+ {
+ errlCommit( l_tmpErrl, HWPF_COMP_ID );
+ }
+ else
+ {
+ l_errl = l_tmpErrl;
+ }
+ }
+#endif
+ }
+
+ TRACFCOMP( g_fapiTd,EXIT_MRK"stopAllOCCs" );
+ return l_errl;
+ }
+
+} //end OCC namespace
+
diff --git a/src/usr/occ/p8_pmc_force_vsafe.C b/src/usr/occ/p8_pmc_force_vsafe.C
new file mode 100644
index 000000000..3bd59b986
--- /dev/null
+++ b/src/usr/occ/p8_pmc_force_vsafe.C
@@ -0,0 +1,517 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/occ/p8_pmc_force_vsafe.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2016 */
+/* [+] 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 */
+// $Id: p8_pmc_force_vsafe.C,v 1.18 2014/04/24 16:54:18 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/p8_pmc_force_vsafe.C,v $
+//------------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2011
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+//------------------------------------------------------------------------------
+// *! OWNER NAME: Joe Procwriter Email: asmartpersion@xx.ibm.com
+// *!
+// *! General Description: Forces the PMC to VSAFE mode
+// *!
+// *! The purpose of this procedure is to ......
+// *!
+// *! High-level procedure flow:
+// *! o Do thing 1
+// *! o Do thing 2
+// *! o Do thing 3
+// *! o Check if all went well
+// *! o If so celebrate
+// *! o Else write logs, set bad return code
+// *!
+// *! Procedure Prereq:
+// *! o System clocks are running
+// *!
+// buildfapiprcd -e ../../xml/error_info/p8_force_vsafe_errors.xml,../../xml/error_info/p8_pstate_registers.xml p8_pmc_force_vsafe.C
+
+// -----------------------------------------------------------------------------
+// Write a voltage value into
+// PVSAFE - PMC_PARAMETER_REG1
+// Actually, this value will be been written outside this procedure by the OCC pstate installation routine after the p8_build_pstate runs to build
+// the Pstate superstructure. We had identified a HWP ATTR (ATTR_PM_PVSAFE_PSTATE) to be used by p8_pmc_init to set this up originally but we're
+// going away from that approach so that we have all things about Pstates being done in one place (the OCC pstate installation routine).
+// So, this step should not exist in the p8_pmc_force_vsafe procedure; rather, you should write a value into the hardware with a script that
+// represents what the OCC pstate install routine would have done
+
+// ------------------
+// | Procedure Starts |
+// ------------------
+// |
+// |
+// V
+// Write into PMC_OCC_HEARTBEAT_REG
+// PMC_OCC_HEARTBEAT_TIME - Write the field to 0 to cause an immediate heartbeat loss.
+// PMC_OCC_HEARTBEAT_EN - this bit needs to be 1 to acually cause the 0 time value to trigger the heartbeat loss.
+// |
+// |
+// V
+// POLL PMC_STATUS_REG (8)
+// VOLT_CHG_ONGOING (bit 8) Yes... this bit needs to be 0 to indicate that the voltage controller is at its target.
+
+// 1.3V Turbo to 0.8V (most of the supported range) in 25mV steps (the eVRM step size with iVRMs enabled) is 20 steps which, at 12.5mV/5us rate
+// (a modest time), yields 8us. Given this an error case, we need a conservative time. So let's set the timeout at 100us for the lab.
+// To test the timeout, clear PMC.PMC_MODE_REG (3) (with a script) so that the PMC won't respond.
+
+
+
+
+// Check that the other bits in PMC_STATUS_REG do not indicate errors (eg they should be all zeros). If any are 1
+// | ^
+// | |
+// V |
+// timeout ------
+
+// ----------------------------------------------------------------------
+// Flowchart Ends
+// ----------------------------------------------------------------------
+
+// ----------------------------------------------------------------------
+// Includes
+// ----------------------------------------------------------------------
+#include <fapi.H>
+#include "p8_scom_addresses.H"
+
+extern "C" {
+
+using namespace fapi;
+
+// ----------------------------------------------------------------------
+// Constant definitions
+// ----------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------
+// Global variables
+// ----------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------
+// Function prototypes
+// ----------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------
+// Function definitions
+// ----------------------------------------------------------------------
+
+
+// function: xxx
+/// \param[in] i_target Chip target
+// returns: ECMD_SUCCESS if something good happens,
+// BAD_RETURN_CODE otherwise
+fapi::ReturnCode
+p8_pmc_force_vsafe( const fapi::Target& i_target,
+ const fapi::Target& i_dcm_target)
+{
+ fapi::ReturnCode rc;
+ ecmdDataBufferBase data(64);
+ ecmdDataBufferBase pmcstatusreg(64);
+ uint32_t e_rc = 0;
+
+ // maximum number of status poll attempts to make before giving up
+ const uint32_t MAX_POLL_ATTEMPTS = 0x200;
+
+ uint32_t count = 0;
+ uint16_t pvsafe = 0;
+ bool l_set;
+ uint16_t pstate_target = 0;
+ uint16_t pstate_step_target = 0;
+ uint16_t pstate_actual = 0;
+ uint8_t DONE_FLAG = 0;
+ uint8_t pmc_error = 0;
+ uint8_t intchp_error = 0;
+ uint8_t any_error = 0;
+ uint8_t any_ongoing = 0;
+ uint8_t dummy = 0;
+
+ FAPI_INF("p8_pmc_force_vsafe start to primary target %s",
+ i_target.toEcmdString());
+
+ do
+ {
+ // ******************************************************************
+ // - PMC_MODE_REG checking
+ // ******************************************************************
+ rc = fapiGetScom(i_target, PMC_MODE_REG_0x00062000, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_MODE_REG_0x00062000) failed.");
+ break;
+ }
+
+
+ if ( (data.isBitClear(0) && data.isBitClear(1) ))
+ {
+ FAPI_INF("PMC is not in HARDWARE or FIRMWARE AUCTION MODE so hardware mechanism cannot be used.");
+ break;
+ }
+
+ if ( ( data.isBitClear(3) ))
+ {
+ FAPI_ERR("PMC is disabled for Voltage changes");
+ const fapi::Target & CHIP = i_target;
+ const uint64_t & PMCMODE = data.getDoubleWord(0);
+ FAPI_SET_HWP_ERROR(rc, RC_PROCPM_VOLTAGE_CHANGE_MODE_ERR);
+ break;
+ }
+
+ if ( ( !data.isBitClear(5) ))
+ {
+ FAPI_ERR("PMC is disabled PMC_MASTER_SEQUENCER");
+ const fapi::Target & CHIP = i_target;
+ const uint64_t & PMCMODE = data.getDoubleWord(0);
+ FAPI_SET_HWP_ERROR(rc, RC_PROCPM_MST_SEQUENCER_STATE_ERR);
+ break;
+ }
+
+ // ****************************************************************************
+ // - PMC_STATE_MONITOR_AND_CTRL_REG PMC_PARAMETER_REG1 before the psafe
+ // ****************************************************************************
+
+ rc = fapiGetScom(i_target, PMC_PARAMETER_REG1_0x00062006, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_PARAMETER_REG1_0x00062006) failed.");
+ break;
+ }
+
+ e_rc |= data.extractToRight( &pvsafe,22,8);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+
+ rc = fapiGetScom(i_target, PMC_PSTATE_MONITOR_AND_CTRL_REG_0x00062002, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_PSTATE_MONITOR_AND_CTRL_REG_0x00062002) failed.");
+ break;
+ }
+
+ e_rc |= data.extractToRight( &pstate_target,0,8);
+ e_rc |= data.extractToRight( &pstate_step_target,8,8);
+ e_rc |= data.extractToRight( &pstate_actual,16,8);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+
+ FAPI_INF(" voltage values before the hearbeat loss " );
+ FAPI_INF(" pvsafe => %x , ptarget => %x , pstarget => %x ,pactual => %x " , pvsafe , pstate_target ,pstate_step_target , pstate_actual);
+
+ // ******************************************************************
+ // - SEE PMC_STATUS_REG if debug_mode ==1
+ // ******************************************************************
+
+ rc = fapiGetScom(i_target, PMC_STATUS_REG_0x00062009, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_STATUS_REG_0x00062009) failed.");
+ break;
+ }
+ FAPI_DBG(" debug_mode : status_b4_heartbeat_loss => 0x%16llx", data.getDoubleWord(0));
+
+ l_set = data.isBitSet(0);
+ FAPI_DBG(" pstate_processing_is_susp => %x ", l_set ) ;
+ l_set = data.isBitSet(1);
+ FAPI_DBG(" gpsa_bdcst_error => %x ", l_set );
+
+ e_rc = data.extractToRight( &dummy,2,3);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+ FAPI_DBG(" gpsa_bdcst_resp_info => %x ", dummy );
+ l_set = data.isBitSet(5);
+ FAPI_DBG(" gpsa_vchg_error => %x ", l_set );
+ l_set = data.isBitSet(6);
+ FAPI_DBG(" gpsa_timeout_error => %x ", l_set );
+ l_set = data.isBitSet(7);
+ FAPI_DBG(" gpsa_chg_ongoing => %x ", l_set );
+ l_set = data.isBitSet(8);
+ FAPI_DBG(" volt_chg_ongoing => %x ", l_set );
+ l_set = data.isBitSet(9);
+ FAPI_DBG(" brd_cst_ongoing => %x ", l_set );
+ l_set = data.isBitSet(10);
+ FAPI_DBG(" gpsa_table_error => %x ", l_set );
+ l_set = data.isBitSet(11);
+ FAPI_DBG(" pstate_interchip_error => %x ", l_set );
+ l_set = data.isBitSet(12);
+ FAPI_DBG(" istate_processing_is_susp => %x ", l_set );
+
+
+ // ******************************************************************
+ // - PMC_OCC_HEARTBEAT_REG
+ // ******************************************************************
+
+ FAPI_INF("Forcing PMC Heartbeat loss ");
+
+ e_rc |= data.flushTo0();
+ e_rc |= data.setBit(16);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+
+ rc = fapiPutScom(i_target, PMC_OCC_HEARTBEAT_REG_0x00062066, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiPutScom(PMC_OCC_HEARTBEAT_REG_0x00062066) failed.");
+ break;
+ }
+
+ // delay to reduce number of polling loops
+ rc = fapiDelay(1000, 1000);
+
+ // ******************************************************************
+ // POLL for PMC_STATUS_REG --> BIT_8 to go to 0 or any errors
+ // ******************************************************************
+ FAPI_DBG("Start polling for ongoing to go low ... ");
+ // Loop only if count is less thean poll attempts and DONE_FLAG = 0 and no error
+ for(count=0; ((count<=MAX_POLL_ATTEMPTS) && (DONE_FLAG == 0) && (any_error == 0)); count++)
+ {
+ rc = fapiGetScom(i_target, PMC_STATUS_REG_0x00062009, pmcstatusreg );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_STATUS_REG_0x00062009) failed.");
+ break;
+ }
+
+ FAPI_DBG(" PMC Status poll => 0x%16llx", pmcstatusreg.getDoubleWord(0));
+
+ pmc_error = ( pmcstatusreg.isBitSet(1) || // GPSA_BDCST_ERROR
+ pmcstatusreg.isBitSet(5) || // GPSA_VCHG_ERROR
+ pmcstatusreg.isBitSet(6) || // GPSA_TIMEOUT_ERROR
+ pmcstatusreg.isBitSet(10) || // GPS_TABLE_ERROR
+ pmcstatusreg.isBitSet(12) ); // ISTATE_PROCESSING_IS_SUSPENDED
+
+ any_ongoing = ( pmcstatusreg.isBitSet(7) || // GPSA_CHG_ONGOING
+ pmcstatusreg.isBitSet(8) || // VOLT_CHG_ONGOING
+ pmcstatusreg.isBitSet(9) ); // BRD_CST_ONGOING
+
+
+ // If there is an interchip error, determine if it is expected or not
+ // Unexpected: gpsa_timeout or ECC UE error
+ if (pmcstatusreg.isBitSet(11)) // PSTATE_INTERCHIP_ERROR
+ {
+ rc = fapiGetScom(i_target, PMC_INTCHP_STATUS_REG_0x00062013, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_STATUS_REG_0x00062009) failed.");
+ break;
+ }
+
+ intchp_error = (data.isBitSet(18) || // GPSA_TIMEOUT_ERROR
+ data.isBitSet(19) ); // ECC UE ERROR
+ }
+
+ any_error = (pmc_error || intchp_error);
+
+ // log status if voltage change has any error
+ // Due to SW258130
+ // This block only dumps any detected hw error status
+ // without taking out an error log and stop the reset flow.
+ // Since this procedure is only used by p8_pm_prep_for_reset
+ // we will and should be able to recover from such hardware errors
+ // by going through occ reset flow, thus no FAPI error logged.
+ // Also since if hardware error occurs, there is no need to check
+ // for pstate ongoing or pstate equals to pvsafe due to possible
+ // hardware stuck; therefore, this if/else logic remains.
+ if (any_error)
+ {
+ // dump individual error status
+ FAPI_INF(" PMC_STATUS_REG upon Error");
+ if (pmcstatusreg.isBitSet(0))
+ FAPI_INF(" pstate_processing_is_susp active");
+ if (pmcstatusreg.isBitSet(1))
+ FAPI_INF(" gpsa_bdcst_error active");
+
+ e_rc = pmcstatusreg.extractToRight( &dummy,2,3);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+ if (dummy)
+ FAPI_INF(" gpsa_bdcst_resp_info is non-zero => %x ", dummy );
+
+ if (pmcstatusreg.isBitSet(5))
+ FAPI_INF(" gpsa_vchg_error active");
+ if (pmcstatusreg.isBitSet(6))
+ FAPI_INF(" gpsa_timeout_error active");
+ if (pmcstatusreg.isBitSet(7))
+ FAPI_INF(" gpsa_chg_ongoing active");
+ if (pmcstatusreg.isBitSet(8))
+ FAPI_INF(" volt_chg_ongoing active");
+ if (pmcstatusreg.isBitSet(9))
+ FAPI_INF(" brd_cst_ongoing active");
+ if (pmcstatusreg.isBitSet(10))
+ FAPI_INF(" gpsa_table_error active");
+ if (pmcstatusreg.isBitSet(11))
+ FAPI_INF(" pstate_interchip_error active");
+ if (pmcstatusreg.isBitSet(12))
+ FAPI_INF(" istate_processing_is_susp active");
+
+ FAPI_INF("Status dumpped with PMC on-going deassertion during safe voltage movement, now continue on reset");
+ } // end of status log if
+ else if (any_ongoing == 0)
+ {
+ // Voltage change done (not on-going) and not errors
+ FAPI_INF("PMC completed performing safe mode transition");
+ l_set = pmcstatusreg.isBitSet(0);
+ if (l_set) FAPI_INF(" pstate_processing_is_susp => %x ", l_set ) ;
+
+ l_set = pmcstatusreg.isBitSet(1);
+ if (l_set) FAPI_INF(" gpsa_bdcst_error => %x ", l_set );
+
+ e_rc = pmcstatusreg.extractToRight( &dummy,2,3);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+ if (l_set) FAPI_INF(" gpsa_bdcst_resp_info => %x ", dummy );
+
+ l_set = pmcstatusreg.isBitSet(5);
+ if (l_set) FAPI_INF(" gpsa_vchg_error => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(6);
+ if (l_set) FAPI_INF(" gpsa_timeout_error => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(7);
+ if (l_set) FAPI_INF(" gpsa_chg_ongoing => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(8);
+ if (l_set) FAPI_INF(" volt_chg_ongoing => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(9);
+ if (l_set) FAPI_INF(" brd_cst_ongoing => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(10);
+ if (l_set) FAPI_INF(" gpsa_table_error => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(11);
+ if (l_set) FAPI_INF(" pstate_interchip_error => %x ", l_set );
+
+ l_set = pmcstatusreg.isBitSet(12);
+ if (l_set) FAPI_INF(" istate_processing_is_susp => %x ", l_set );
+
+
+ rc = fapiGetScom(i_target, PMC_PARAMETER_REG1_0x00062006, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_PARAMETER_REG1_0x00062006) failed.");
+ break;
+ }
+
+ e_rc = data.extractToRight( &pvsafe,22,8);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+
+ rc = fapiGetScom(i_target, PMC_PSTATE_MONITOR_AND_CTRL_REG_0x00062002, data );
+ if (rc)
+ {
+ FAPI_ERR("fapiGetScom(PMC_PSTATE_MONITOR_AND_CTRL_REG_0x00062002) failed.");
+ break;
+ }
+
+ e_rc |= data.extractToRight( &pstate_target,0,8);
+ e_rc |= data.extractToRight( &pstate_step_target,8,8);
+ e_rc |= data.extractToRight( &pstate_actual,16,8);
+ if (e_rc)
+ {
+ rc.setEcmdError(e_rc);
+ break;
+ }
+ FAPI_INF(" pvsafe => %x , ptarget => %x , pstarget => %x ,pactual => %x " , pvsafe , pstate_target ,pstate_step_target , pstate_actual);
+
+ // Check that PVSAFE Pstate (in PMC Parameter Reg1) is the value
+ // in the voltage stepper in the following fields of
+ // PMC_STATE_MONITOR_AND_CRTL_REG
+ // 0:7 - Global Pstate Target
+ // 8:15 - Global Pstate Step Target
+ // 16:23 - Global Pstate Actual
+ // if the above do not match, post an error
+ if (pstate_target != pvsafe || pstate_step_target != pvsafe || pstate_actual != pvsafe )
+ {
+ FAPI_ERR("Pstate monitor and control register targets did not match");
+ const fapi::Target & THISCHIP = i_target;
+ const fapi::Target & DCMCHIP = i_dcm_target;
+ const uint64_t & PSTATETARGET = (uint64_t)pstate_target;
+ const uint64_t & PSTATESTEPTARGET = (uint64_t)pstate_step_target;
+ const uint64_t & PSTATEACTUAL = (uint64_t)pstate_actual;
+ FAPI_SET_HWP_ERROR(rc, RC_PROCPM_PSTATE_MONITOR_ERR);
+ break;
+ }
+ DONE_FLAG = 1;
+ }
+ else // voltage change is ongoing so wait and then poll again
+ {
+
+ // wait for 1 millisecond in hardware
+ rc = fapiDelay(1000*1000, 20000000);
+ if (rc)
+ {
+ FAPI_ERR("fapi delay ends up with error");
+ break;
+ }
+ }
+ } // For loop
+ // Inner loop error check
+ if (!rc.ok())
+ {
+ break;
+ }
+
+ // Check if the above loop timed out
+ if (count>=MAX_POLL_ATTEMPTS)
+ {
+ FAPI_ERR("Timed out wait for voltage change on-going to drop");
+ const uint64_t & PSTATETARGET = (uint64_t)pstate_target;
+ const uint64_t & PSTATESTEPTARGET = (uint64_t)pstate_step_target;
+ const uint64_t & PSTATEACTUAL = (uint64_t)pstate_actual;
+ const fapi::Target & THISCHIP = i_target;
+ const fapi::Target & DCMCHIP = i_dcm_target;
+ FAPI_SET_HWP_ERROR(rc, RC_PROCPM_VLT_TIMEOUT);
+ break;
+ }
+
+ } while(0);
+
+ FAPI_INF("p8_pmc_force_vsafe end ....");
+
+ return rc ;
+} // Procedure
+
+} //end extern C
diff --git a/src/usr/occ/p8_pmc_force_vsafe.H b/src/usr/occ/p8_pmc_force_vsafe.H
new file mode 100755
index 000000000..eeec2b840
--- /dev/null
+++ b/src/usr/occ/p8_pmc_force_vsafe.H
@@ -0,0 +1,81 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/occ/p8_pmc_force_vsafe.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2016 */
+/* [+] 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 */
+// $Id: p8_pmc_force_vsafe.H,v 1.3 2014/03/05 21:10:02 stillgs Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/p8_pmc_force_vsafe.H,v $
+//------------------------------------------------------------------------------
+// *|
+// *! (C) Copyright International Business Machines Corp. 2011
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+// *|
+// *! TITLE : p8_pmc_force_vsafe.H
+// *! DESCRIPTION : Force Safe voltage to the chip via PMC
+// *!
+// *! OWNER NAME : Greg Still Email: stillgs@us.ibm.com
+// *! BACKUP NAME : Pradeep CN Email: padeepcn@in.ibm.com
+// *!
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Includes
+//------------------------------------------------------------------------------
+
+
+// function pointer typedef definition for HWP call support
+typedef fapi::ReturnCode (*p8_pmc_force_vsafe_FP_t) (const fapi::Target&,
+ const fapi::Target& );
+
+extern "C" {
+
+
+//------------------------------------------------------------------------------
+// Constant definitions
+//------------------------------------------------------------------------------
+
+
+
+//------------------------------------------------------------------------------
+// Parameter structure definitions
+//------------------------------------------------------------------------------
+
+
+
+//------------------------------------------------------------------------------
+// Function prototype
+//------------------------------------------------------------------------------
+/// \param[in] i_target Chip target
+/// \param[in] i_dcm_target Chip target of the other DCM chip (for FFDC)
+
+/// \retval ECMD_SUCCESS if something good happens,
+/// \retval BAD_RETURN_CODE otherwise
+fapi::ReturnCode
+p8_pmc_force_vsafe( const fapi::Target& i_target,
+ const fapi::Target& i_dcm_target );
+
+
+} // extern "C"
+
+
diff --git a/src/usr/occ/runtime/makefile b/src/usr/occ/runtime/makefile
new file mode 100644
index 000000000..008798945
--- /dev/null
+++ b/src/usr/occ/runtime/makefile
@@ -0,0 +1,39 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/occ/runtime/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2016
+# [+] 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
+
+HOSTBOOT_RUNTIME = 1
+
+ROOTPATH = ../../../../../..
+VPATH += ../
+
+MODULE = occ_rt
+
+## Objects unique to HBRT
+OBJS += rt_occ.o
+
+## Objects common to HBRT and HB IPL
+include ../occ.mk
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/occ/runtime/rt_occ.C b/src/usr/occ/runtime/rt_occ.C
new file mode 100644
index 000000000..a5a2126b0
--- /dev/null
+++ b/src/usr/occ/runtime/rt_occ.C
@@ -0,0 +1,486 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/occ/runtime/rt_occ.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014,2016 */
+/* [+] 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 <runtime/interface.h>
+#include <kernel/console.H>
+
+#include <hwpf/hwp/occ/occ_common.H>
+
+#include <vmmconst.h>
+#include <sys/misc.h>
+#include <errno.h>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <util/utillidmgr.H>
+#include <htmgt/htmgt.H>
+
+// targeting support
+#include <targeting/common/commontargeting.H>
+#include <targeting/common/utilFilter.H>
+#include <targeting/common/targetservice.H>
+#include <targeting/common/utilFilter.H>
+#include <targeting/common/util.H>
+#include <runtime/rt_targeting.H>
+
+// fapi support
+#include <fapi.H>
+#include <fapiPlatHwpInvoker.H>
+#include <hwpf/plat/fapiPlatTrace.H>
+#include <isteps/hwpf_reasoncodes.H>
+
+// Procedures
+#include <p8_occ_control.H>
+#include <p8_pba_bar_config.H>
+#include <p8_pm_init.H>
+#include <p8_pm_prep_for_reset.H>
+
+using namespace TARGETING;
+// Trace
+
+extern trace_desc_t* g_fapiTd; // defined in rt_fapiPlatUtil.C
+
+namespace RT_OCC
+{
+ typedef std::vector<TARGETING::Target *> target_list_t;
+
+ //------------------------------------------------------------------------
+
+ void process_occ_error (uint64_t i_chipId)
+ {
+#ifdef CONFIG_HTMGT
+ TARGETING::Target* l_reportingOccTarget = NULL;
+ errlHndl_t err = RT_TARG::getHbTarget(i_chipId,l_reportingOccTarget);
+ if (err)
+ {
+ TRACFCOMP (g_fapiTd, ERR_MRK"process_occ_error: getHbTarget"
+ " failed at %d chipId", i_chipId);
+ errlCommit (err, HWPF_COMP_ID);
+ }
+ else
+ {
+ HTMGT::processOccError(l_reportingOccTarget);
+ }
+#else
+ TRACFCOMP(g_fapiTd, ERR_MRK"Unexpected call to process_occ_error(%d)"
+ " when HTMGT is not enabled", i_chipId);
+#endif
+ }
+
+ //------------------------------------------------------------------------
+
+ void process_occ_reset (uint64_t i_chipId)
+ {
+#ifdef CONFIG_HTMGT
+ TARGETING::Target* l_failedOccTarget = NULL;
+ errlHndl_t err = RT_TARG::getHbTarget(i_chipId,l_failedOccTarget);
+ if (err)
+ {
+ TRACFCOMP (g_fapiTd, ERR_MRK"process_occ_reset: getHbTarget"
+ " failed at %d chipId", i_chipId);
+ errlCommit (err, HWPF_COMP_ID);
+ }
+ else
+ {
+ HTMGT::processOccReset(l_failedOccTarget);
+ }
+#else
+ TRACFCOMP(g_fapiTd, ERR_MRK"Unexpected call to process_occ_reset(%d)"
+ " when HTMGT is not enabled", i_chipId);
+#endif
+ }
+
+ //------------------------------------------------------------------------
+
+ int enable_occ_actuation (int i_occ_activation)
+ {
+ int rc = 0;
+#ifdef CONFIG_HTMGT
+ errlHndl_t err = HTMGT::enableOccActuation(0 != i_occ_activation);
+ if (err)
+ {
+ rc = err->reasonCode();
+ if (0 == rc)
+ {
+ // If there was a failure, be sure to return non-zero status
+ rc = -1;
+ }
+ TRACFCOMP (g_fapiTd,ERR_MRK"enable_occ_actuation: OCC state change"
+ " failed with rc=0x%04X (actuate=%d)",
+ err->reasonCode(), i_occ_activation);
+ errlCommit (err, HWPF_COMP_ID);
+ }
+#else
+ rc = -1;
+ TRACFCOMP(g_fapiTd,ERR_MRK"Unexpected call to enable_occ_actuation(%d)"
+ " when HTMGT is not enabled", i_occ_activation);
+#endif
+ return rc;
+ }
+
+ //------------------------------------------------------------------------
+
+ int htmgt_pass_thru (uint16_t i_cmdLength,
+ uint8_t * i_cmdData,
+ uint16_t * o_rspLength,
+ uint8_t * o_rspData)
+ {
+ int rc = 0;
+#ifdef CONFIG_HTMGT
+ errlHndl_t err = HTMGT::passThruCommand(i_cmdLength, i_cmdData,
+ *o_rspLength, o_rspData);
+ if (err)
+ {
+ rc = err->reasonCode();
+ if (0 == rc)
+ {
+ // If there was a failure, be sure to return non-zero status
+ rc = -1;
+ }
+ if ((i_cmdLength > 0) && (NULL != i_cmdData))
+ {
+ TRACFCOMP (g_fapiTd,ERR_MRK"htmgt_pass_thru: command 0x%02X"
+ " (%d bytes) failed with rc=0x%04X",
+ i_cmdData[0], i_cmdLength, err->reasonCode());
+ }
+ errlCommit (err, HWPF_COMP_ID);
+ }
+#else
+ o_rspLength = 0;
+#endif
+ return rc;
+ }
+
+ //------------------------------------------------------------------------
+
+ int executeLoadOCC(uint64_t i_homer_addr_phys,
+ uint64_t i_homer_addr_va,
+ uint64_t i_common_addr_phys,
+ uint64_t i_common_addr_va,
+ uint64_t i_proc_chip)
+ {
+ errlHndl_t err = NULL;
+ int rc = 0;
+
+ TRACFCOMP( g_fapiTd,
+ "LoadOCC: homer paddr=%016llx vaddr=%016llx. "
+ " common paddr=%016lx vaddr=%016llx. RtProcChip=%llx",
+ i_homer_addr_phys,
+ i_homer_addr_va,
+ i_common_addr_phys,
+ i_common_addr_va,
+ i_proc_chip);
+
+ do
+ {
+ // Utility to convert i_proc_chip to Target
+ TARGETING::Target* proc_target = NULL;
+ err = RT_TARG::getHbTarget(i_proc_chip, proc_target);
+ if(err)
+ {
+ rc = EINVAL;
+ break;
+ }
+ err = HBOCC::loadOCC(proc_target,
+ i_homer_addr_phys,
+ i_homer_addr_va,
+ i_common_addr_phys);
+ if( err )
+ {
+ break;
+ }
+
+ void* occHostVirt = reinterpret_cast <void *> (i_homer_addr_va +
+ HOMER_OFFSET_TO_OCC_HOST_DATA);
+ err = HBOCC::loadHostDataToHomer(proc_target,occHostVirt);
+ if( err != NULL )
+ {
+ TRACFCOMP( g_fapiImpTd, ERR_MRK"loading Host Data Area failed!" );
+ break;
+ }
+
+ } while(0);
+
+ if ( err )
+ {
+ uint64_t status = err->plid();
+ errlCommit( err, HWPF_COMP_ID );
+
+ if(g_hostInterfaces &&
+ g_hostInterfaces->report_failure)
+ {
+
+ g_hostInterfaces->report_failure(status,
+ i_proc_chip);
+ }
+
+ if(rc == 0)
+ {
+ rc = -1;
+ }
+ }
+ return rc;
+ }
+
+ //------------------------------------------------------------------------
+
+ int executeOnDcms(HBOCC::occAction_t i_action,
+ uint64_t * i_proc_chip,
+ size_t i_num_chips)
+ {
+ errlHndl_t err = NULL;
+ int rc = 0;
+ TARGETING::Target* l_failedTarget = NULL;
+ TRACFCOMP( g_fapiTd,
+ "Action=%d, number of procs = %d ",
+ i_action,
+ i_num_chips);
+
+ for(size_t i = 0; i < i_num_chips; ++i)
+ {
+ TRACFCOMP( g_fapiTd, "\tRtProcChip %llx", i_proc_chip[i]);
+ }
+
+ do
+ {
+ if(i_num_chips < 1 || i_proc_chip == NULL)
+ {
+ rc = EINVAL;
+ break;
+ }
+
+ // Convert chipIds to HB targets
+ target_list_t targets;
+ targets.reserve(i_num_chips);
+
+ for(size_t i = 0; i < i_num_chips; ++i)
+ {
+ TARGETING::Target* proc_target = NULL;
+ err = RT_TARG::getHbTarget(i_proc_chip[i], proc_target);
+ if( err )
+ {
+ rc = EINVAL;
+ break;
+ }
+ targets.push_back(proc_target);
+ }
+ if (err)
+ {
+ break;
+ }
+
+ // If there are no DCMs INSTALLED the do on each proc
+ target_list_t::iterator itarg = targets.begin();
+ if (0 == (*itarg)->getAttr<ATTR_PROC_DCM_INSTALLED>())
+ {
+ for(itarg = targets.begin();
+ itarg != targets.end();
+ ++itarg)
+ {
+ if(i_action == HBOCC::OCC_START)
+ {
+ err = HBOCC::startOCC(*itarg, NULL, l_failedTarget);
+ }
+ else if(i_action == HBOCC::OCC_STOP)
+ {
+ err = HBOCC::stopOCC(*itarg, NULL);
+ }
+
+ if( err )
+ {
+ uint64_t status = err->plid();
+ errlCommit( err, HWPF_COMP_ID );
+
+ if(g_hostInterfaces &&
+ g_hostInterfaces->report_failure)
+ {
+ RT_TARG::rtChipId_t proc_chip = 0;
+ errlHndl_t err2 =
+ RT_TARG::getRtTarget(*itarg, proc_chip);
+
+ if(err2) // should never happen
+ {
+ TRACFCOMP
+ (g_fapiTd, ERR_MRK
+ "Error converting target to RT chipID");
+ errlCommit( err2, HWPF_COMP_ID );
+ }
+
+ g_hostInterfaces->report_failure(status,
+ proc_chip);
+ }
+ err = NULL;
+ rc = -1;
+ // keep going
+ }
+ }
+ break; // done
+ }
+
+ // continue here only if have DCMs
+ // Sort the target list by node then pos
+ std::sort(targets.begin(),
+ targets.end(),
+ orderByNodeAndPosition);
+
+ for(itarg = targets.begin();
+ itarg != targets.end();
+ ++itarg)
+ {
+ TARGETING::Target* t0 = *itarg;
+ TARGETING::Target* t1 = NULL;
+ if((itarg+1) != targets.end())
+ {
+ if((t0->getAttr<ATTR_FABRIC_GROUP_ID>()) ==
+ ((*(itarg+1))->getAttr<ATTR_FABRIC_GROUP_ID>()))
+ {
+ ++itarg;
+ t1 = *itarg;
+ }
+ }
+ if(i_action == HBOCC::OCC_START)
+ {
+ err = HBOCC::startOCC(t0,t1, l_failedTarget);
+ }
+ else if(i_action == HBOCC::OCC_STOP)
+ {
+ err = HBOCC::stopOCC(t0,t1);
+ }
+
+ if( err )
+ {
+ uint64_t status = err->plid();
+ errlCommit( err, HWPF_COMP_ID );
+
+ if(g_hostInterfaces &&
+ g_hostInterfaces->report_failure)
+ {
+ RT_TARG::rtChipId_t proc_chip = 0;
+ errlHndl_t err2 =
+ RT_TARG::getRtTarget(t0, proc_chip);
+
+ if(err2) // should never happen
+ {
+ TRACFCOMP
+ (g_fapiTd, ERR_MRK
+ "Error converting target to RT chipID");
+ errlCommit( err2, HWPF_COMP_ID );
+ }
+
+ g_hostInterfaces->report_failure(status,
+ proc_chip);
+
+ if(t1)
+ {
+ err2 = RT_TARG::getRtTarget(t1, proc_chip);
+ if(err2) // should never happen
+ {
+ TRACFCOMP
+ (g_fapiTd, ERR_MRK
+ "Error converting target to RT chipID");
+ errlCommit( err2, HWPF_COMP_ID );
+ }
+
+ g_hostInterfaces->report_failure(status,
+ proc_chip);
+ }
+ }
+ err = NULL;
+ rc = -1;
+ // keep going
+ }
+ }
+ if( err )
+ {
+ break;
+ }
+
+ } while(0);
+
+
+ if( err )
+ {
+ errlCommit( err, HWPF_COMP_ID );
+ if(rc == 0)
+ {
+ rc = -1;
+ }
+ }
+
+ return rc;
+ }
+
+ int executeStartOCCs(uint64_t* i_proc_chip,
+ size_t i_num_chips)
+ {
+ return executeOnDcms(HBOCC::OCC_START,
+ i_proc_chip,
+ i_num_chips);
+ }
+
+ int executeStopOCCs(uint64_t* i_proc_chip,
+ size_t i_num_chips)
+ {
+ return executeOnDcms(HBOCC::OCC_STOP,
+ i_proc_chip,
+ i_num_chips);
+ }
+
+ //------------------------------------------------------------------------
+
+ struct registerOcc
+ {
+ registerOcc()
+ {
+ runtimeInterfaces_t * rt_intf = getRuntimeInterfaces();
+ rt_intf->get_lid_list = &UtilLidMgr::getLidList;
+ rt_intf->occ_load = &executeLoadOCC;
+ rt_intf->occ_start = &executeStartOCCs;
+ rt_intf->occ_stop = &executeStopOCCs;
+ rt_intf->process_occ_error = &process_occ_error;
+ rt_intf->process_occ_reset = &process_occ_reset;
+ rt_intf->enable_occ_actuation = &enable_occ_actuation;
+ rt_intf->mfg_htmgt_pass_thru = &htmgt_pass_thru;
+
+ // If we already loaded OCC during the IPL we need to fix up
+ // the virtual address because we're now not using virtual
+ // memory
+
+ TargetHandleList procChips;
+ getAllChips(procChips, TYPE_PROC, true);
+ for (TargetHandleList::iterator itr = procChips.begin();
+ itr != procChips.end();
+ ++itr)
+ {
+ uint64_t l_instance = (*itr)->getAttr<ATTR_POSITION>();
+ uint64_t l_homerAddr =
+ g_hostInterfaces->get_reserved_mem("ibm,homer-image",
+ l_instance);
+ (*itr)->setAttr<ATTR_HOMER_VIRT_ADDR>(l_homerAddr);
+ }
+ }
+ };
+
+ registerOcc g_registerOcc;
+}
+
OpenPOWER on IntegriCloud